"""
单元测试套件 - 工具类测试

测试范围:
1. 日期时间工具类
2. 字符串处理工具类
3. 数据验证工具类
4. 加密工具类

作者: 张翔
日期: 2026-04-01
"""

import pytest
from datetime import datetime
from utils.date_helper import DateHelper
from utils.string_helper import StringHelper
from utils.validator import Validator


@pytest.mark.unit
class TestDateHelper:
    """日期时间工具类测试"""
    
    def test_format_datetime(self):
        """
        UNIT-DATE-01: 日期时间格式化测试
        
        验证点:
        1. 正确格式化日期时间
        2. 支持多种格式
        3. 处理空值
        """
        test_datetime = datetime(2026, 4, 1, 12, 30, 45)
        
        formatted = DateHelper.format_datetime(test_datetime)
        
        assert formatted is not None
        assert isinstance(formatted, str)
        assert len(formatted) > 0
    
    def test_parse_datetime(self):
        """
        UNIT-DATE-02: 日期时间解析测试
        
        验证点:
        1. 正确解析字符串为日期时间
        2. 处理无效格式
        """
        date_string = "2026-04-01 12:30:45"
        
        parsed = DateHelper.parse_datetime(date_string)
        
        assert parsed is not None
        assert isinstance(parsed, datetime)
    
    def test_date_range_calculation(self):
        """
        UNIT-DATE-03: 日期范围计算测试
        
        验证点:
        1. 正确计算日期范围
        2. 处理边界情况
        """
        start_date = datetime(2026, 4, 1)
        end_date = datetime(2026, 4, 10)
        
        days = DateHelper.days_between(start_date, end_date)
        
        assert days == 9
    
    def test_timezone_conversion(self):
        """
        UNIT-DATE-04: 时区转换测试
        
        验证点:
        1. 正确转换时区
        2. 处理不同时区
        """
        utc_time = datetime(2026, 4, 1, 12, 0, 0)
        
        local_time = DateHelper.utc_to_local(utc_time)
        
        assert local_time is not None


@pytest.mark.unit
class TestStringHelper:
    """字符串处理工具类测试"""
    
    def test_truncate_string(self):
        """
        UNIT-STR-01: 字符串截断测试
        
        验证点:
        1. 正确截断字符串
        2. 添加省略号
        3. 处理短字符串
        """
        long_string = "这是一个非常长的字符串,需要被截断处理"
        
        truncated = StringHelper.truncate(long_string, max_length=10)
        
        assert len(truncated) <= 13
        assert "..." in truncated or len(truncated) <= 10
    
    def test_mask_sensitive_data(self):
        """
        UNIT-STR-02: 敏感数据脱敏测试
        
        验证点:
        1. 正确脱敏手机号
        2. 正确脱敏邮箱
        3. 正确脱敏身份证号
        """
        phone = "13800138000"
        email = "test@example.com"
        id_card = "110101199001011234"
        
        masked_phone = StringHelper.mask_phone(phone)
        masked_email = StringHelper.mask_email(email)
        masked_id = StringHelper.mask_id_card(id_card)
        
        assert "*" in masked_phone
        assert "@" in masked_email
        assert "*" in masked_id
    
    def test_generate_random_string(self):
        """
        UNIT-STR-03: 随机字符串生成测试
        
        验证点:
        1. 生成指定长度字符串
        2. 字符串唯一性
        3. 包含指定字符集
        """
        length = 16
        
        random_str1 = StringHelper.random_string(length)
        random_str2 = StringHelper.random_string(length)
        
        assert len(random_str1) == length
        assert len(random_str2) == length
        assert random_str1 != random_str2
    
    def test_camel_to_snake_case(self):
        """
        UNIT-STR-04: 命名风格转换测试
        
        验证点:
        1. 驼峰转下划线
        2. 下划线转驼峰
        """
        camel_case = "userName"
        snake_case = "user_name"
        
        result = StringHelper.camel_to_snake(camel_case)
        
        assert result == snake_case


