# -*- coding: utf-8 -*-
"""
自杀式进程杀防护测试。

覆盖 ShellExecTool._detect_suicide 检测的 3 类危险命令模式：
1. PowerShell Stop-Process -Name python / pythonw
2. cmd taskkill /IM python.exe /IM pythonw.exe
3. Unix killall python / pkill python

例外：用 -Id 精确指定 PID 的合法命令不应被拦截。
"""
import pytest

from abyss.tools.shell_exec import ShellExecTool


@pytest.fixture
def tool():
    return ShellExecTool()


# ---------- 应拦截 ----------

@pytest.mark.parametrize("cmd", [
    # 基本形式
    "Stop-Process -Name python -Force",
    # 不带 -Force
    "Stop-Process -Name python",
    # pythonw
    "Stop-Process -Name pythonw -Force",
    # 通配符
    "Stop-Process -Name python* -Force",
    # 参数顺序变化（-Force 在前）
    "Stop-Process -Force -Name python",
    # 大小写混合
    "stop-process -name Python -Force",
    # 前置 cd
    'cd "D:\\proj"; Stop-Process -Name python -Force',
    # 管道组合（仍应拦截）
    "Get-Process python | Stop-Process -Name python -Force",
])
def test_blocks_powershell_stop_process_by_name(tool, cmd):
    """Stop-Process -Name python* 应被拦截。"""
    result = tool.execute(command=cmd, timeout=5)

    assert result["success"] is False
    assert "自杀" in result["error"] or "abyss 自身" in result["error"]


@pytest.mark.parametrize("cmd", [
    # 基本
    "taskkill /F /IM python.exe",
    # 不带 /F
    "taskkill /IM python.exe",
    # pythonw
    "taskkill /F /IM pythonw.exe",
    # 多参数
    "taskkill /F /T /IM python.exe",
    # 大小写
    "TASKKILL /f /im Python.exe",
])
def test_blocks_taskkill_im_python(tool, cmd):
    """taskkill /IM python.exe 应被拦截。"""
    result = tool.execute(command=cmd, timeout=5)

    assert result["success"] is False
    assert "自杀" in result["error"] or "abyss 自身" in result["error"]


@pytest.mark.parametrize("cmd", [
    "killall python",
    "killall -9 python",
    "pkill python",
    "pkill -f python",
    "pkill -9 python",
])
def test_blocks_unix_killall_python(tool, cmd):
    """Unix killall/pkill python 应被拦截。"""
    result = tool.execute(command=cmd, timeout=5)

    assert result["success"] is False
    assert "自杀" in result["error"] or "abyss 自身" in result["error"]


# ---------- 不应拦截（合法用法） ----------

@pytest.mark.parametrize("cmd", [
    # 用 -Id 精确指定 PID（合法用法）
    "Stop-Process -Id 12345 -Force",
    # 用进程对象（变量）
    "$p = Start-Process python -ArgumentList x.py -PassThru; Stop-Process -Id $p.Id -Force",
    # Get-Date -Format（合法，不应被 format 误伤）
    "Get-Date -Format 'yyyy-MM-dd'",
    # 其他 Stop-Process 用法（非 python）
    "Stop-Process -Name notepad -Force",
    "Stop-Process -Name chrome -Force",
    # 其他 taskkill（非 python）
    "taskkill /F /IM notepad.exe",
    # 完全无关的命令
    "echo hello",
    "Get-ChildItem",
    "python snake_game.py",
])
def test_allows_legitimate_commands(tool, cmd):
    """合法命令不应被自杀检测拦截。

    注意：这些命令仍会经过 _is_safe 和 ToolSafetyGuard，可能因其他原因被拦截，
    但不应因自杀检测被拦截。这里只验证错误信息不含"自杀"字样。
    """
    # 直接调用 _detect_suicide 检测
    suicide_reason = ShellExecTool._detect_suicide(cmd)
    assert suicide_reason is None, f"合法命令被误判为自杀：{cmd} → {suicide_reason}"


# ---------- 错误信息可读性 ----------

def test_error_message_includes_guidance(tool):
    """错误信息应包含 -PassThru + -Id 的修复建议，让 LLM 知道怎么改。"""
    result = tool.execute(command="Stop-Process -Name python -Force", timeout=5)

    assert result["success"] is False
    assert "PassThru" in result["error"]
    assert "-Id" in result["error"]


def test_error_message_mentions_abyss_self(tool):
    """错误信息应说明会杀掉 abyss 自身。"""
    result = tool.execute(command="Stop-Process -Name python -Force", timeout=5)

    assert result["success"] is False
    assert "abyss" in result["error"] or "自身" in result["error"]
