#!/usr/bin/env bash set -euo pipefail : "${HOMESICK_CMD:=/workspace/dist/homesick-go}" : "${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" } 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/7] clone" run_homesick "clone file://$remote_root/base.git parity-castle" assert_path_exists "$HOME/.homesick/repos/parity-castle/.git" assert_path_exists "$HOME/.homesick/repos/parity-castle/home/.vimrc" pass echo "[2/7] 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 "[3/7] 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 "[4/7] 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 "[5/7] 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 include parity-castle path" pass echo "[6/7] 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 "[7/7] version" 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