391 lines
12 KiB
Bash
Executable File
391 lines
12 KiB
Bash
Executable File
#!/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
|