From 919be7467a6372f4cba97811a6f75bb20fe80a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20L=C3=A4tt?= Date: Tue, 29 Oct 2024 17:10:38 +0200 Subject: [PATCH] Fix duration TestNode duration parsing --- src/codemagic/models/xctests/converter.py | 25 ++++++++++++++++--- .../xctests/xcresult/xcode_16_xcresult.py | 2 +- .../converter/test_xcode_16_converter.py | 21 ++++++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/codemagic/models/xctests/converter.py b/src/codemagic/models/xctests/converter.py index 8b516afc..cb7cb677 100644 --- a/src/codemagic/models/xctests/converter.py +++ b/src/codemagic/models/xctests/converter.py @@ -4,7 +4,9 @@ import re from abc import ABC from abc import abstractmethod +from collections import defaultdict from datetime import datetime +from typing import Dict from typing import Iterator from typing import List from typing import Optional @@ -240,15 +242,30 @@ def _get_test_case_skipped(cls, xc_test_case: XcTestNode) -> Optional[Skipped]: return Skipped(message="\n".join(skipped_messages)) + @classmethod + def parse_xcresult_test_node_duration_value(cls, xc_duration: str) -> float: + counters: Dict[str, float] = defaultdict(float) + + try: + for part in xc_duration.split(): + if part.endswith("s"): + counter = "seconds" + elif part.endswith("m"): + counter = "minutes" + else: + raise ValueError("Unknown duration unit") + counters[counter] = float(part[:-1].replace(",", ".")) + except ValueError as ve: + raise ValueError("Invalid duration", xc_duration) from ve + + return counters["minutes"] * 60.0 + counters["seconds"] + @classmethod def _get_test_node_duration(cls, xc_test_case: XcTestNode) -> float: if not xc_test_case.duration: return 0.0 - duration = xc_test_case.duration.replace(",", ".") - if duration.endswith("s"): - duration = duration[:-1] - return float(duration) + return cls.parse_xcresult_test_node_duration_value(xc_test_case.duration) @classmethod def _get_test_case(cls, xc_test_case: XcTestNode, xc_test_suite: XcTestNode) -> TestCase: diff --git a/src/codemagic/models/xctests/xcresult/xcode_16_xcresult.py b/src/codemagic/models/xctests/xcresult/xcode_16_xcresult.py index efafd710..fac5724d 100644 --- a/src/codemagic/models/xctests/xcresult/xcode_16_xcresult.py +++ b/src/codemagic/models/xctests/xcresult/xcode_16_xcresult.py @@ -164,7 +164,7 @@ def from_dict(cls, d: Dict[str, Any]) -> XcTestInsight: class XcTests(XcModel): """ Model definitions for `xcresulttool get test-results tests` output. - Check schema with `xcrun xcresulttool help get test-results tests. + Check schema with `xcrun xcresulttool help get test-results tests`. """ devices: List[XcDevice] diff --git a/tests/models/xctests/converter/test_xcode_16_converter.py b/tests/models/xctests/converter/test_xcode_16_converter.py index 1976bdb2..ea4c8422 100644 --- a/tests/models/xctests/converter/test_xcode_16_converter.py +++ b/tests/models/xctests/converter/test_xcode_16_converter.py @@ -127,3 +127,24 @@ def test_converter(mock_datetime, expected_properties): time=3.0, error=Error(message="banaanUITests.swift:40: failed - Bad UI", type="Failure"), ) + + +@pytest.mark.parametrize( + ("duration", "expected_value"), + ( + ("0,00045s", 0.00045), + ("0,002s", 0.002), + ("0,0052s", 0.0052), + ("0,26s", 0.26), + ("0,2s", 0.2), + ("2s", 2.0), + ("3s", 3.0), + ("1m 4s", 64.0), + ("2m 26s", 146.0), + ("5m 3s", 303.0), + ("6m", 360.0), + ), +) +def test_parse_xcresult_test_node_duration_value(duration, expected_value): + value = Xcode16XcResultConverter.parse_xcresult_test_node_duration_value(duration) + assert value == pytest.approx(expected_value)