470 lines
10 KiB
Go
470 lines
10 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|