Adds tests.
This commit is contained in:
469
internal/tools/yq_test.go
Normal file
469
internal/tools/yq_test.go
Normal file
@@ -0,0 +1,469 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewYQ(t *testing.T) {
|
||||
t.Run("creates YQ instance with default path", func(t *testing.T) {
|
||||
yq := NewYQ()
|
||||
if yq == nil {
|
||||
t.Fatal("NewYQ() returned nil")
|
||||
}
|
||||
if yq.yqPath == "" {
|
||||
t.Error("yqPath should not be empty")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestYQGet(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(tmpDir string) (string, string)
|
||||
expression string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "get simple value",
|
||||
setup: func(tmpDir string) (string, string) {
|
||||
yamlContent := `name: test
|
||||
version: "1.0"
|
||||
`
|
||||
filePath := filepath.Join(tmpDir, "test.yaml")
|
||||
if err := os.WriteFile(filePath, []byte(yamlContent), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return filePath, ".name"
|
||||
},
|
||||
want: "test",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "get nested value",
|
||||
setup: func(tmpDir string) (string, string) {
|
||||
yamlContent := `person:
|
||||
name: John
|
||||
age: 30
|
||||
`
|
||||
filePath := filepath.Join(tmpDir, "nested.yaml")
|
||||
if err := os.WriteFile(filePath, []byte(yamlContent), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return filePath, ".person.name"
|
||||
},
|
||||
want: "John",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "non-existent file returns error",
|
||||
setup: func(tmpDir string) (string, string) {
|
||||
return filepath.Join(tmpDir, "nonexistent.yaml"), ".name"
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Skip if yq is not available
|
||||
if _, err := os.Stat("/usr/bin/yq"); os.IsNotExist(err) {
|
||||
t.Skip("yq not installed, skipping test")
|
||||
}
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
filePath, expression := tt.setup(tmpDir)
|
||||
|
||||
yq := NewYQ()
|
||||
got, err := yq.Get(filePath, expression)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && got != tt.want {
|
||||
t.Errorf("Get() = %q, want %q", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestYQSet(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(tmpDir string) string
|
||||
expression string
|
||||
value string
|
||||
verify func(t *testing.T, filePath string)
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "set simple value",
|
||||
setup: func(tmpDir string) string {
|
||||
yamlContent := `name: old`
|
||||
filePath := filepath.Join(tmpDir, "test.yaml")
|
||||
if err := os.WriteFile(filePath, []byte(yamlContent), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return filePath
|
||||
},
|
||||
expression: ".name",
|
||||
value: "new",
|
||||
verify: func(t *testing.T, filePath string) {
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(string(content), "new") {
|
||||
t.Errorf("File does not contain expected value 'new': %s", content)
|
||||
}
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "set value with special characters",
|
||||
setup: func(tmpDir string) string {
|
||||
yamlContent := `message: hello`
|
||||
filePath := filepath.Join(tmpDir, "special.yaml")
|
||||
if err := os.WriteFile(filePath, []byte(yamlContent), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return filePath
|
||||
},
|
||||
expression: ".message",
|
||||
value: `hello "world"`,
|
||||
verify: func(t *testing.T, filePath string) {
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Should contain escaped quotes
|
||||
if !strings.Contains(string(content), "hello") {
|
||||
t.Errorf("File does not contain expected value: %s", content)
|
||||
}
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "expression without leading dot gets dot prepended",
|
||||
setup: func(tmpDir string) string {
|
||||
yamlContent := `key: value`
|
||||
filePath := filepath.Join(tmpDir, "nodot.yaml")
|
||||
if err := os.WriteFile(filePath, []byte(yamlContent), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return filePath
|
||||
},
|
||||
expression: "key",
|
||||
value: "newvalue",
|
||||
verify: func(t *testing.T, filePath string) {
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(string(content), "newvalue") {
|
||||
t.Errorf("File does not contain expected value: %s", content)
|
||||
}
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Skip if yq is not available
|
||||
if _, err := os.Stat("/usr/bin/yq"); os.IsNotExist(err) {
|
||||
t.Skip("yq not installed, skipping test")
|
||||
}
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
filePath := tt.setup(tmpDir)
|
||||
|
||||
yq := NewYQ()
|
||||
err := yq.Set(filePath, tt.expression, tt.value)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && tt.verify != nil {
|
||||
tt.verify(t, filePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestYQDelete(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(tmpDir string) string
|
||||
expression string
|
||||
verify func(t *testing.T, filePath string)
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "delete simple key",
|
||||
setup: func(tmpDir string) string {
|
||||
yamlContent := `name: test
|
||||
version: "1.0"
|
||||
`
|
||||
filePath := filepath.Join(tmpDir, "delete.yaml")
|
||||
if err := os.WriteFile(filePath, []byte(yamlContent), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return filePath
|
||||
},
|
||||
expression: ".name",
|
||||
verify: func(t *testing.T, filePath string) {
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Contains(string(content), "name:") {
|
||||
t.Errorf("Key 'name' was not deleted: %s", content)
|
||||
}
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Skip if yq is not available
|
||||
if _, err := os.Stat("/usr/bin/yq"); os.IsNotExist(err) {
|
||||
t.Skip("yq not installed, skipping test")
|
||||
}
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
filePath := tt.setup(tmpDir)
|
||||
|
||||
yq := NewYQ()
|
||||
err := yq.Delete(filePath, tt.expression)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && tt.verify != nil {
|
||||
tt.verify(t, filePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestYQValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(tmpDir string) string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid YAML",
|
||||
setup: func(tmpDir string) string {
|
||||
yamlContent := `name: test
|
||||
version: "1.0"
|
||||
nested:
|
||||
key: value
|
||||
`
|
||||
filePath := filepath.Join(tmpDir, "valid.yaml")
|
||||
if err := os.WriteFile(filePath, []byte(yamlContent), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return filePath
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid YAML",
|
||||
setup: func(tmpDir string) string {
|
||||
invalidYaml := `name: test
|
||||
invalid indentation
|
||||
version: "1.0"
|
||||
`
|
||||
filePath := filepath.Join(tmpDir, "invalid.yaml")
|
||||
if err := os.WriteFile(filePath, []byte(invalidYaml), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return filePath
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "non-existent file",
|
||||
setup: func(tmpDir string) string {
|
||||
return filepath.Join(tmpDir, "nonexistent.yaml")
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Skip if yq is not available
|
||||
if _, err := os.Stat("/usr/bin/yq"); os.IsNotExist(err) {
|
||||
t.Skip("yq not installed, skipping test")
|
||||
}
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
filePath := tt.setup(tmpDir)
|
||||
|
||||
yq := NewYQ()
|
||||
err := yq.Validate(filePath)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestYQExec(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(tmpDir string) (string, []string)
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "exec with valid args",
|
||||
setup: func(tmpDir string) (string, []string) {
|
||||
yamlContent := `name: test`
|
||||
filePath := filepath.Join(tmpDir, "exec.yaml")
|
||||
if err := os.WriteFile(filePath, []byte(yamlContent), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return filePath, []string{"eval", ".name", filePath}
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Skip if yq is not available
|
||||
if _, err := os.Stat("/usr/bin/yq"); os.IsNotExist(err) {
|
||||
t.Skip("yq not installed, skipping test")
|
||||
}
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
_, args := tt.setup(tmpDir)
|
||||
|
||||
yq := NewYQ()
|
||||
output, err := yq.Exec(args...)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Exec() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && len(output) == 0 {
|
||||
t.Error("Exec() returned empty output")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanYQOutput(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "removes trailing newline",
|
||||
input: "value\n",
|
||||
want: "value",
|
||||
},
|
||||
{
|
||||
name: "converts null to empty string",
|
||||
input: "null",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "removes whitespace",
|
||||
input: " value \n",
|
||||
want: "value",
|
||||
},
|
||||
{
|
||||
name: "handles empty string",
|
||||
input: "",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "handles multiple newlines",
|
||||
input: "value\n\n",
|
||||
want: "value",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := CleanYQOutput(tt.input)
|
||||
if got != tt.want {
|
||||
t.Errorf("CleanYQOutput(%q) = %q, want %q", tt.input, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestYQMerge(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(tmpDir string) (string, string, string)
|
||||
verify func(t *testing.T, outputPath string)
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "merge two files",
|
||||
setup: func(tmpDir string) (string, string, string) {
|
||||
file1 := filepath.Join(tmpDir, "file1.yaml")
|
||||
file2 := filepath.Join(tmpDir, "file2.yaml")
|
||||
output := filepath.Join(tmpDir, "output.yaml")
|
||||
|
||||
if err := os.WriteFile(file1, []byte("key1: value1\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(file2, []byte("key2: value2\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return file1, file2, output
|
||||
},
|
||||
verify: func(t *testing.T, outputPath string) {
|
||||
if _, err := os.Stat(outputPath); os.IsNotExist(err) {
|
||||
t.Error("Output file was not created")
|
||||
}
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Skip if yq is not available
|
||||
if _, err := os.Stat("/usr/bin/yq"); os.IsNotExist(err) {
|
||||
t.Skip("yq not installed, skipping test")
|
||||
}
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
file1, file2, output := tt.setup(tmpDir)
|
||||
|
||||
yq := NewYQ()
|
||||
err := yq.Merge(file1, file2, output)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && tt.verify != nil {
|
||||
tt.verify(t, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user