-
Notifications
You must be signed in to change notification settings - Fork 0
feat(testing): add ShellSpec tests for all shell scripts #421
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,102 @@ | ||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||
| # shellcheck disable=SC2329 | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Describe 'brew-upgrader/upgrade.sh' | ||||||||||||||||||||||||
| SCRIPT="$PWD/home-manager/services/brew-upgrader/upgrade.sh" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Describe 'brew upgrade command' | ||||||||||||||||||||||||
| setup() { | ||||||||||||||||||||||||
| MOCK_BIN=$(mktemp -d) | ||||||||||||||||||||||||
| MOCK_LOG="$MOCK_BIN/mock.log" | ||||||||||||||||||||||||
| : >"$MOCK_LOG" | ||||||||||||||||||||||||
| export MOCK_BIN MOCK_LOG | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Create mock brew in /opt/homebrew/bin | ||||||||||||||||||||||||
| mkdir -p /tmp/mock_homebrew/bin | ||||||||||||||||||||||||
| cat >/tmp/mock_homebrew/bin/brew <<'EOF' | ||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||
| echo "brew $*" | ||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||
| EOF | ||||||||||||||||||||||||
| chmod +x /tmp/mock_homebrew/bin/brew | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Also create at the actual path the script uses | ||||||||||||||||||||||||
| mkdir -p "$MOCK_BIN/opt/homebrew/bin" | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| cleanup() { | ||||||||||||||||||||||||
| rm -rf "$MOCK_BIN" /tmp/mock_homebrew | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Before 'setup' | ||||||||||||||||||||||||
| After 'cleanup' | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| It 'calls brew upgrade' | ||||||||||||||||||||||||
| # Test by checking what the script would do | ||||||||||||||||||||||||
| When run bash -c "cat '$SCRIPT' | grep 'brew upgrade'" | ||||||||||||||||||||||||
| The output should include 'brew upgrade' | ||||||||||||||||||||||||
| End | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| It 'uses /opt/homebrew/bin/brew path' | ||||||||||||||||||||||||
| When run bash -c "cat '$SCRIPT'" | ||||||||||||||||||||||||
| The output should include '/opt/homebrew/bin/brew' | ||||||||||||||||||||||||
| End | ||||||||||||||||||||||||
| End | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Describe 'script properties' | ||||||||||||||||||||||||
| It 'uses strict mode' | ||||||||||||||||||||||||
| When run bash -c "head -5 '$SCRIPT'" | ||||||||||||||||||||||||
| The output should include 'set -euo pipefail' | ||||||||||||||||||||||||
| End | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| It 'uses bash shebang' | ||||||||||||||||||||||||
| When run bash -c "head -1 '$SCRIPT'" | ||||||||||||||||||||||||
| The output should include '#!/usr/bin/env bash' | ||||||||||||||||||||||||
| End | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| It 'is a short script (less than 10 lines)' | ||||||||||||||||||||||||
| When run bash -c "wc -l < '$SCRIPT' | tr -d ' '" | ||||||||||||||||||||||||
| The output should eq '5' | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
| The output should eq '5' | |
| The output should satisfy 'test "$output" -lt 10' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relax or remove the exact line-count assertion.
Line 59 asserts that the script is exactly 5 lines. This is overly brittle: adding a blank line, comment, or minor reformatting breaks the test even if functionality is preserved. Consider one of these alternatives:
- Remove the test entirely: A 5-line script limit is not a functional requirement.
- Use a looser bound:
"wc -l < '$SCRIPT' | awk '{print $1 <= 10}'"allows reasonable growth without excessive brittleness. - Replace with a different metric: Test script complexity (e.g., cyclomatic complexity) rather than line count, which is more maintainable.
Unless there's a specific reason to enforce exactly 5 lines (e.g., compliance, documentation), this assertion should be relaxed or removed.
🤖 Prompt for AI Agents
In spec/brew_upgrader_spec.sh around lines 57 to 60, the test asserts the script
has exactly 5 lines which is brittle; change the spec to relax or remove this
exact line-count check. Either remove the block entirely, or replace it with a
looser bound such as checking the line count is <= 10, or swap to a different
metric (e.g., run a simple complexity or lint check) so the test verifies
reasonable brevity without failing on harmless formatting changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: This test doesn't actually test the script's error handling. It creates a new temporary script that calls the mock brew, rather than running the actual $SCRIPT (upgrade.sh) against the mock. The test passes but doesn't verify the real script's behavior. Consider modifying PATH or using a mechanism to make the actual script use the mock brew.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At spec/brew_upgrader_spec.sh, line 90:
<comment>This test doesn't actually test the script's error handling. It creates a new temporary script that calls the mock brew, rather than running the actual `$SCRIPT` (upgrade.sh) against the mock. The test passes but doesn't verify the real script's behavior. Consider modifying PATH or using a mechanism to make the actual script use the mock brew.</comment>
<file context>
@@ -0,0 +1,102 @@
+cat >"$TEMP_SCRIPT" <<EOF
+#!/usr/bin/env bash
+set -euo pipefail
+$MOCK_BIN/opt/homebrew/bin/brew upgrade
+EOF
+chmod +x "$TEMP_SCRIPT"
</file context>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is intended to check the script's failure mode, but it does so by creating a new temporary script that re-implements the logic of the original script. This means you are not testing the actual upgrade.sh file.
A better approach is to test a modified version of the actual script. You can use sed to replace the hardcoded /opt/homebrew/bin/brew path with your mock path in a temporary copy of the script. This ensures you're testing the real script's structure and content, just adapted for the test environment.
| TEMP_SCRIPT=$(mktemp) | |
| cat >"$TEMP_SCRIPT" <<EOF | |
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| $MOCK_BIN/opt/homebrew/bin/brew upgrade | |
| EOF | |
| chmod +x "$TEMP_SCRIPT" | |
| TEMP_SCRIPT=$(mktemp) | |
| # Create a temporary, testable version of the script by replacing the hardcoded path | |
| sed "s|/opt/homebrew/bin/brew|$MOCK_BIN/opt/homebrew/bin/brew|" "$SCRIPT" > "$TEMP_SCRIPT" | |
| chmod +x "$TEMP_SCRIPT" |
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cleanup logic at line 98 uses rm -f inside the test case, which will execute even if the test fails. This cleanup should be moved to the cleanup() function in the After hook to ensure it always runs.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,103 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # shellcheck disable=SC2329 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Describe 'cliproxyapi/start.sh' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SCRIPT="$PWD/home-manager/services/cliproxyapi/start.sh" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Describe 'configuration handling' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setup() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TEMP_HOME=$(mktemp -d) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/.cli-proxy-api" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/dotfiles" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Create template config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cat >"$TEMP_HOME/.cli-proxy-api/config.template.yaml" <<'YAML' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| api_key: __OPENROUTER_API_KEY__ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| management_password: __CLIPROXY_MANAGEMENT_PASSWORD__ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| YAML | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Create .env file | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cat >"$TEMP_HOME/dotfiles/.env" <<'ENV' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OPENROUTER_API_KEY=test_openrouter_key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CLIPROXY_MANAGEMENT_PASSWORD=test_mgmt_password | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ENV | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cleanup() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rm -rf "$TEMP_HOME" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Before 'setup' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| After 'cleanup' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| It 'sources .env file when present' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Create a script that tests env sourcing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cat >"$TEMP_HOME/test_env.sh" <<'EOF' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ENV_FILE="$HOME/dotfiles/.env" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -f "$ENV_FILE" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| source "$ENV_FILE" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set +a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "OPENROUTER_API_KEY=$OPENROUTER_API_KEY" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EOF | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chmod +x "$TEMP_HOME/test_env.sh" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| When run bash -c "HOME='$TEMP_HOME' bash '$TEMP_HOME/test_env.sh'" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The output should include 'OPENROUTER_API_KEY=test_openrouter_key' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The status should be success | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| It 'generates config from template' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Create a simplified test script | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cat >"$TEMP_HOME/test_config.sh" <<'EOF' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CONFIG_DIR="$HOME/.cli-proxy-api" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TEMPLATE="$CONFIG_DIR/config.template.yaml" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CONFIG="$CONFIG_DIR/config.yaml" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OPENROUTER_API_KEY="test_key" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CLIPROXY_MANAGEMENT_PASSWORD="test_pass" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -f "$TEMPLATE" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sed -e "s|__OPENROUTER_API_KEY__|${OPENROUTER_API_KEY:-}|g" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -e "s|__CLIPROXY_MANAGEMENT_PASSWORD__|${CLIPROXY_MANAGEMENT_PASSWORD:-}|g" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$TEMPLATE" >"$CONFIG" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cat "$CONFIG" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EOF | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chmod +x "$TEMP_HOME/test_config.sh" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| When run bash -c "HOME='$TEMP_HOME' bash '$TEMP_HOME/test_config.sh'" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The output should include 'api_key: test_key' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The output should include 'management_password: test_pass' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+34
to
+76
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Create a script that tests env sourcing | |
| cat >"$TEMP_HOME/test_env.sh" <<'EOF' | |
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| ENV_FILE="$HOME/dotfiles/.env" | |
| if [ -f "$ENV_FILE" ]; then | |
| set -a | |
| source "$ENV_FILE" | |
| set +a | |
| fi | |
| echo "OPENROUTER_API_KEY=$OPENROUTER_API_KEY" | |
| EOF | |
| chmod +x "$TEMP_HOME/test_env.sh" | |
| When run bash -c "HOME='$TEMP_HOME' bash '$TEMP_HOME/test_env.sh'" | |
| The output should include 'OPENROUTER_API_KEY=test_openrouter_key' | |
| The status should be success | |
| End | |
| It 'generates config from template' | |
| # Create a simplified test script | |
| cat >"$TEMP_HOME/test_config.sh" <<'EOF' | |
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| CONFIG_DIR="$HOME/.cli-proxy-api" | |
| TEMPLATE="$CONFIG_DIR/config.template.yaml" | |
| CONFIG="$CONFIG_DIR/config.yaml" | |
| OPENROUTER_API_KEY="test_key" | |
| CLIPROXY_MANAGEMENT_PASSWORD="test_pass" | |
| if [ -f "$TEMPLATE" ]; then | |
| sed -e "s|__OPENROUTER_API_KEY__|${OPENROUTER_API_KEY:-}|g" \ | |
| -e "s|__CLIPROXY_MANAGEMENT_PASSWORD__|${CLIPROXY_MANAGEMENT_PASSWORD:-}|g" \ | |
| "$TEMPLATE" >"$CONFIG" | |
| fi | |
| cat "$CONFIG" | |
| EOF | |
| chmod +x "$TEMP_HOME/test_config.sh" | |
| When run bash -c "HOME='$TEMP_HOME' bash '$TEMP_HOME/test_config.sh'" | |
| The output should include 'api_key: test_key' | |
| The output should include 'management_password: test_pass' | |
| # Run the actual script and check if environment variables are sourced | |
| When run bash -c "HOME='$TEMP_HOME' bash '$SCRIPT' --print-env" | |
| The output should include 'OPENROUTER_API_KEY=test_openrouter_key' | |
| The status should be success | |
| End | |
| It 'generates config from template' | |
| # Set environment variables for the script | |
| export OPENROUTER_API_KEY="test_key" | |
| export CLIPROXY_MANAGEMENT_PASSWORD="test_pass" | |
| # Run the actual script to generate the config | |
| When run bash -c "HOME='$TEMP_HOME' OPENROUTER_API_KEY='$OPENROUTER_API_KEY' CLIPROXY_MANAGEMENT_PASSWORD='$CLIPROXY_MANAGEMENT_PASSWORD' bash '$SCRIPT' --generate-config" | |
| The file "$TEMP_HOME/.cli-proxy-api/config.yaml" should exist | |
| The contents of file "$TEMP_HOME/.cli-proxy-api/config.yaml" should include 'api_key: test_key' | |
| The contents of file "$TEMP_HOME/.cli-proxy-api/config.yaml" should include 'management_password: test_pass' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test re-implements the config generation logic in a separate test script instead of testing the main script's behavior. This is a common pattern in this PR that should be avoided, as it doesn't test the actual script file.
A more robust, behavioral test would execute the main script and verify its side effects. Since the script uses a hardcoded path for cliproxyapi, you can't easily mock it via PATH. However, you can create a temporary mock binary and use sed to point a temporary copy of the script to it. Then, you can run the script and assert that the config.yaml file is created with the correct content. Here is an example of how this test could be rewritten:
It 'generates config from template'
# Mock the cliproxyapi binary that the script tries to exec
MOCK_BIN_DIR=$(mktemp -d)
mkdir -p "$MOCK_BIN_DIR/opt/homebrew/bin"
touch "$MOCK_BIN_DIR/opt/homebrew/bin/cliproxyapi"
chmod +x "$MOCK_BIN_DIR/opt/homebrew/bin/cliproxyapi"
# Create a temporary script that uses our mock binary path
TEMP_SCRIPT=$(mktemp)
sed "s|/opt/homebrew/bin/cliproxyapi|$MOCK_BIN_DIR/opt/homebrew/bin/cliproxyapi|" "$SCRIPT" > "$TEMP_SCRIPT"
chmod +x "$TEMP_SCRIPT"
When run bash -c "HOME='$TEMP_HOME' bash '$TEMP_SCRIPT'"
The status should be success
The file "$TEMP_HOME/.cli-proxy-api/config.yaml" should be file
The contents of file "$TEMP_HOME/.cli-proxy-api/config.yaml" should include "api_key: test_openrouter_key"
The contents of file "$TEMP_HOME/.cli-proxy-api/config.yaml" should include "management_password: test_mgmt_password"
rm -f "$TEMP_SCRIPT"
rm -rf "$MOCK_BIN_DIR"
End
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These tests check for strings in the script source code using grep instead of testing the actual binary detection behavior. Consider testing that the script actually executes the correct binary path or shows the error message when run.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,152 @@ | ||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||
| # shellcheck disable=SC2329 | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Describe 'code-syncer/sync.sh' | ||||||||||||||||||||||||||||
| SCRIPT="$PWD/home-manager/services/code-syncer/sync.sh" | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Describe 'VS Code CLI detection' | ||||||||||||||||||||||||||||
| setup() { | ||||||||||||||||||||||||||||
| TEMP_HOME=$(mktemp -d) | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Code/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Cursor/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Windsurf/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Antigravity/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Code - Insiders/User" | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| cleanup() { | ||||||||||||||||||||||||||||
| rm -rf "$TEMP_HOME" | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Before 'setup' | ||||||||||||||||||||||||||||
| After 'cleanup' | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| It 'exits with error when VS Code CLI not found' | ||||||||||||||||||||||||||||
| When run bash -c "HOME='$TEMP_HOME' bash '$SCRIPT' 2>&1" | ||||||||||||||||||||||||||||
| The output should include 'VS Code CLI not found' | ||||||||||||||||||||||||||||
| The status should be failure | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Describe 'extension filtering' | ||||||||||||||||||||||||||||
| setup() { | ||||||||||||||||||||||||||||
| mock_bin_setup code fswatch | ||||||||||||||||||||||||||||
| TEMP_HOME=$(mktemp -d) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Create required directories | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Code/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Cursor/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Windsurf/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Antigravity/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Code - Insiders/User" | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Create mock VS Code CLI that lists extensions | ||||||||||||||||||||||||||||
| cat >"$MOCK_BIN/code" <<'EOF' | ||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||
| : "${MOCK_LOG:?MOCK_LOG must be set}" | ||||||||||||||||||||||||||||
| if [[ "$1" == "--list-extensions" ]]; then | ||||||||||||||||||||||||||||
| echo "esbenp.prettier-vscode" | ||||||||||||||||||||||||||||
| echo "github.copilot" | ||||||||||||||||||||||||||||
| echo "ms-python.python" | ||||||||||||||||||||||||||||
| echo "bradlc.vscode-tailwindcss" | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| printf '%s\n' "code $*" >>"$MOCK_LOG" | ||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||
| EOF | ||||||||||||||||||||||||||||
| chmod +x "$MOCK_BIN/code" | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| cleanup() { | ||||||||||||||||||||||||||||
| rm -rf "$TEMP_HOME" | ||||||||||||||||||||||||||||
| mock_bin_cleanup | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Before 'setup' | ||||||||||||||||||||||||||||
| After 'cleanup' | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| It 'lists VS Code extensions' | ||||||||||||||||||||||||||||
| When run bash -c "HOME='$TEMP_HOME' bash '$SCRIPT' 2>&1 | head -20" | ||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Piping to Prompt for AI agents |
||||||||||||||||||||||||||||
| The output should include 'extension' | ||||||||||||||||||||||||||||
| The status should be success | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
|
Comment on lines
+67
to
+71
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test is a good start, but it's too generic. It only checks that the word 'extension' appears in the output. Given the setup for this test block, you have a great opportunity to specifically test the extension filtering logic. You can make the assertions much more specific to verify that allowed extensions are present in the sync list and blocklisted extensions are correctly filtered out.
Suggested change
|
||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Describe 'proprietary extension blocklist' | ||||||||||||||||||||||||||||
| It 'defines proprietary extensions to filter' | ||||||||||||||||||||||||||||
| When run bash -c "grep -A 20 'PROPRIETARY_EXTENSIONS=' '$SCRIPT' | head -20" | ||||||||||||||||||||||||||||
| The output should include 'github.copilot' | ||||||||||||||||||||||||||||
| The output should include 'ms-python.python' | ||||||||||||||||||||||||||||
| The output should include 'ms-vscode-remote' | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| It 'defines AI extensions to filter' | ||||||||||||||||||||||||||||
| When run bash -c "grep -A 20 'AI_EXTENSIONS=' '$SCRIPT' | head -20" | ||||||||||||||||||||||||||||
| The output should include 'github.copilot' | ||||||||||||||||||||||||||||
| The output should include 'anthropic.claude-code' | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
|
Comment on lines
+74
to
+87
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Describe 'config file syncing' | ||||||||||||||||||||||||||||
| setup() { | ||||||||||||||||||||||||||||
| mock_bin_setup code fswatch cp | ||||||||||||||||||||||||||||
| TEMP_HOME=$(mktemp -d) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Create VS Code user directory with config files | ||||||||||||||||||||||||||||
| VSCODE_DIR="$TEMP_HOME/Library/Application Support/Code/User" | ||||||||||||||||||||||||||||
| mkdir -p "$VSCODE_DIR" | ||||||||||||||||||||||||||||
| echo '{"editor.fontSize": 14}' >"$VSCODE_DIR/settings.json" | ||||||||||||||||||||||||||||
| echo '[]' >"$VSCODE_DIR/keybindings.json" | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Create target directories | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Cursor/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Windsurf/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Antigravity/User" | ||||||||||||||||||||||||||||
| mkdir -p "$TEMP_HOME/Library/Application Support/Code - Insiders/User" | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Create code mock | ||||||||||||||||||||||||||||
| cat >"$MOCK_BIN/code" <<'EOF' | ||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||
| : "${MOCK_LOG:?MOCK_LOG must be set}" | ||||||||||||||||||||||||||||
| if [[ "$1" == "--list-extensions" ]]; then | ||||||||||||||||||||||||||||
| echo "esbenp.prettier-vscode" | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| printf '%s\n' "code $*" >>"$MOCK_LOG" | ||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||
| EOF | ||||||||||||||||||||||||||||
| chmod +x "$MOCK_BIN/code" | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| cleanup() { | ||||||||||||||||||||||||||||
| rm -rf "$TEMP_HOME" | ||||||||||||||||||||||||||||
| mock_bin_cleanup | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Before 'setup' | ||||||||||||||||||||||||||||
| After 'cleanup' | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| It 'copies settings.json to target editors' | ||||||||||||||||||||||||||||
| When run bash -c "HOME='$TEMP_HOME' bash '$SCRIPT' 2>&1 | head -30" | ||||||||||||||||||||||||||||
| The output should include 'settings.json' | ||||||||||||||||||||||||||||
| The status should be success | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| It 'copies keybindings.json to target editors' | ||||||||||||||||||||||||||||
| When run bash -c "HOME='$TEMP_HOME' bash '$SCRIPT' 2>&1 | head -30" | ||||||||||||||||||||||||||||
| The output should include 'keybindings.json' | ||||||||||||||||||||||||||||
| The status should be success | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Describe 'fswatch integration' | ||||||||||||||||||||||||||||
| It 'checks for fswatch availability' | ||||||||||||||||||||||||||||
| When run bash -c "grep 'fswatch' '$SCRIPT'" | ||||||||||||||||||||||||||||
| The output should include 'fswatch' | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| It 'shows message when fswatch not found' | ||||||||||||||||||||||||||||
| When run bash -c "grep -A 2 'fswatch not found' '$SCRIPT'" | ||||||||||||||||||||||||||||
| The output should include 'Auto-sync disabled' | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
|
Comment on lines
+140
to
+150
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| End | ||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These tests (lines 34-43) use grep to check the script source code instead of testing actual execution behavior. The tests only verify the script contains certain strings, not that it works correctly. The mock setup at lines 8-25 is never actually used in these tests.