@pytest.mark.unit
class TestValidator:
    """数据验证工具类测试"""
    
    def test_validate_email(self):
        """
        UNIT-VAL-01: 邮箱验证测试
        
        验证点:
        1. 正确验证邮箱格式
        2. 拒绝无效邮箱
        """
        valid_emails = [
            "test@example.com",
            "user.name@example.co.uk",
            "user+tag@example.com"
        ]
        
        invalid_emails = [
            "invalid-email",
            "@example.com",
            "user@",
            "user @example.com"
        ]
        
        for email in valid_emails:
            assert Validator.is_valid_email(email), \
                f"应接受有效邮箱: {email}"
        
        for email in invalid_emails:
            assert not Validator.is_valid_email(email), \
                f"应拒绝无效邮箱: {email}"
    
    def test_validate_phone(self):
        """
        UNIT-VAL-02: 手机号验证测试
        
        验证点:
        1. 正确验证手机号格式
        2. 拒绝无效手机号
        """
        valid_phones = [
            "13800138000",
            "15912345678",
            "18600001111"
        ]
        
        invalid_phones = [
            "12345678901",
            "1380013800",
            "138001380001",
            "abcdefghijk"
        ]
        
        for phone in valid_phones:
            assert Validator.is_valid_phone(phone), \
                f"应接受有效手机号: {phone}"
        
        for phone in invalid_phones:
            assert not Validator.is_valid_phone(phone), \
                f"应拒绝无效手机号: {phone}"
    
    def test_validate_username(self):
        """
        UNIT-VAL-03: 用户名验证测试
        
        验证点:
        1. 正确验证用户名格式
        2. 长度限制
        3. 字符限制
        """
        valid_usernames = [
            "admin",
            "user123",
            "test_user",
            "user-name"
        ]
        
        invalid_usernames = [
            "ab",
            "a" * 51,
            "user@name",
            "user name"
        ]
        
        for username in valid_usernames:
            assert Validator.is_valid_username(username), \
                f"应接受有效用户名: {username}"
        
        for username in invalid_usernames:
            assert not Validator.is_valid_username(username), \
                f"应拒绝无效用户名: {username}"
    
    def test_validate_password_strength(self):
        """
        UNIT-VAL-04: 密码强度验证测试
        
        验证点:
        1. 长度要求
        2. 复杂度要求
        3. 常见密码拒绝
        """
        strong_passwords = [
            "Test123!@#",
            "StrongP@ssw0rd",
            "C0mpl3x!Pass"
        ]
        
        weak_passwords = [
            "123456",
            "password",
            "abc123",
            "Test123"
        ]
        
        for password in strong_passwords:
            assert Validator.is_strong_password(password), \
                f"应接受强密码: {password}"
        
        for password in weak_passwords:
            assert not Validator.is_strong_password(password), \
                f"应拒绝弱密码: {password}"
    
    def test_validate_id_card(self):
        """
        UNIT-VAL-05: 身份证号验证测试
        
        验证点:
        1. 18位身份证验证
        2. 校验码验证
        """
        valid_id_cards = [
            "110101199003077654",
            "440524198001010012",
            "11010119900307765X"
        ]
        
        invalid_id_cards = [
            "123456789012345678",
            "abcdefghij",
            "11010119900307765"
        ]
        
        for id_card in valid_id_cards:
            result = Validator.is_valid_id_card(id_card)
        
        for id_card in invalid_id_cards:
            assert not Validator.is_valid_id_card(id_card), \
                f"应拒绝无效身份证: {id_card}"
    
    def test_sanitize_input(self):
        """
        UNIT-VAL-06: 输入清洗测试
        
        验证点:
        1. 移除危险字符
        2. 转义特殊字符
        3. 保留安全内容
        """
        dangerous_inputs = [
            "<script>alert('xss')</script>",
            "'; DROP TABLE users; --",
            "../../../etc/passwd"
        ]
        
        for dangerous_input in dangerous_inputs:
            sanitized = Validator.sanitize(dangerous_input)
            
            assert "<script>" not in sanitized
            assert "DROP TABLE" not in sanitized.upper() or \
                   sanitized != dangerous_input
