Files
gosick/test/behavior/behavior_suite.sh
2026-03-20 21:48:30 +00:00

329 lines
9.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
: "${HOMESICK_CMD:=ruby /workspace/bin/homesick}"
: "${BEHAVIOR_VERBOSE:=0}"
RUN_OUTPUT=""
fail() {
echo "FAIL: $*" >&2
exit 1
}
pass() {
if [[ -t 1 ]]; then
printf ' \033[32mPassed\033[0m\n'
else
echo " Passed"
fi
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
-v|--verbose)
BEHAVIOR_VERBOSE=1
;;
*)
fail "unknown argument: $1"
;;
esac
shift
done
}
run_git() {
if [[ "$BEHAVIOR_VERBOSE" == "1" ]]; then
git "$@"
else
git "$@" >/dev/null 2>&1
fi
}
assert_path_exists() {
local path="$1"
[[ -e "$path" ]] || fail "expected path to exist: $path"
}
assert_path_missing() {
local path="$1"
[[ ! -e "$path" ]] || fail "expected path to be missing: $path"
}
assert_symlink_target() {
local link_path="$1"
local expected_target="$2"
[[ -L "$link_path" ]] || fail "expected symlink: $link_path"
local actual_target
actual_target="$(readlink "$link_path")"
[[ "$actual_target" == "$expected_target" ]] || fail "expected symlink target '$expected_target' but got '$actual_target'"
}
run_homesick() {
local out_file
local output
out_file="$(mktemp)"
if ! bash -lc "$HOMESICK_CMD $*" >"$out_file" 2>&1; then
cat "$out_file" >&2
rm -f "$out_file"
fail "homesick command failed: $*"
fi
output="$(cat "$out_file")"
RUN_OUTPUT="$output"
if [[ "$BEHAVIOR_VERBOSE" == "1" && -n "$output" ]]; then
printf '%s\n' "$output"
fi
rm -f "$out_file"
}
run_homesick_with_stdin() {
local stdin_data="$1"
shift
local out_file
local output
out_file="$(mktemp)"
if ! printf '%b' "$stdin_data" | bash -lc "$HOMESICK_CMD $*" >"$out_file" 2>&1; then
cat "$out_file" >&2
rm -f "$out_file"
fail "homesick command failed: $*"
fi
output="$(cat "$out_file")"
RUN_OUTPUT="$output"
if [[ "$BEHAVIOR_VERBOSE" == "1" && -n "$output" ]]; then
printf '%s\n' "$output"
fi
rm -f "$out_file"
}
run_homesick_with_env() {
local env_prefix="$1"
shift
local out_file
local output
out_file="$(mktemp)"
if ! bash -lc "$env_prefix $HOMESICK_CMD $*" >"$out_file" 2>&1; then
cat "$out_file" >&2
rm -f "$out_file"
fail "homesick command failed: $*"
fi
output="$(cat "$out_file")"
RUN_OUTPUT="$output"
if [[ "$BEHAVIOR_VERBOSE" == "1" && -n "$output" ]]; then
printf '%s\n' "$output"
fi
rm -f "$out_file"
}
setup_remote_castle() {
local remote_dir="$1"
local work_dir="$2"
mkdir -p "$remote_dir"
run_git init --bare "$remote_dir/base.git"
mkdir -p "$work_dir/base"
pushd "$work_dir/base" >/dev/null
run_git init
run_git config user.email "behavior@test.local"
run_git config user.name "Behavior Test"
mkdir -p home/.config/myapp
echo "set number" > home/.vimrc
echo "export PATH=\"$PATH:$HOME/bin\"" > home/.zshrc
echo "option=true" > home/.config/myapp/config.toml
printf '.config\n' > .homesick_subdir
run_git add .
run_git commit -m "initial castle"
run_git remote add origin "$remote_dir/base.git"
run_git push -u origin master
popd >/dev/null
}
setup_local_test_file() {
mkdir -p "$HOME/.local/bin"
echo "#!/usr/bin/env bash" > "$HOME/.local/bin/tool"
chmod +x "$HOME/.local/bin/tool"
}
run_suite() {
local tmp_root
tmp_root="$(mktemp -d)"
trap "rm -rf '$tmp_root'" EXIT
export HOME="$tmp_root/home"
mkdir -p "$HOME"
local remote_root="$tmp_root/remote"
local work_root="$tmp_root/work"
setup_remote_castle "$remote_root" "$work_root"
echo "[1/18] help"
run_homesick "help"
[[ "$RUN_OUTPUT" == *"Usage:"* || "$RUN_OUTPUT" == *"Commands:"* ]] || fail "expected help output to include command usage information"
run_homesick "help clone"
[[ "$RUN_OUTPUT" == *"clone"* ]] || fail "expected command help output for clone"
pass
echo "[2/18] clone"
run_homesick "clone file://$remote_root/base.git parity-castle"
run_homesick "clone file://$remote_root/base.git parity-castle-2"
assert_path_exists "$HOME/.homesick/repos/parity-castle/.git"
assert_path_exists "$HOME/.homesick/repos/parity-castle/home/.vimrc"
assert_path_exists "$HOME/.homesick/repos/parity-castle-2/.git"
run_git -C "$HOME/.homesick/repos/parity-castle" config user.email "behavior@test.local"
run_git -C "$HOME/.homesick/repos/parity-castle" config user.name "Behavior Test"
run_git -C "$HOME/.homesick/repos/parity-castle-2" config user.email "behavior@test.local"
run_git -C "$HOME/.homesick/repos/parity-castle-2" config user.name "Behavior Test"
pass
echo "[3/18] link"
run_homesick "link parity-castle"
assert_symlink_target "$HOME/.vimrc" "$HOME/.homesick/repos/parity-castle/home/.vimrc"
assert_symlink_target "$HOME/.zshrc" "$HOME/.homesick/repos/parity-castle/home/.zshrc"
assert_path_exists "$HOME/.config/myapp"
assert_symlink_target "$HOME/.config/myapp" "$HOME/.homesick/repos/parity-castle/home/.config/myapp"
pass
echo "[4/18] unlink"
run_homesick "unlink parity-castle"
assert_path_missing "$HOME/.vimrc"
assert_path_missing "$HOME/.zshrc"
assert_path_exists "$HOME/.config"
assert_path_missing "$HOME/.config/myapp"
pass
echo "[5/18] symlink alias"
run_homesick "symlink parity-castle"
assert_symlink_target "$HOME/.vimrc" "$HOME/.homesick/repos/parity-castle/home/.vimrc"
pass
echo "[6/18] relink + track"
run_homesick "link parity-castle"
setup_local_test_file
run_homesick "track $HOME/.local/bin/tool parity-castle"
assert_symlink_target "$HOME/.local/bin/tool" "$HOME/.homesick/repos/parity-castle/home/.local/bin/tool"
assert_path_exists "$HOME/.homesick/repos/parity-castle/.homesick_subdir"
grep -q "^.local/bin$" "$HOME/.homesick/repos/parity-castle/.homesick_subdir" || fail "expected .homesick_subdir to contain .local/bin"
pass
echo "[7/18] list and show_path"
local list_output
run_homesick "list"
list_output="$RUN_OUTPUT"
[[ "$list_output" == *"parity-castle"* ]] || fail "expected list output to include parity-castle"
local show_path_output
run_homesick "show_path parity-castle"
show_path_output="$RUN_OUTPUT"
[[ "$show_path_output" == "$HOME/.homesick/repos/parity-castle" ]] || fail "expected show_path output to equal parity-castle root path"
pass
echo "[8/18] status and diff"
echo "change" >> "$HOME/.vimrc"
local status_output
run_homesick "status parity-castle"
status_output="$RUN_OUTPUT"
[[ "$status_output" == *"modified:"* ]] || fail "expected status output to include modified file"
local diff_output
run_homesick "diff parity-castle"
diff_output="$RUN_OUTPUT"
[[ "$diff_output" == *"diff --git"* ]] || fail "expected diff output to include git diff"
pass
echo "[9/18] pull --all"
local pull_all_output
run_homesick "pull --all"
pull_all_output="$RUN_OUTPUT"
[[ "$pull_all_output" == *"parity-castle:"* ]] || fail "expected pull --all output to include parity-castle"
[[ "$pull_all_output" == *"parity-castle-2:"* ]] || fail "expected pull --all output to include parity-castle-2"
pass
echo "[10/18] single-castle pull"
pushd "$work_root/base" >/dev/null
echo "single-castle-pull" > home/.pull-single
run_git add .
run_git commit -m "single-castle pull fixture"
run_git push
popd >/dev/null
run_homesick "pull parity-castle"
assert_path_exists "$HOME/.homesick/repos/parity-castle/home/.pull-single"
pass
echo "[11/18] exec"
local exec_marker="$HOME/.homesick/repos/parity-castle/.exec-marker"
run_homesick "exec parity-castle touch .exec-marker"
assert_path_exists "$exec_marker"
pass
echo "[12/18] exec_all"
local exec_all_marker_a="$HOME/.homesick/repos/parity-castle/.exec-all-marker"
local exec_all_marker_b="$HOME/.homesick/repos/parity-castle-2/.exec-all-marker"
run_homesick "exec_all touch .exec-all-marker"
assert_path_exists "$exec_all_marker_a"
assert_path_exists "$exec_all_marker_b"
pass
echo "[13/18] generate"
local generated_castle="$HOME/generated-castle"
run_homesick "generate $generated_castle"
assert_path_exists "$generated_castle/.git"
assert_path_exists "$generated_castle/home"
pass
echo "[14/18] commit and push"
echo "commit-change" >> "$HOME/.zshrc"
run_homesick "commit parity-castle behavior-suite-commit"
run_homesick "push parity-castle"
local remote_head
remote_head="$(git --git-dir "$remote_root/base.git" log --oneline -1)"
[[ "$remote_head" == *"behavior-suite-commit"* ]] || fail "expected pushed commit in remote history"
pass
echo "[15/18] open"
run_homesick_with_env "EDITOR=true" "open parity-castle"
pass
echo "[16/18] cd"
run_homesick_with_env "SHELL=/bin/true" "cd parity-castle"
pass
echo "[17/18] rc --force"
local rc_marker="$HOME/rc-force-was-here"
cat > "$HOME/.homesick/repos/parity-castle/.homesickrc" <<EOF
File.write('$rc_marker', 'ok\n')
EOF
run_homesick "rc --force parity-castle"
assert_path_exists "$rc_marker"
pass
echo "[18/18] destroy confirmation + version"
run_homesick_with_stdin "n\n" "destroy parity-castle"
assert_path_exists "$HOME/.homesick/repos/parity-castle"
run_homesick_with_stdin "y\n" "destroy parity-castle"
assert_path_missing "$HOME/.homesick/repos/parity-castle"
assert_path_missing "$HOME/.vimrc"
local version_output
run_homesick "version"
version_output="$RUN_OUTPUT"
[[ "$version_output" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "expected semantic version output, got: $version_output"
pass
echo "PASS: behavior suite completed for command: $HOMESICK_CMD"
}
parse_args "$@"
run_suite