1package config
2
3import (
4 "context"
5 "errors"
6 "testing"
7
8 "github.com/charmbracelet/crush/pkg/env"
9 "github.com/stretchr/testify/assert"
10)
11
12// mockShell implements the Shell interface for testing
13type mockShell struct {
14 execFunc func(ctx context.Context, command string) (stdout, stderr string, err error)
15}
16
17func (m *mockShell) Exec(ctx context.Context, command string) (stdout, stderr string, err error) {
18 if m.execFunc != nil {
19 return m.execFunc(ctx, command)
20 }
21 return "", "", nil
22}
23
24func TestShellVariableResolver_ResolveValue(t *testing.T) {
25 tests := []struct {
26 name string
27 value string
28 envVars map[string]string
29 shellFunc func(ctx context.Context, command string) (stdout, stderr string, err error)
30 expected string
31 expectError bool
32 }{
33 {
34 name: "non-variable string returns as-is",
35 value: "plain-string",
36 expected: "plain-string",
37 },
38 {
39 name: "environment variable resolution",
40 value: "$HOME",
41 envVars: map[string]string{"HOME": "/home/user"},
42 expected: "/home/user",
43 },
44 {
45 name: "missing environment variable returns error",
46 value: "$MISSING_VAR",
47 envVars: map[string]string{},
48 expectError: true,
49 },
50 {
51 name: "shell command execution",
52 value: "$(echo hello)",
53 shellFunc: func(ctx context.Context, command string) (stdout, stderr string, err error) {
54 if command == "echo hello" {
55 return "hello\n", "", nil
56 }
57 return "", "", errors.New("unexpected command")
58 },
59 expected: "hello",
60 },
61 {
62 name: "shell command with whitespace trimming",
63 value: "$(echo ' spaced ')",
64 shellFunc: func(ctx context.Context, command string) (stdout, stderr string, err error) {
65 if command == "echo ' spaced '" {
66 return " spaced \n", "", nil
67 }
68 return "", "", errors.New("unexpected command")
69 },
70 expected: "spaced",
71 },
72 {
73 name: "shell command execution error",
74 value: "$(false)",
75 shellFunc: func(ctx context.Context, command string) (stdout, stderr string, err error) {
76 return "", "", errors.New("command failed")
77 },
78 expectError: true,
79 },
80 {
81 name: "invalid format returns error",
82 value: "$",
83 expectError: true,
84 },
85 }
86
87 for _, tt := range tests {
88 t.Run(tt.name, func(t *testing.T) {
89 testEnv := env.NewFromMap(tt.envVars)
90 resolver := &shellVariableResolver{
91 shell: &mockShell{execFunc: tt.shellFunc},
92 env: testEnv,
93 }
94
95 result, err := resolver.ResolveValue(tt.value)
96
97 if tt.expectError {
98 assert.Error(t, err)
99 } else {
100 assert.NoError(t, err)
101 assert.Equal(t, tt.expected, result)
102 }
103 })
104 }
105}
106
107func TestEnvironmentVariableResolver_ResolveValue(t *testing.T) {
108 tests := []struct {
109 name string
110 value string
111 envVars map[string]string
112 expected string
113 expectError bool
114 }{
115 {
116 name: "non-variable string returns as-is",
117 value: "plain-string",
118 expected: "plain-string",
119 },
120 {
121 name: "environment variable resolution",
122 value: "$HOME",
123 envVars: map[string]string{"HOME": "/home/user"},
124 expected: "/home/user",
125 },
126 {
127 name: "environment variable with complex value",
128 value: "$PATH",
129 envVars: map[string]string{"PATH": "/usr/bin:/bin:/usr/local/bin"},
130 expected: "/usr/bin:/bin:/usr/local/bin",
131 },
132 {
133 name: "missing environment variable returns error",
134 value: "$MISSING_VAR",
135 envVars: map[string]string{},
136 expectError: true,
137 },
138 {
139 name: "empty environment variable returns error",
140 value: "$EMPTY_VAR",
141 envVars: map[string]string{"EMPTY_VAR": ""},
142 expectError: true,
143 },
144 }
145
146 for _, tt := range tests {
147 t.Run(tt.name, func(t *testing.T) {
148 testEnv := env.NewFromMap(tt.envVars)
149 resolver := NewEnvironmentVariableResolver(testEnv)
150
151 result, err := resolver.ResolveValue(tt.value)
152
153 if tt.expectError {
154 assert.Error(t, err)
155 } else {
156 assert.NoError(t, err)
157 assert.Equal(t, tt.expected, result)
158 }
159 })
160 }
161}
162
163func TestNewShellVariableResolver(t *testing.T) {
164 testEnv := env.NewFromMap(map[string]string{"TEST": "value"})
165 resolver := NewShellVariableResolver(testEnv)
166
167 assert.NotNil(t, resolver)
168 assert.Implements(t, (*VariableResolver)(nil), resolver)
169}
170
171func TestNewEnvironmentVariableResolver(t *testing.T) {
172 testEnv := env.NewFromMap(map[string]string{"TEST": "value"})
173 resolver := NewEnvironmentVariableResolver(testEnv)
174
175 assert.NotNil(t, resolver)
176 assert.Implements(t, (*VariableResolver)(nil), resolver)
177}
178