#!/usr/bin/env python3
#   Copyright (C) 2026 John Kacur
# SPDX-License-Identifier: GPL-2.0-only
"""
Unit tests for argument converter functions.

Tests verify that threadstring_to_list, irqstring_to_list, and
socketstring_to_list properly convert string arguments to lists.
"""

import unittest
import sys
import os

# Add parent directory to path to import tuna-cmd
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# Import the converter functions from tuna-cmd
import importlib.util
spec = importlib.util.spec_from_file_location("tuna_cmd", os.path.join(os.path.dirname(os.path.dirname(__file__)), "tuna-cmd.py"))
tuna_cmd = importlib.util.module_from_spec(spec)


class MockPidStats:
    """Mock procfs.pidstats() for testing"""

    def __init__(self, pids=None):
        """Initialize with dict of pid -> info"""
        self.pids = pids or {}

    def find_by_regex(self, pattern):
        """Mock find_by_regex - returns PIDs based on pattern"""
        import re
        pattern_str = str(pattern)
        # fnmatch.translate('systemd*') creates a pattern matching 'systemd' followed by anything
        # fnmatch.translate('systemd') creates a pattern matching exactly 'systemd'

        # Check if it's a wildcard pattern (contains .* from fnmatch.translate)
        if '.*' in pattern.pattern:
            # This is 'systemd*' or similar - return multiple PIDs
            return [100, 101]
        else:
            # This is exact match 'systemd' - return single PID
            return [100]

    def find_by_name(self, name):
        """Mock find_by_name - exact name match"""
        if name == 'systemd':
            return [100]
        return []


class TestThreadstringToList(unittest.TestCase):
    """Test cases for threadstring_to_list() function"""

    @classmethod
    def setUpClass(cls):
        """Load the tuna-cmd module"""
        spec.loader.exec_module(tuna_cmd)

    def test_empty_string(self):
        """Test empty string returns empty list and False"""
        result, match_requested = tuna_cmd.threadstring_to_list('')
        self.assertEqual(result, [])
        self.assertFalse(match_requested)

    def test_single_numeric_pid(self):
        """Test single numeric PID"""
        result, match_requested = tuna_cmd.threadstring_to_list('123')
        self.assertEqual(result, [123])
        self.assertTrue(match_requested)

    def test_multiple_numeric_pids(self):
        """Test multiple comma-separated numeric PIDs"""
        result, match_requested = tuna_cmd.threadstring_to_list('1,2,3')
        self.assertEqual(sorted(result), [1, 2, 3])
        self.assertTrue(match_requested)

    def test_duplicate_pids_deduplicated(self):
        """Test duplicate PIDs are deduplicated"""
        result, match_requested = tuna_cmd.threadstring_to_list('1,2,1,3,2')
        self.assertEqual(sorted(result), [1, 2, 3])
        self.assertTrue(match_requested)

    def test_pattern_with_mock_ps(self):
        """Test pattern matching with mock ps"""
        mock_ps = MockPidStats()
        result, match_requested = tuna_cmd.threadstring_to_list('systemd*', mock_ps)
        self.assertEqual(sorted(result), [100, 101])
        self.assertTrue(match_requested)

    def test_exact_name_with_mock_ps(self):
        """Test exact name matching with mock ps"""
        mock_ps = MockPidStats()
        result, match_requested = tuna_cmd.threadstring_to_list('systemd', mock_ps)
        self.assertEqual(result, [100])
        self.assertTrue(match_requested)

    def test_mixed_numeric_and_pattern(self):
        """Test mixed numeric PIDs and patterns"""
        mock_ps = MockPidStats()
        result, match_requested = tuna_cmd.threadstring_to_list('1,systemd*,5', mock_ps)
        self.assertIn(1, result)
        self.assertIn(5, result)
        self.assertIn(100, result)
        self.assertIn(101, result)
        self.assertTrue(match_requested)


class TestIrqstringToList(unittest.TestCase):
    """Test cases for irqstring_to_list() function"""

    @classmethod
    def setUpClass(cls):
        """Load the tuna-cmd module"""
        spec.loader.exec_module(tuna_cmd)

    def test_empty_string(self):
        """Test empty string returns empty list and False"""
        result, match_requested = tuna_cmd.irqstring_to_list('')
        self.assertEqual(result, [])
        self.assertFalse(match_requested)

    def test_single_numeric_irq(self):
        """Test single numeric IRQ"""
        result, match_requested = tuna_cmd.irqstring_to_list('42')
        self.assertEqual(result, [42])
        self.assertTrue(match_requested)

    def test_multiple_numeric_irqs(self):
        """Test multiple comma-separated numeric IRQs"""
        result, match_requested = tuna_cmd.irqstring_to_list('1,2,42')
        self.assertEqual(sorted(result), [1, 2, 42])
        self.assertTrue(match_requested)

    def test_duplicate_irqs_deduplicated(self):
        """Test duplicate IRQs are deduplicated"""
        result, match_requested = tuna_cmd.irqstring_to_list('1,2,1,42,2')
        self.assertEqual(sorted(result), [1, 2, 42])
        self.assertTrue(match_requested)


class TestSocketstringToList(unittest.TestCase):
    """Test cases for socketstring_to_list() function"""

    @classmethod
    def setUpClass(cls):
        """Load the tuna-cmd module"""
        spec.loader.exec_module(tuna_cmd)

    def test_socketstring_exists(self):
        """Test that socketstring_to_list function exists"""
        # Note: socketstring_to_list doesn't return match_requested tuple
        # and requires access to sysfs.cpus() which may not be available
        # in test environment. Just verify the function exists.
        self.assertTrue(callable(tuna_cmd.socketstring_to_list))


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