
# Beschreibung der Tests für die Funktion `getAngleFromVideo`
#
# Anforderung 1.3  -> Das System muss die Position der Arme in Winkel umwandeln.
# 
# 
# 1. Test der manuellen Berechnung der erwarteten Winkel:
#    - Es wird geprüft, ob die Funktion `getAngleFromVideo` korrekte Winkel für die Arme berechnet.
#    - Die Berechnung basiert auf synthetischen Landmark-Daten.
#    - Die Erwartungswerte werden manuell berechnet und mit den von der Funktion gelieferten Werten verglichen.

# Ziel:
#    - Korrekte Winkelberechnung basierend auf den bereitgestellten Daten.


#Ergebnis 
'''FF
======================================================================
FAIL: test_angle_calculation (__main__.TestGetAngleFromVideo.test_angle_calculation)
Testet die Berechnung der Armwinkel mit synthetischen Eingaben.
----------------------------------------------------------------------
    self.assertAlmostEqual(left_angle, expected_left_angle, delta=1.0)
AssertionError: np.float32(318.36646) != 333.43 within 1.0 delta (np.float32(15.063538) difference)
'''
#Winkel weicht um 15 Grad vom erwarteten winkel ab.



import unittest
import numpy as np
from io import StringIO
from collections import namedtuple
from BodyPoseEstimation import getAngleFromVideo
# Mock für PoseOutput und MarkerData
PoseLandmark = namedtuple('PoseLandmark', ['x', 'y'])
PoseOutput = namedtuple('PoseOutput', ['landmark'])
MarkerData = namedtuple('MarkerData', ['mid_shoulder', 'mid_hip', 'left_shoulder_parallel', 'left_hip_parallel', 'right_shoulder_parallel', 'right_hip_parallel'])

class MockPoseLandmark:
    LEFT_SHOULDER = 11
    RIGHT_SHOULDER = 12
    LEFT_ELBOW = 13
    RIGHT_ELBOW = 14
    LEFT_HIP = 23
    RIGHT_HIP = 24

PoseOutput = namedtuple('PoseOutput', ['landmark'])

def mock_pose_landmarks():
    """Erzeugt einen Mock von Pose-Landmark-Daten mit korrekten Indizes."""
    landmarks = [None] * 33  # Mediapipe hat 33 Landmark-Indizes
    landmarks[MockPoseLandmark.LEFT_SHOULDER] = PoseLandmark(0.5, 0.2)
    landmarks[MockPoseLandmark.RIGHT_SHOULDER] = PoseLandmark(0.6, 0.2)
    landmarks[MockPoseLandmark.LEFT_ELBOW] = PoseLandmark(0.4, 0.4)
    landmarks[MockPoseLandmark.RIGHT_ELBOW] = PoseLandmark(0.7, 0.4)
    landmarks[MockPoseLandmark.LEFT_HIP] = PoseLandmark(0.5, 0.6)
    landmarks[MockPoseLandmark.RIGHT_HIP] = PoseLandmark(0.6, 0.6)
    return PoseOutput(landmark=landmarks)
def calculate_expected_angle(vec, ref):
        """Berechnet den Winkel zwischen zwei Vektoren für den Erwartungswert."""
        angle_rad = np.arctan2(vec[1], vec[0]) - np.arctan2(ref[1], ref[0])
        return (np.degrees(angle_rad) + 360) % 360
def test_manual_expected_values(self):
        bodyMarker = mock_pose_landmarks()
        height, width = 720, 1280
        left_shoulder_px = np.array([bodyMarker.landmark[11].x * width, bodyMarker.landmark[11].y * height])
        right_shoulder_px = np.array([bodyMarker.landmark[12].x * width, bodyMarker.landmark[12].y * height])
        left_elbow_px = np.array([bodyMarker.landmark[13].x * width, bodyMarker.landmark[13].y * height])
        right_elbow_px = np.array([bodyMarker.landmark[14].x * width, bodyMarker.landmark[14].y * height])
        mid_shoulder_px = 0.5 * (left_shoulder_px + right_shoulder_px)
        mid_hip_px = 0.5 * (
            np.array([bodyMarker.landmark[23].x * width, bodyMarker.landmark[23].y * height]) +
            np.array([bodyMarker.landmark[24].x * width, bodyMarker.landmark[24].y * height])
        )
        vertical_ref = mid_hip_px - mid_shoulder_px
        left_arm = left_elbow_px - left_shoulder_px
        right_arm = right_elbow_px - right_shoulder_px

        expected_left_angle = 360 - calculate_expected_angle(left_arm, vertical_ref)
        expected_right_angle = calculate_expected_angle(right_arm, vertical_ref)

        print("Expected Left Angle:", expected_left_angle)
        print("Expected Right Angle:", expected_right_angle)
class TestGetAngleFromVideo(unittest.TestCase):
    def test_angle_calculation(self):
        """Testet die Berechnung der Armwinkel mit synthetischen Eingaben."""
        # Mock-Daten
        height, width = 720, 1280
        bodyMarker = mock_pose_landmarks()

        # Erwartete Ergebnisse (manuell berechnet oder erwartet)
        expected_left_angle = 360 - 26.57  # Beispielwert, je nach Vektorrechnung
        expected_right_angle = 26.57       # Beispielwert, je nach Vektorrechnung

        # Aufruf der Funktion
        result = getAngleFromVideo(bodyMarker, height, width)

        # Winkelprüfungen
        left_angle, right_angle = result['Angle']
        self.assertAlmostEqual(left_angle, expected_left_angle, delta=1.0)
        self.assertAlmostEqual(right_angle, expected_right_angle, delta=1.0)

        # Überprüfung von MarkerData
        marker_data = result['MarkerData']
        self.assertIsInstance(marker_data, MarkerData)
        self.assertTrue(np.allclose(marker_data.mid_shoulder, [640, 144]))
        self.assertTrue(np.allclose(marker_data.mid_hip, [640, 432]))

    def test_invalid_input(self):
        """Testet, ob die Funktion mit ungültigen Eingaben ordnungsgemäß umgeht."""
        # Ungültige Eingabe: None
        with self.assertRaises(AttributeError):
            getAngleFromVideo(None, 720, 1280)

        # Ungültige Eingabe: Höhe und Breite 0
        bodyMarker = mock_pose_landmarks()
        with self.assertRaises(ZeroDivisionError):
            getAngleFromVideo(bodyMarker, 0, 0)

if __name__ == "__main__":
    # Erstellen eines textbasierten Berichts
    report_output = StringIO()
    runner = unittest.TextTestRunner(stream=report_output, verbosity=2)
    test_suite = unittest.TestLoader().loadTestsFromTestCase(TestGetAngleFromVideo)
    runner.run(test_suite)

    # Speichern des Berichts in einer Datei
    with open("TestReport.txt", "w") as report_file:
        report_file.write(report_output.getvalue())

    print("Der Testbericht wurde in 'TestReport.txt' gespeichert.")