import os
import sys
import unittest

# 상위 디렉토리를 Python 경로에 추가
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


class TestPythonCoreSyntax(unittest.TestCase):
    """Python 기본 문법 테스트 클래스"""

    def setUp(self):
        """테스트 전 설정"""
        pass

    def test_basic_data_types(self):
        """기본 데이터 타입 테스트"""
        # 정수
        my_integer = 10
        self.assertEqual(my_integer, 10)
        self.assertIsInstance(my_integer, int)

        # 실수
        my_float = 3.14
        self.assertEqual(my_float, 3.14)
        self.assertIsInstance(my_float, float)

        # 문자열
        my_string = "Hello, Python!"
        self.assertEqual(my_string, "Hello, Python!")
        self.assertIsInstance(my_string, str)

        # 불리언
        my_boolean = True
        self.assertTrue(my_boolean)
        self.assertIsInstance(my_boolean, bool)

    def test_list_operations(self):
        """리스트 연산 테스트"""
        my_list = [1, 2, "three", 4.0]

        # 기본 리스트 생성
        self.assertEqual(len(my_list), 4)
        self.assertEqual(my_list[0], 1)
        self.assertEqual(my_list[2], "three")

        # 요소 추가
        my_list.append(5)
        self.assertEqual(len(my_list), 5)
        self.assertEqual(my_list[-1], 5)

        # 슬라이싱
        sliced = my_list[1:3]
        self.assertEqual(sliced, [2, "three"])

        # 리스트 컴프리헨션
        squares = [x**2 for x in range(5)]
        self.assertEqual(squares, [0, 1, 4, 9, 16])

    def test_tuple_operations(self):
        """튜플 연산 테스트"""
        my_tuple = (1, 2, "three", 4.0)

        # 튜플 생성 및 접근
        self.assertEqual(len(my_tuple), 4)
        self.assertEqual(my_tuple[0], 1)
        self.assertEqual(my_tuple[2], "three")

        # 튜플은 불변
        with self.assertRaises(TypeError):
            my_tuple[0] = 99

    def test_dictionary_operations(self):
        """딕셔너리 연산 테스트"""
        my_dict = {"name": "Alice", "age": 25, "city": "New York"}

        # 기본 딕셔너리 생성
        self.assertEqual(len(my_dict), 3)
        self.assertEqual(my_dict["name"], "Alice")
        self.assertEqual(my_dict["age"], 25)

        # 새로운 키-값 쌍 추가
        my_dict["email"] = "alice@example.com"
        self.assertEqual(len(my_dict), 4)
        self.assertEqual(my_dict["email"], "alice@example.com")

        # 키 존재 확인
        self.assertIn("name", my_dict)
        self.assertNotIn("phone", my_dict)

        # 모든 키와 값
        keys = list(my_dict.keys())
        values = list(my_dict.values())
        self.assertIn("name", keys)
        self.assertIn("Alice", values)

    def test_set_operations(self):
        """집합 연산 테스트"""
        my_set = {1, 2, 3, 2, 1}  # 중복 제거

        # 기본 집합 생성
        self.assertEqual(len(my_set), 3)
        self.assertIn(1, my_set)
        self.assertIn(2, my_set)
        self.assertIn(3, my_set)

        # 요소 추가
        my_set.add(4)
        self.assertEqual(len(my_set), 4)
        self.assertIn(4, my_set)

        # 집합 연산
        other_set = {3, 4, 5, 6}

        # 합집합
        union_set = my_set.union(other_set)
        expected_union = {1, 2, 3, 4, 5, 6}
        self.assertEqual(union_set, expected_union)

        # 교집합
        intersection_set = my_set.intersection(other_set)
        expected_intersection = {3, 4}
        self.assertEqual(intersection_set, expected_intersection)

        # 차집합
        difference_set = my_set.difference(other_set)
        expected_difference = {1, 2}
        self.assertEqual(difference_set, expected_difference)

    def test_control_flow(self):
        """제어 흐름 테스트"""

        # if-elif-else
        def get_grade(score):
            if score >= 90:
                return "A"
            elif score >= 80:
                return "B"
            else:
                return "C"

        self.assertEqual(get_grade(95), "A")
        self.assertEqual(get_grade(85), "B")
        self.assertEqual(get_grade(75), "C")

        # for 반복문
        numbers = [1, 2, 3, 4, 5]
        sum_result = 0
        for num in numbers:
            sum_result += num
        self.assertEqual(sum_result, 15)

        # while 반복문
        count = 3
        result = []
        while count > 0:
            result.append(count)
            count -= 1
        self.assertEqual(result, [3, 2, 1])

    def test_functions(self):
        """함수 테스트"""

        def greet(name):
            """지정된 이름에게 인사하는 함수"""
            return f"안녕하세요, {name}님!"

        def calculate_area(width, height):
            """사각형의 넓이를 계산하는 함수"""
            area = width * height
            return area

        # greet 함수 테스트
        greeting = greet("파이썬")
        self.assertEqual(greeting, "안녕하세요, 파이썬님!")

        # calculate_area 함수 테스트
        area = calculate_area(10, 5)
        self.assertEqual(area, 50)

        # 다양한 입력값 테스트
        self.assertEqual(calculate_area(3, 4), 12)
        self.assertEqual(calculate_area(0, 5), 0)
        self.assertEqual(calculate_area(1, 1), 1)


