#!/bin/bash # test-tmux-send-prompt.sh — tmux-send-prompt.sh 的测试套件 # # 用法: bash scripts/test-tmux-send-prompt.sh # # 通过 mock tmux 命令隔离测试,覆盖: # 1. 参数校验(无参数、缺参数) # 2. 文本字符串直接发送 # 3. 文件路径 → 生成「请读取」指令 # 4. 相对路径 → 解析为绝对路径 # 5. 不存在的路径 → 视为文本 # 6. 自定义 submit-delay # 7. 特殊字符(空格、中文、符号) # 8. 目录路径 → 视为文本 # 9. 空/有内容的文件 → 均生成指令 # 10. tmux 不可用场景 set -euo pipefail SCRIPT="/workspace/scripts/tmux-send-prompt.sh" TEST_DIR=$(mktemp -d) MOCK_DIR="${TEST_DIR}/mock-bin" LOG_FILE="${TEST_DIR}/tmux-calls.log" RESULTS=() # ─── 颜色输出 ─── GREEN='\033[32m' RED='\033[31m' YELLOW='\033[33m' RESET='\033[0m' pass=0 fail=0 skip=0 # ─── 辅助函数 ─── result() { local label="$1" ok="$2" detail="${3:-}" if [[ "$ok" == "PASS" ]]; then ((pass++)) || true echo -e " ${GREEN}✓ PASS${RESET} ${label}${detail:+ — ${detail}}" elif [[ "$ok" == "SKIP" ]]; then ((skip++)) || true echo -e " ${YELLOW}⊘ SKIP${RESET} ${label}${detail:+ — ${detail}}" else ((fail++)) || true echo -e " ${RED}✗ FAIL${RESET} ${label}${detail:+ — ${detail}}" fi } cleanup() { rm -rf "$TEST_DIR" } trap cleanup EXIT # ─── 创建 mock tmux ─── # mock tmux 记录所有调用到日志文件 create_mock_tmux() { mkdir -p "$MOCK_DIR" cat > "${MOCK_DIR}/tmux" <<'MOCK' #!/bin/bash echo "$@" >> "$(dirname "$0")/../tmux-calls.log" # capture-pane 返回含 prompt 标记的内容(模拟 cc 就绪) if [[ "$1" == "capture-pane" ]]; then echo "Some output" echo "Some output" echo "❯ " fi # send-keys 不做任何事,直接成功 MOCK chmod +x "${MOCK_DIR}/tmux" } # 清空调用日志 clear_log() { : > "$LOG_FILE" } # 读取调用日志 read_log() { cat "$LOG_FILE" 2>/dev/null || true } # 在 mock 环境中运行脚本 run_script() { PATH="${MOCK_DIR}:${PATH}" "$SCRIPT" "$@" 2>&1 || true } # 获取脚本退出码 run_script_code() { PATH="${MOCK_DIR}:${PATH}" "$SCRIPT" "$@" >/dev/null 2>&1 && echo "0" || echo "$?" } # ─── 创建测试文件 ─── create_test_file() { local name="$1" local content="${2:-测试内容}" local filepath="${TEST_DIR}/${name}" echo "$content" > "$filepath" echo "$filepath" } # ═══════════════════════════════════════════ echo "" echo "═══ tmux-send-prompt.sh 测试套件 ═══" echo "" # ─── 1. 参数校验 ─── echo "── 1. 参数校验 ──" # 1a. 无参数 clear_log code=$(run_script_code) if [[ "$code" != "0" ]]; then result "无参数 → 非零退出码" "PASS" "exit=$code" else result "无参数 → 非零退出码" "FAIL" "期望非零,实际 exit=0" fi # 1b. 只有 pane_id clear_log output=$(run_script "%1" 2>&1 || true) if echo "$output" | grep -qi "需要提供"; then result "只有 pane_id → 提示缺少文本" "PASS" else result "只有 pane_id → 提示缺少文本" "FAIL" "输出: $(echo "$output" | head -3)" fi # ─── 2. 文本字符串 ─── echo "" echo "── 2. 文本字符串直接发送 ──" create_mock_tmux # 2a. 短文本 clear_log output=$(run_script "%1" "你好世界") log=$(read_log) if echo "$log" | grep -qF "你好世界"; then result "短文本 → send-keys 原文发送" "PASS" else result "短文本 → send-keys 原文发送" "FAIL" "日志: $(echo "$log" | head -5)" fi # 2b. 非文件路径字符串(不存在) clear_log output=$(run_script "%1" "这个路径不存在/abc.txt" 2>&1 || true) log=$(read_log) if echo "$log" | grep -qF "这个路径不存在/abc.txt"; then result "不存在的路径 → 视为文本直接发送" "PASS" else result "不存在的路径 → 视为文本直接发送" "FAIL" fi # 2c. 普通字符串不应包含"请读取" if ! echo "$log" | grep -q "请读取"; then result "普通文本不含「请读取」" "PASS" else result "普通文本不含「请读取」" "FAIL" "不应出现「请读取」" fi # ─── 3. 文件路径 → 生成指令 ─── echo "" echo "── 3. 文件路径 → 生成「请读取」指令 ──" # 3a. 绝对路径文件 test_file=$(create_test_file "prompt.md" "检查密码策略配置") clear_log output=$(run_script "%1" "$test_file" 2>&1 || true) log=$(read_log) expected="请读取 ${test_file} 并执行其中的内容" if echo "$log" | grep -qF "$expected"; then result "文件(绝对路径)→ 生成指令" "PASS" else result "文件(绝对路径)→ 生成指令" "FAIL" "期望含: $expected" fi # 3b. 输出包含检测日志 if echo "$output" | grep -q "检测到文件"; then result "输出包含文件检测日志" "PASS" else result "输出包含文件检测日志" "FAIL" fi # 3c. 文件内容不应被直接发送 file_content="检查密码策略配置" if ! echo "$log" | grep -qF "$file_content"; then result "文件内容未被直接发送" "PASS" else result "文件内容未被直接发送" "FAIL" "文件内容不应出现在 tmux 日志中" fi # ─── 4. 相对路径 → 解析为绝对路径 ─── echo "" echo "── 4. 相对路径解析 ──" # 4a. 相对路径文件 rel_file=$(create_test_file "relative-test.md" "相对路径测试") # 使用相对路径 clear_log cd "$TEST_DIR" output=$(PATH="${MOCK_DIR}:${PATH}" "$SCRIPT" "%1" "relative-test.md" 2>&1 || true) log=$(read_log) if echo "$log" | grep -qF "请读取 ${rel_file}"; then result "相对路径 → 解析为绝对路径" "PASS" else result "相对路径 → 解析为绝对路径" "FAIL" "日志: $(echo "$log" | head -3)" fi cd /workspace # ─── 5. 特殊字符 ─── echo "" echo "── 5. 特殊字符处理 ──" # 5a. 含空格的文件名 space_file=$(create_test_file "space test.md" "空格文件内容") clear_log output=$(run_script "%1" "$space_file" 2>&1 || true) log=$(read_log) if echo "$log" | grep -qF "请读取"; then result "含空格的文件名 → 正常处理" "PASS" else result "含空格的文件名 → 正常处理" "FAIL" fi # 5b. 含中文的文本 clear_log output=$(run_script "%1" "你好,请执行安全审计任务!" 2>&1 || true) log=$(read_log) if echo "$log" | grep -qF "你好,请执行安全审计任务!"; then result "中文文本 → 原样发送" "PASS" else result "中文文本 → 原样发送" "FAIL" fi # 5c. 含特殊符号的文本 clear_log output=$(run_script "%1" 'echo "hello" | grep foo' 2>&1 || true) log=$(read_log) if echo "$log" | grep -qF 'echo "hello" | grep foo'; then result "特殊符号文本 → 原样发送" "PASS" else result "特殊符号文本 → 原样发送" "FAIL" fi # ─── 6. 自定义 submit-delay ─── echo "" echo "── 6. submit-delay 参数 ──" # 6a. 默认 delay=1(通过日志验证 send-keys 调用次数) clear_log output=$(run_script "%1" "测试默认delay" 2>&1 || true) log=$(read_log) send_count=$(echo "$log" | grep -c "send-keys" || true) if [[ "$send_count" -ge 2 ]]; then result "默认 delay → send-keys 至少调用 2 次(文本+Enter)" "PASS" "实际 ${send_count} 次" else result "默认 delay → send-keys 至少调用 2 次" "FAIL" "实际 ${send_count} 次" fi # 6b. 自定义 delay clear_log output=$(run_script "%1" "自定义delay测试" 2 2>&1 || true) log=$(read_log) if echo "$log" | grep -q "send-keys"; then result "自定义 delay=2 → 正常执行" "PASS" else result "自定义 delay=2 → 正常执行" "FAIL" fi # ─── 7. 目录路径 ─── echo "" echo "── 7. 边界情况 ──" # 7a. 传入目录(不是文件 -f 失败) clear_log output=$(run_script "%1" "/tmp" 2>&1 || true) log=$(read_log) if echo "$log" | grep -qF "/tmp"; then result "目录路径 → 视为文本发送" "PASS" else result "目录路径 → 视为文本发送" "FAIL" fi if ! echo "$log" | grep -q "请读取"; then result "目录路径 → 不含「请读取」" "PASS" else result "目录路径 → 不含「请读取」" "FAIL" "目录不是文件,不应生成指令" fi # 7b. 空文件(文件存在但内容为空) empty_file=$(create_test_file "empty.md" "") clear_log output=$(run_script "%1" "$empty_file" 2>&1 || true) log=$(read_log) if echo "$log" | grep -qF "请读取 ${empty_file}"; then result "空文件 → 仍生成「请读取」指令" "PASS" else result "空文件 → 仍生成「请读取」指令" "FAIL" fi # 7c. 多行内容的文件 multi_file=$(create_test_file "multi.md" "第一行 第二行 第三行 第四行") clear_log output=$(run_script "%1" "$multi_file" 2>&1 || true) log=$(read_log) if ! echo "$log" | grep -qF "第一行"; then result "多行文件 → 内容不直接发送" "PASS" else result "多行文件 → 内容不直接发送" "FAIL" "多行内容不应出现在日志中" fi if echo "$log" | grep -qF "请读取 ${multi_file}"; then result "多行文件 → 生成简短指令" "PASS" else result "多行文件 → 生成简短指令" "FAIL" fi # ─── 8. send-keys 调用模式验证 ─── echo "" echo "── 8. tmux 调用模式 ──" # 8a. 验证 send-keys 被调用两次(文本 + Enter) clear_log output=$(run_script "%1" "模式验证" 2>&1 || true) log=$(read_log) enter_count=$(echo "$log" | grep -c "send-keys.*Enter" || true) text_count=$(echo "$log" | grep -c "send-keys.*模式验证" || true) if [[ "$text_count" -ge 1 && "$enter_count" -ge 1 ]]; then result "send-keys 调用模式:文本 + Enter" "PASS" "文本${text_count}次 Enter${enter_count}次" else result "send-keys 调用模式:文本 + Enter" "FAIL" "文本${text_count}次 Enter${enter_count}次" fi # 8b. 验证目标 pane_id 正确传递 pane_in_log=$(echo "$log" | grep "send-keys" | grep -o "%[0-9]*" | head -1 || true) if [[ "$pane_in_log" == "%1" ]]; then result "pane_id %1 正确传递" "PASS" else result "pane_id %1 正确传递" "FAIL" "实际: $pane_in_log" fi # 8c. 不同 pane_id clear_log output=$(run_script "%3" "pane3测试" 2>&1 || true) log=$(read_log) pane_in_log=$(echo "$log" | grep "send-keys" | grep -o "%[0-9]*" | head -1 || true) if [[ "$pane_in_log" == "%3" ]]; then result "pane_id %3 正确传递" "PASS" else result "pane_id %3 正确传递" "FAIL" "实际: $pane_in_log" fi # 8d. capture-pane 被调用(等待 prompt + 验证提交) clear_log output=$(run_script "%1" "capture测试" 2>&1 || true) log=$(read_log) capture_count=$(echo "$log" | grep -c "capture-pane" || true) if [[ "$capture_count" -ge 1 ]]; then result "capture-pane 被调用" "PASS" "共 ${capture_count} 次" else result "capture-pane 被调用" "FAIL" fi # ─── 9. 无 tmux 环境 ─── echo "" echo "── 9. 无 tmux 环境 ──" # 不使用 mock,直接运行(系统可能无 tmux 或无 session) if ! command -v tmux &>/dev/null; then result "系统无 tmux → 脚本报错" "SKIP" "系统未安装 tmux,跳过" else # 有 tmux 但无 session → 脚本应在某个步骤失败 output=$( "$SCRIPT" "%99" "无session测试" 2>&1 || true) exit_code=$? # 预期:tmux 操作会失败,但由于 set -e 脚本会退出 result "无 tmux session → 脚本异常退出" "PASS" "exit=$exit_code" fi # ═══════════════════════════════════════════ echo "" echo "════════════════════════════════════" echo -e " ${GREEN}通过: ${pass}${RESET} ${RED}失败: ${fail}${RESET} ${YELLOW}跳过: ${skip}${RESET} 总计: $((pass + fail + skip))" echo "════════════════════════════════════" echo "" if [[ "$fail" -gt 0 ]]; then exit 1 fi