opencode-pilot 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugin/index.js +1 -1
- package/test/unit/paths.test.js +0 -15
- package/service/io.opencode.pilot.plist +0 -29
- package/test/run_tests.bash +0 -34
- package/test/test_actions.bash +0 -248
- package/test/test_cli.bash +0 -157
- package/test/test_helper.bash +0 -140
- package/test/test_plist.bash +0 -124
- package/test/test_poll_service.bash +0 -179
- package/test/test_poller.bash +0 -120
- package/test/test_readiness.bash +0 -313
- package/test/test_repo_config.bash +0 -192
- package/test/test_service.bash +0 -295
package/package.json
CHANGED
package/plugin/index.js
CHANGED
package/test/unit/paths.test.js
CHANGED
|
@@ -32,19 +32,4 @@ describe('Path naming consistency', () => {
|
|
|
32
32
|
'server.js should not reference old opencode-ntfy name');
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
|
-
|
|
36
|
-
describe('plist file', () => {
|
|
37
|
-
const plistPath = join(SERVICE_DIR, 'io.opencode.pilot.plist');
|
|
38
|
-
const content = readFileSync(plistPath, 'utf8');
|
|
39
|
-
|
|
40
|
-
test('uses opencode-pilot label', () => {
|
|
41
|
-
assert.match(content, /io\.opencode\.pilot/,
|
|
42
|
-
'plist should use io.opencode.pilot label');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test('does not reference old opencode-ntfy name', () => {
|
|
46
|
-
assert.doesNotMatch(content, /opencode-ntfy/,
|
|
47
|
-
'plist should not reference old opencode-ntfy name');
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
35
|
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
-
<plist version="1.0">
|
|
4
|
-
<dict>
|
|
5
|
-
<key>Label</key>
|
|
6
|
-
<string>io.opencode.pilot</string>
|
|
7
|
-
|
|
8
|
-
<key>ProgramArguments</key>
|
|
9
|
-
<array>
|
|
10
|
-
<string>/usr/local/bin/node</string>
|
|
11
|
-
<string>/usr/local/opt/opencode-pilot/libexec/server.js</string>
|
|
12
|
-
</array>
|
|
13
|
-
|
|
14
|
-
<key>RunAtLoad</key>
|
|
15
|
-
<true/>
|
|
16
|
-
|
|
17
|
-
<key>KeepAlive</key>
|
|
18
|
-
<true/>
|
|
19
|
-
|
|
20
|
-
<key>StandardOutPath</key>
|
|
21
|
-
<string>/usr/local/var/log/opencode-pilot.log</string>
|
|
22
|
-
|
|
23
|
-
<key>StandardErrorPath</key>
|
|
24
|
-
<string>/usr/local/var/log/opencode-pilot.log</string>
|
|
25
|
-
|
|
26
|
-
<key>WorkingDirectory</key>
|
|
27
|
-
<string>/usr/local/opt/opencode-pilot/libexec</string>
|
|
28
|
-
</dict>
|
|
29
|
-
</plist>
|
package/test/run_tests.bash
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# Run all tests for opencode-ntfy
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
-
|
|
10
|
-
echo "========================================"
|
|
11
|
-
echo " opencode-pilot test suite"
|
|
12
|
-
echo "========================================"
|
|
13
|
-
echo ""
|
|
14
|
-
|
|
15
|
-
FAILED=0
|
|
16
|
-
|
|
17
|
-
for test_file in "$SCRIPT_DIR"/test_*.bash; do
|
|
18
|
-
if [[ -f "$test_file" ]] && [[ "$test_file" != *"test_helper.bash"* ]]; then
|
|
19
|
-
echo "----------------------------------------"
|
|
20
|
-
if ! bash "$test_file"; then
|
|
21
|
-
FAILED=1
|
|
22
|
-
fi
|
|
23
|
-
echo ""
|
|
24
|
-
fi
|
|
25
|
-
done
|
|
26
|
-
|
|
27
|
-
echo "========================================"
|
|
28
|
-
if [[ $FAILED -eq 0 ]]; then
|
|
29
|
-
echo " All test suites passed!"
|
|
30
|
-
else
|
|
31
|
-
echo " Some tests failed!"
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
echo "========================================"
|
package/test/test_actions.bash
DELETED
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# Tests for actions.js - Action system for starting sessions
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
-
source "$SCRIPT_DIR/test_helper.bash"
|
|
10
|
-
|
|
11
|
-
SERVICE_DIR="$(dirname "$SCRIPT_DIR")/service"
|
|
12
|
-
|
|
13
|
-
echo "Testing actions.js module..."
|
|
14
|
-
echo ""
|
|
15
|
-
|
|
16
|
-
# =============================================================================
|
|
17
|
-
# File Structure Tests
|
|
18
|
-
# =============================================================================
|
|
19
|
-
|
|
20
|
-
test_actions_file_exists() {
|
|
21
|
-
assert_file_exists "$SERVICE_DIR/actions.js"
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
test_actions_js_syntax() {
|
|
25
|
-
if ! command -v node &>/dev/null; then
|
|
26
|
-
echo "SKIP: node not available"
|
|
27
|
-
return 0
|
|
28
|
-
fi
|
|
29
|
-
node --check "$SERVICE_DIR/actions.js" 2>&1 || {
|
|
30
|
-
echo "actions.js has syntax errors"
|
|
31
|
-
return 1
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
# =============================================================================
|
|
36
|
-
# Export Tests
|
|
37
|
-
# =============================================================================
|
|
38
|
-
|
|
39
|
-
test_actions_exports_execute_action() {
|
|
40
|
-
grep -q "export.*function executeAction\|export.*executeAction" "$SERVICE_DIR/actions.js" || {
|
|
41
|
-
echo "executeAction export not found"
|
|
42
|
-
return 1
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
test_actions_exports_build_command() {
|
|
47
|
-
grep -q "export.*function buildCommand\|export.*buildCommand" "$SERVICE_DIR/actions.js" || {
|
|
48
|
-
echo "buildCommand export not found"
|
|
49
|
-
return 1
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
# =============================================================================
|
|
54
|
-
# Implementation Tests
|
|
55
|
-
# =============================================================================
|
|
56
|
-
|
|
57
|
-
test_actions_uses_opencode_run() {
|
|
58
|
-
grep -q "opencode.*run" "$SERVICE_DIR/actions.js" || {
|
|
59
|
-
echo "opencode run command not found"
|
|
60
|
-
return 1
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
test_actions_prompt_template() {
|
|
65
|
-
grep -q "prompt_template\|promptTemplate\|buildPromptFromTemplate" "$SERVICE_DIR/actions.js" || {
|
|
66
|
-
echo "Prompt template support not found"
|
|
67
|
-
return 1
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
test_actions_calls_opencode() {
|
|
72
|
-
grep -q "opencode" "$SERVICE_DIR/actions.js" || {
|
|
73
|
-
echo "OpenCode invocation not found"
|
|
74
|
-
return 1
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
test_actions_builds_prompt_from_item() {
|
|
79
|
-
grep -q "title\|body" "$SERVICE_DIR/actions.js" || {
|
|
80
|
-
echo "Prompt building from item not found"
|
|
81
|
-
return 1
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
# =============================================================================
|
|
86
|
-
# Functional Tests
|
|
87
|
-
# =============================================================================
|
|
88
|
-
|
|
89
|
-
test_actions_build_local_command() {
|
|
90
|
-
if ! command -v node &>/dev/null; then
|
|
91
|
-
echo "SKIP: node not available"
|
|
92
|
-
return 0
|
|
93
|
-
fi
|
|
94
|
-
|
|
95
|
-
local result
|
|
96
|
-
result=$(node --experimental-vm-modules -e "
|
|
97
|
-
import { buildCommand } from './service/actions.js';
|
|
98
|
-
|
|
99
|
-
const item = {
|
|
100
|
-
title: 'Fix bug #123',
|
|
101
|
-
html_url: 'https://github.com/org/repo/issues/123',
|
|
102
|
-
number: 123
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const config = {
|
|
106
|
-
repo_path: '~/code/myrepo',
|
|
107
|
-
session: { name: 'issue-{number}' }
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
const cmd = buildCommand(item, config);
|
|
111
|
-
|
|
112
|
-
if (!cmd.includes('opencode run')) {
|
|
113
|
-
console.log('FAIL: Local command should include opencode run');
|
|
114
|
-
process.exit(1);
|
|
115
|
-
}
|
|
116
|
-
// Check for cwd pattern (cd ~/code/myrepo && ...)
|
|
117
|
-
if (!cmd.includes('cd') || !cmd.includes('myrepo')) {
|
|
118
|
-
console.log('FAIL: Command should include cd to repo path, got: ' + cmd);
|
|
119
|
-
process.exit(1);
|
|
120
|
-
}
|
|
121
|
-
console.log('PASS');
|
|
122
|
-
" 2>&1) || {
|
|
123
|
-
echo "Functional test failed: $result"
|
|
124
|
-
return 1
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if ! echo "$result" | grep -q "PASS"; then
|
|
128
|
-
echo "$result"
|
|
129
|
-
return 1
|
|
130
|
-
fi
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
test_actions_session_name_template() {
|
|
134
|
-
if ! command -v node &>/dev/null; then
|
|
135
|
-
echo "SKIP: node not available"
|
|
136
|
-
return 0
|
|
137
|
-
fi
|
|
138
|
-
|
|
139
|
-
local result
|
|
140
|
-
result=$(node --experimental-vm-modules -e "
|
|
141
|
-
import { buildSessionName } from './service/actions.js';
|
|
142
|
-
|
|
143
|
-
const item = {
|
|
144
|
-
number: 42,
|
|
145
|
-
repo_key: 'myorg/backend',
|
|
146
|
-
repo_short: 'backend'
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const template = 'issue-{repo_short}-{number}';
|
|
150
|
-
const name = buildSessionName(template, item);
|
|
151
|
-
|
|
152
|
-
if (name !== 'issue-backend-42') {
|
|
153
|
-
console.log('FAIL: Expected issue-backend-42, got ' + name);
|
|
154
|
-
process.exit(1);
|
|
155
|
-
}
|
|
156
|
-
console.log('PASS');
|
|
157
|
-
" 2>&1) || {
|
|
158
|
-
echo "Functional test failed: $result"
|
|
159
|
-
return 1
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if ! echo "$result" | grep -q "PASS"; then
|
|
163
|
-
echo "$result"
|
|
164
|
-
return 1
|
|
165
|
-
fi
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
test_actions_expand_template() {
|
|
169
|
-
if ! command -v node &>/dev/null; then
|
|
170
|
-
echo "SKIP: node not available"
|
|
171
|
-
return 0
|
|
172
|
-
fi
|
|
173
|
-
|
|
174
|
-
local result
|
|
175
|
-
result=$(node --experimental-vm-modules -e "
|
|
176
|
-
import { expandTemplate } from './service/actions.js';
|
|
177
|
-
|
|
178
|
-
const item = {
|
|
179
|
-
title: 'Fix bug',
|
|
180
|
-
number: 456
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
const template = 'Issue #{number}: {title}';
|
|
184
|
-
const expanded = expandTemplate(template, item);
|
|
185
|
-
|
|
186
|
-
if (expanded !== 'Issue #456: Fix bug') {
|
|
187
|
-
console.log('FAIL: Expected \"Issue #456: Fix bug\", got \"' + expanded + '\"');
|
|
188
|
-
process.exit(1);
|
|
189
|
-
}
|
|
190
|
-
console.log('PASS');
|
|
191
|
-
" 2>&1) || {
|
|
192
|
-
echo "Functional test failed: $result"
|
|
193
|
-
return 1
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if ! echo "$result" | grep -q "PASS"; then
|
|
197
|
-
echo "$result"
|
|
198
|
-
return 1
|
|
199
|
-
fi
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
# =============================================================================
|
|
203
|
-
# Run Tests
|
|
204
|
-
# =============================================================================
|
|
205
|
-
|
|
206
|
-
echo "File Structure Tests:"
|
|
207
|
-
|
|
208
|
-
for test_func in \
|
|
209
|
-
test_actions_file_exists \
|
|
210
|
-
test_actions_js_syntax
|
|
211
|
-
do
|
|
212
|
-
run_test "${test_func#test_}" "$test_func"
|
|
213
|
-
done
|
|
214
|
-
|
|
215
|
-
echo ""
|
|
216
|
-
echo "Export Tests:"
|
|
217
|
-
|
|
218
|
-
for test_func in \
|
|
219
|
-
test_actions_exports_execute_action \
|
|
220
|
-
test_actions_exports_build_command
|
|
221
|
-
do
|
|
222
|
-
run_test "${test_func#test_}" "$test_func"
|
|
223
|
-
done
|
|
224
|
-
|
|
225
|
-
echo ""
|
|
226
|
-
echo "Implementation Tests:"
|
|
227
|
-
|
|
228
|
-
for test_func in \
|
|
229
|
-
test_actions_uses_opencode_run \
|
|
230
|
-
test_actions_prompt_template \
|
|
231
|
-
test_actions_calls_opencode \
|
|
232
|
-
test_actions_builds_prompt_from_item
|
|
233
|
-
do
|
|
234
|
-
run_test "${test_func#test_}" "$test_func"
|
|
235
|
-
done
|
|
236
|
-
|
|
237
|
-
echo ""
|
|
238
|
-
echo "Functional Tests:"
|
|
239
|
-
|
|
240
|
-
for test_func in \
|
|
241
|
-
test_actions_build_local_command \
|
|
242
|
-
test_actions_session_name_template \
|
|
243
|
-
test_actions_expand_template
|
|
244
|
-
do
|
|
245
|
-
run_test "${test_func#test_}" "$test_func"
|
|
246
|
-
done
|
|
247
|
-
|
|
248
|
-
print_summary
|
package/test/test_cli.bash
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# Tests for bin/opencode-pilot CLI
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
-
source "$SCRIPT_DIR/test_helper.bash"
|
|
10
|
-
|
|
11
|
-
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
12
|
-
CLI_PATH="$PROJECT_DIR/bin/opencode-pilot"
|
|
13
|
-
|
|
14
|
-
echo "Testing opencode-pilot CLI..."
|
|
15
|
-
echo ""
|
|
16
|
-
|
|
17
|
-
# =============================================================================
|
|
18
|
-
# File Structure Tests
|
|
19
|
-
# =============================================================================
|
|
20
|
-
|
|
21
|
-
test_cli_file_exists() {
|
|
22
|
-
assert_file_exists "$CLI_PATH"
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
test_cli_is_executable() {
|
|
26
|
-
[[ -x "$CLI_PATH" ]] || {
|
|
27
|
-
echo "CLI is not executable"
|
|
28
|
-
return 1
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
test_cli_js_syntax() {
|
|
33
|
-
if ! command -v node &>/dev/null; then
|
|
34
|
-
echo "SKIP: node not available"
|
|
35
|
-
return 0
|
|
36
|
-
fi
|
|
37
|
-
node --check "$CLI_PATH" 2>&1 || {
|
|
38
|
-
echo "CLI has syntax errors"
|
|
39
|
-
return 1
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
# =============================================================================
|
|
44
|
-
# Help Command Tests
|
|
45
|
-
# =============================================================================
|
|
46
|
-
|
|
47
|
-
test_cli_help_shows_usage() {
|
|
48
|
-
"$CLI_PATH" help 2>&1 | grep -q "Usage:" || {
|
|
49
|
-
echo "help command should show Usage"
|
|
50
|
-
return 1
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
test_cli_help_shows_start_command() {
|
|
55
|
-
"$CLI_PATH" help 2>&1 | grep -q "start" || {
|
|
56
|
-
echo "help command should show start command"
|
|
57
|
-
return 1
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
test_cli_help_shows_status_command() {
|
|
62
|
-
"$CLI_PATH" help 2>&1 | grep -q "status" || {
|
|
63
|
-
echo "help command should show status command"
|
|
64
|
-
return 1
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
test_cli_help_shows_config_command() {
|
|
69
|
-
"$CLI_PATH" help 2>&1 | grep -q "config" || {
|
|
70
|
-
echo "help command should show config command"
|
|
71
|
-
return 1
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
test_cli_default_shows_help() {
|
|
76
|
-
"$CLI_PATH" 2>&1 | grep -q "Usage:" || {
|
|
77
|
-
echo "default should show usage"
|
|
78
|
-
return 1
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
test_cli_unknown_command_shows_error() {
|
|
83
|
-
local output
|
|
84
|
-
output=$("$CLI_PATH" unknowncommand 2>&1) || true
|
|
85
|
-
|
|
86
|
-
echo "$output" | grep -q "Unknown command" || {
|
|
87
|
-
echo "unknown command should show error"
|
|
88
|
-
echo "Output: $output"
|
|
89
|
-
return 1
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
# =============================================================================
|
|
94
|
-
# Status Command Tests
|
|
95
|
-
# =============================================================================
|
|
96
|
-
|
|
97
|
-
test_cli_status_shows_service_info() {
|
|
98
|
-
local output
|
|
99
|
-
output=$("$CLI_PATH" status 2>&1) || true
|
|
100
|
-
|
|
101
|
-
echo "$output" | grep -qi "service" || {
|
|
102
|
-
echo "status should show service info"
|
|
103
|
-
echo "Output: $output"
|
|
104
|
-
return 1
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
test_cli_status_shows_config_info() {
|
|
109
|
-
local output
|
|
110
|
-
output=$("$CLI_PATH" status 2>&1) || true
|
|
111
|
-
|
|
112
|
-
echo "$output" | grep -qi "config" || {
|
|
113
|
-
echo "status should show config info"
|
|
114
|
-
echo "Output: $output"
|
|
115
|
-
return 1
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
# =============================================================================
|
|
120
|
-
# Run Tests
|
|
121
|
-
# =============================================================================
|
|
122
|
-
|
|
123
|
-
echo "File Structure Tests:"
|
|
124
|
-
|
|
125
|
-
for test_func in \
|
|
126
|
-
test_cli_file_exists \
|
|
127
|
-
test_cli_is_executable \
|
|
128
|
-
test_cli_js_syntax
|
|
129
|
-
do
|
|
130
|
-
run_test "${test_func#test_}" "$test_func"
|
|
131
|
-
done
|
|
132
|
-
|
|
133
|
-
echo ""
|
|
134
|
-
echo "Help Command Tests:"
|
|
135
|
-
|
|
136
|
-
for test_func in \
|
|
137
|
-
test_cli_help_shows_usage \
|
|
138
|
-
test_cli_help_shows_start_command \
|
|
139
|
-
test_cli_help_shows_status_command \
|
|
140
|
-
test_cli_help_shows_config_command \
|
|
141
|
-
test_cli_default_shows_help \
|
|
142
|
-
test_cli_unknown_command_shows_error
|
|
143
|
-
do
|
|
144
|
-
run_test "${test_func#test_}" "$test_func"
|
|
145
|
-
done
|
|
146
|
-
|
|
147
|
-
echo ""
|
|
148
|
-
echo "Status Command Tests:"
|
|
149
|
-
|
|
150
|
-
for test_func in \
|
|
151
|
-
test_cli_status_shows_service_info \
|
|
152
|
-
test_cli_status_shows_config_info
|
|
153
|
-
do
|
|
154
|
-
run_test "${test_func#test_}" "$test_func"
|
|
155
|
-
done
|
|
156
|
-
|
|
157
|
-
print_summary
|
package/test/test_helper.bash
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# Test helper functions for opencode-ntfy tests
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
# Test counters
|
|
7
|
-
TESTS_RUN=0
|
|
8
|
-
TESTS_PASSED=0
|
|
9
|
-
TESTS_FAILED=0
|
|
10
|
-
|
|
11
|
-
# Colors
|
|
12
|
-
RED='\033[0;31m'
|
|
13
|
-
GREEN='\033[0;32m'
|
|
14
|
-
YELLOW='\033[0;33m'
|
|
15
|
-
NC='\033[0m' # No Color
|
|
16
|
-
|
|
17
|
-
# Setup test environment
|
|
18
|
-
setup_test_env() {
|
|
19
|
-
export TEST_DIR=$(mktemp -d)
|
|
20
|
-
export HOME="$TEST_DIR/home"
|
|
21
|
-
mkdir -p "$HOME"
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
# Cleanup test environment
|
|
25
|
-
cleanup_test_env() {
|
|
26
|
-
if [[ -n "$TEST_DIR" ]] && [[ -d "$TEST_DIR" ]]; then
|
|
27
|
-
rm -rf "$TEST_DIR"
|
|
28
|
-
fi
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
# Assert equality
|
|
32
|
-
assert_equals() {
|
|
33
|
-
local expected="$1"
|
|
34
|
-
local actual="$2"
|
|
35
|
-
local message="${3:-Values should be equal}"
|
|
36
|
-
|
|
37
|
-
if [[ "$expected" == "$actual" ]]; then
|
|
38
|
-
return 0
|
|
39
|
-
else
|
|
40
|
-
echo " Expected: $expected"
|
|
41
|
-
echo " Actual: $actual"
|
|
42
|
-
return 1
|
|
43
|
-
fi
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
# Assert string contains
|
|
47
|
-
assert_contains() {
|
|
48
|
-
local haystack="$1"
|
|
49
|
-
local needle="$2"
|
|
50
|
-
local message="${3:-String should contain substring}"
|
|
51
|
-
|
|
52
|
-
if [[ "$haystack" == *"$needle"* ]]; then
|
|
53
|
-
return 0
|
|
54
|
-
else
|
|
55
|
-
echo " String: $haystack"
|
|
56
|
-
echo " Should contain: $needle"
|
|
57
|
-
return 1
|
|
58
|
-
fi
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
# Assert command succeeds
|
|
62
|
-
assert_success() {
|
|
63
|
-
local cmd="$1"
|
|
64
|
-
local message="${2:-Command should succeed}"
|
|
65
|
-
|
|
66
|
-
if eval "$cmd" >/dev/null 2>&1; then
|
|
67
|
-
return 0
|
|
68
|
-
else
|
|
69
|
-
echo " Command failed: $cmd"
|
|
70
|
-
return 1
|
|
71
|
-
fi
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
# Assert command fails
|
|
75
|
-
assert_failure() {
|
|
76
|
-
local cmd="$1"
|
|
77
|
-
local message="${2:-Command should fail}"
|
|
78
|
-
|
|
79
|
-
if eval "$cmd" >/dev/null 2>&1; then
|
|
80
|
-
echo " Command should have failed: $cmd"
|
|
81
|
-
return 1
|
|
82
|
-
else
|
|
83
|
-
return 0
|
|
84
|
-
fi
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
# Assert file exists
|
|
88
|
-
assert_file_exists() {
|
|
89
|
-
local file="$1"
|
|
90
|
-
local message="${2:-File should exist}"
|
|
91
|
-
|
|
92
|
-
if [[ -f "$file" ]]; then
|
|
93
|
-
return 0
|
|
94
|
-
else
|
|
95
|
-
echo " File does not exist: $file"
|
|
96
|
-
return 1
|
|
97
|
-
fi
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
# Run a single test
|
|
101
|
-
run_test() {
|
|
102
|
-
local test_name="$1"
|
|
103
|
-
local test_func="$2"
|
|
104
|
-
|
|
105
|
-
TESTS_RUN=$((TESTS_RUN + 1))
|
|
106
|
-
|
|
107
|
-
printf " %-50s " "$test_name"
|
|
108
|
-
|
|
109
|
-
# Run test in subshell to isolate failures
|
|
110
|
-
local output
|
|
111
|
-
if output=$($test_func 2>&1); then
|
|
112
|
-
echo -e "${GREEN}PASS${NC}"
|
|
113
|
-
TESTS_PASSED=$((TESTS_PASSED + 1))
|
|
114
|
-
else
|
|
115
|
-
echo -e "${RED}FAIL${NC}"
|
|
116
|
-
if [[ -n "$output" ]]; then
|
|
117
|
-
echo "$output" | sed 's/^/ /'
|
|
118
|
-
fi
|
|
119
|
-
TESTS_FAILED=$((TESTS_FAILED + 1))
|
|
120
|
-
fi
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
# Print test summary
|
|
124
|
-
print_summary() {
|
|
125
|
-
echo ""
|
|
126
|
-
echo "========================================"
|
|
127
|
-
echo "Tests run: $TESTS_RUN"
|
|
128
|
-
echo -e "Tests passed: ${GREEN}$TESTS_PASSED${NC}"
|
|
129
|
-
if [[ $TESTS_FAILED -gt 0 ]]; then
|
|
130
|
-
echo -e "Tests failed: ${RED}$TESTS_FAILED${NC}"
|
|
131
|
-
else
|
|
132
|
-
echo "Tests failed: $TESTS_FAILED"
|
|
133
|
-
fi
|
|
134
|
-
echo "========================================"
|
|
135
|
-
|
|
136
|
-
if [[ $TESTS_FAILED -gt 0 ]]; then
|
|
137
|
-
return 1
|
|
138
|
-
fi
|
|
139
|
-
return 0
|
|
140
|
-
}
|