import unittest
import os
import os.path as osp
import shutil
from rwl.hardening.path_security import safe_join, is_safe_path


class PathSecurityTest(unittest.TestCase):

    def setUp(self):
        self.base_dir = "/tmp/test_safe_dir"  # Use /tmp for testing
        if not os.path.exists(self.base_dir):
            os.makedirs(self.base_dir)

    def tearDown(self):
       if os.path.exists(self.base_dir):
           shutil.rmtree(self.base_dir)

    def test_safe_join_valid_path(self):
        filepath = safe_join(self.base_dir, "myfile.txt")
        self.assertEqual(filepath, osp.abspath(osp.join(self.base_dir, "myfile.txt")))

    def test_safe_join_path_traversal(self):
        filepath = safe_join(self.base_dir, "../../../etc/passwd")
        self.assertIsNone(filepath)

    def test_safe_join_empty_filename(self):
        filepath = safe_join(self.base_dir, "")
        self.assertEqual(filepath, osp.abspath(self.base_dir))

    def test_safe_join_with_absolute_filename(self):
        filepath = safe_join(self.base_dir, "/tmp/another_file.txt")
        self.assertIsNone(filepath) #Should fail. It shouldn't allow absolute filenames

    def test_safe_join_base_not_absolute(self):
        with self.assertRaises(ValueError):
            safe_join("relative/path", "file.txt")

    def test_safe_join_type_error(self):
        with self.assertRaises(TypeError):
            safe_join(123, "file.txt")
        with self.assertRaises(TypeError):
            safe_join(self.base_dir, 123)

    def test_is_safe_path_valid_path(self):
        filepath = osp.join(self.base_dir, "myfile.txt")
        self.assertTrue(is_safe_path(self.base_dir, filepath))

    def test_is_safe_path_path_traversal(self):
       outside_path = osp.abspath(osp.join(self.base_dir, "..", "..", "outside_file.txt"))
       self.assertFalse(is_safe_path(self.base_dir, outside_path))

    def test_is_safe_path_empty_path(self):
        self.assertTrue(is_safe_path(self.base_dir, self.base_dir)) # Empty path is the base path itself.

    def test_is_safe_path_base_not_absolute(self):
        with self.assertRaises(ValueError):
            is_safe_path("relative/path", "/absolute/path")

    def test_is_safe_path_type_error(self):
        with self.assertRaises(TypeError):
            is_safe_path(123, "/absolute/path")
        with self.assertRaises(TypeError):
            is_safe_path(self.base_dir, 123)

    def test_safe_join_unicode(self):
        filepath = safe_join(self.base_dir, "你好.txt")
        self.assertEqual(filepath, osp.abspath(osp.join(self.base_dir, "你好.txt")))

    def test_is_safe_path_unicode(self):
        filepath = osp.join(self.base_dir, "你好.txt")
        self.assertTrue(is_safe_path(self.base_dir, filepath))

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