From 77f1cc923367d9ea5e77283c0399f0629a40bf4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20L=C3=A4tt?= Date: Tue, 29 Oct 2024 18:23:28 +0200 Subject: [PATCH] Fix XCResult testcase duration parsing (#433) --- CHANGELOG.md | 6 +++++ pyproject.toml | 2 +- src/codemagic/__version__.py | 2 +- src/codemagic/models/xctests/converter.py | 24 +++++++++++++++---- .../xctests/xcresult/xcode_16_xcresult.py | 2 +- .../converter/test_xcode_16_converter.py | 23 ++++++++++++++++++ 6 files changed, 52 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25948999..d91a9544 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Version 0.54.1 +------------- + +**Bugfixes** +- Fix testcase duration parsing from `XCResult` bundle when using Xcode 16.0+. [PR #433](https://github.com/codemagic-ci-cd/cli-tools/pull/433) + Version 0.54.0 ------------- diff --git a/pyproject.toml b/pyproject.toml index f9a06334..b5163937 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "codemagic-cli-tools" -version = "0.54.0" +version = "0.54.1" description = "CLI tools used in Codemagic builds" readme = "README.md" authors = [ diff --git a/src/codemagic/__version__.py b/src/codemagic/__version__.py index eeb532ca..631b097c 100644 --- a/src/codemagic/__version__.py +++ b/src/codemagic/__version__.py @@ -1,5 +1,5 @@ __title__ = "codemagic-cli-tools" __description__ = "CLI tools used in Codemagic builds" -__version__ = "0.54.0.dev" +__version__ = "0.54.1.dev" __url__ = "https://github.com/codemagic-ci-cd/cli-tools" __licence__ = "GNU General Public License v3.0" diff --git a/src/codemagic/models/xctests/converter.py b/src/codemagic/models/xctests/converter.py index 8b516afc..34f53677 100644 --- a/src/codemagic/models/xctests/converter.py +++ b/src/codemagic/models/xctests/converter.py @@ -5,6 +5,7 @@ from abc import ABC from abc import abstractmethod from datetime import datetime +from datetime import timedelta from typing import Iterator from typing import List from typing import Optional @@ -240,15 +241,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: + duration = timedelta() + + try: + for part in xc_duration.split(): + part_value = float(part[:-1].replace(",", ".")) + if part.endswith("s"): + duration += timedelta(seconds=part_value) + elif part.endswith("m"): + duration += timedelta(minutes=part_value) + else: + raise ValueError("Unknown duration unit") + except ValueError as ve: + raise ValueError("Invalid duration", xc_duration) from ve + + return duration.total_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..bf213b86 100644 --- a/tests/models/xctests/converter/test_xcode_16_converter.py +++ b/tests/models/xctests/converter/test_xcode_16_converter.py @@ -127,3 +127,26 @@ 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 3,01s", 63.01), + ("1m 3.01s", 63.01), + ("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)