class TestPythonCollections(unittest.TestCase):
    """Python 컬렉션 고급 기능 테스트 클래스"""

    def test_list_comprehension(self):
        """리스트 컴프리헨션 테스트"""
        # 기본 컴프리헨션
        squares = [x**2 for x in range(5)]
        self.assertEqual(squares, [0, 1, 4, 9, 16])

        # 조건부 컴프리헨션
        even_squares = [x**2 for x in range(10) if x % 2 == 0]
        self.assertEqual(even_squares, [0, 4, 16, 36, 64])

        # 중첩 컴프리헨션
        matrix = [[i + j for j in range(3)] for i in range(3)]
        expected = [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
        self.assertEqual(matrix, expected)

    def test_dictionary_comprehension(self):
        """딕셔너리 컴프리헨션 테스트"""
        # 기본 딕셔너리 컴프리헨션
        square_dict = {x: x**2 for x in range(5)}
        expected = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
        self.assertEqual(square_dict, expected)

        # 조건부 딕셔너리 컴프리헨션
        even_square_dict = {x: x**2 for x in range(10) if x % 2 == 0}
        expected = {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
        self.assertEqual(even_square_dict, expected)

    def test_set_comprehension(self):
        """집합 컴프리헨션 테스트"""
        # 기본 집합 컴프리헨션
        square_set = {x**2 for x in range(5)}
        expected = {0, 1, 4, 9, 16}
        self.assertEqual(square_set, expected)

        # 조건부 집합 컴프리헨션
        even_square_set = {x**2 for x in range(10) if x % 2 == 0}
        expected = {0, 4, 16, 36, 64}
        self.assertEqual(even_square_set, expected)


if __name__ == "__main__":
    # 테스트 스위트 생성
    test_suite = unittest.TestSuite()

    # 테스트 클래스 추가
    test_suite.addTest(unittest.makeSuite(TestPythonCoreSyntax))
    test_suite.addTest(unittest.makeSuite(TestPythonCollections))

    # 테스트 실행
    runner = unittest.TextTestRunner(verbosity=2)
    result = runner.run(test_suite)

    # 테스트 결과 출력
    print(f"\n테스트 결과: {len(result.failures)} 실패, {len(result.errors)} 오류")
    if result.failures:
        print("\n실패한 테스트:")
        for test, traceback in result.failures:
            print(f"- {test}: {traceback}")
    if result.errors:
        print("\n오류가 발생한 테스트:")
        for test, traceback in result.errors:
            print(f"- {test}: {traceback}")
