"""
Unit tests untuk netdiag.utils module.
"""

import unittest
import ipaddress
from netdiag.utils import (
    validate_hostname,
    validate_port,
    validate_port_range,
    validate_timeout,
    validate_count,
    format_duration,
    is_private_ip,
    get_common_ports,
    sanitize_filename
)
from netdiag.exceptions import ValidationError


class TestValidationFunctions(unittest.TestCase):
    """Test validation utility functions."""
    
    def test_validate_hostname_valid(self):
        """Test valid hostname validation."""
        # Valid hostnames
        self.assertEqual(validate_hostname("google.com"), "google.com")
        self.assertEqual(validate_hostname("sub.domain.com"), "sub.domain.com")
        self.assertEqual(validate_hostname("localhost"), "localhost")
        
        # Valid IP addresses
        self.assertEqual(validate_hostname("192.168.1.1"), "192.168.1.1")
        self.assertEqual(validate_hostname("8.8.8.8"), "8.8.8.8")
        
    def test_validate_hostname_invalid(self):
        """Test invalid hostname validation."""
        with self.assertRaises(ValidationError):
            validate_hostname("")
        
        with self.assertRaises(ValidationError):
            validate_hostname("   ")
            
        with self.assertRaises(ValidationError):
            validate_hostname(None)
            
        with self.assertRaises(ValidationError):
            validate_hostname("a" * 254)  # Too long
    
    def test_validate_port_valid(self):
        """Test valid port validation."""
        self.assertEqual(validate_port(80), 80)
        self.assertEqual(validate_port("443"), 443)
        self.assertEqual(validate_port(65535), 65535)
        self.assertEqual(validate_port(1), 1)
    
    def test_validate_port_invalid(self):
        """Test invalid port validation."""
        with self.assertRaises(ValidationError):
            validate_port(0)
            
        with self.assertRaises(ValidationError):
            validate_port(65536)
            
        with self.assertRaises(ValidationError):
            validate_port("invalid")
            
        with self.assertRaises(ValidationError):
            validate_port(-1)
    
    def test_validate_port_range_valid(self):
        """Test valid port range validation."""
        start, end = validate_port_range(80, 443)
        self.assertEqual(start, 80)
        self.assertEqual(end, 443)
        
        start, end = validate_port_range("20", "100")
        self.assertEqual(start, 20)
        self.assertEqual(end, 100)
    
    def test_validate_port_range_invalid(self):
        """Test invalid port range validation."""
        with self.assertRaises(ValidationError):
            validate_port_range(443, 80)  # Start > End
            
        with self.assertRaises(ValidationError):
            validate_port_range(1, 10002)  # Range too large (10001 ports)
    
    def test_validate_timeout_valid(self):
        """Test valid timeout validation."""
        self.assertEqual(validate_timeout(5), 5.0)
        self.assertEqual(validate_timeout("10.5"), 10.5)
        self.assertEqual(validate_timeout(0.1), 0.1)
    
    def test_validate_timeout_invalid(self):
        """Test invalid timeout validation."""
        with self.assertRaises(ValidationError):
            validate_timeout(0)
            
        with self.assertRaises(ValidationError):
            validate_timeout(-1)
            
        with self.assertRaises(ValidationError):
            validate_timeout(301)  # Too large
            
        with self.assertRaises(ValidationError):
            validate_timeout("invalid")
    
    def test_validate_count_valid(self):
        """Test valid count validation."""
        self.assertEqual(validate_count(5), 5)
        self.assertEqual(validate_count("10"), 10)
        self.assertEqual(validate_count(100), 100)
    
    def test_validate_count_invalid(self):
        """Test invalid count validation."""
        with self.assertRaises(ValidationError):
            validate_count(0)
            
        with self.assertRaises(ValidationError):
            validate_count(-1)
            
        with self.assertRaises(ValidationError):
            validate_count(101)  # Too large
            
        with self.assertRaises(ValidationError):
            validate_count("invalid")


class TestUtilityFunctions(unittest.TestCase):
    """Test utility functions."""
    
    def test_format_duration(self):
        """Test duration formatting."""
        self.assertEqual(format_duration(0.5), "500.0ms")
        self.assertEqual(format_duration(1.5), "1.50s")
        self.assertEqual(format_duration(65), "1m 5.0s")
        self.assertEqual(format_duration(3665), "1h 1m")
    
    def test_is_private_ip(self):
        """Test private IP detection."""
        self.assertTrue(is_private_ip("192.168.1.1"))
        self.assertTrue(is_private_ip("10.0.0.1"))
        self.assertTrue(is_private_ip("172.16.0.1"))
        
        self.assertFalse(is_private_ip("8.8.8.8"))
        self.assertFalse(is_private_ip("1.1.1.1"))
        self.assertFalse(is_private_ip("invalid"))
    
    def test_get_common_ports(self):
        """Test common ports dictionary."""
        ports = get_common_ports()
        
        self.assertIsInstance(ports, dict)
        self.assertIn(80, ports)
        self.assertIn(443, ports)
        self.assertEqual(ports[80], 'HTTP')
        self.assertEqual(ports[443], 'HTTPS')
    
    def test_sanitize_filename(self):
        """Test filename sanitization."""
        self.assertEqual(sanitize_filename("normal.txt"), "normal.txt")
        self.assertEqual(sanitize_filename("file:with<bad>chars"), "file_with_bad_chars")
        self.assertEqual(sanitize_filename(""), "netdiag_output")
        self.assertEqual(sanitize_filename("   "), "netdiag_output")


if __name__ == '__main__':
    unittest.main()