| 86 | |
| 87 | @dataclasses.dataclass(slots=True) |
| 88 | class TestResult: |
| 89 | test_name: TestName |
| 90 | state: str | None = None |
| 91 | # Test duration in seconds |
| 92 | duration: float | None = None |
| 93 | xml_data: list[str] | None = None |
| 94 | stats: TestStats | None = None |
| 95 | |
| 96 | # errors and failures copied from support.TestFailedWithDetails |
| 97 | errors: list[tuple[str, str]] | None = None |
| 98 | failures: list[tuple[str, str]] | None = None |
| 99 | |
| 100 | # partial coverage in a worker run; not used by sequential in-process runs |
| 101 | covered_lines: list[Location] | None = None |
| 102 | |
| 103 | def is_failed(self, fail_env_changed: bool) -> bool: |
| 104 | if self.state == State.ENV_CHANGED: |
| 105 | return fail_env_changed |
| 106 | return State.is_failed(self.state) |
| 107 | |
| 108 | def _format_failed(self): |
| 109 | ansi = get_colors() |
| 110 | red, reset = ansi.BOLD_RED, ansi.RESET |
| 111 | if self.errors and self.failures: |
| 112 | le = len(self.errors) |
| 113 | lf = len(self.failures) |
| 114 | error_s = "error" + ("s" if le > 1 else "") |
| 115 | failure_s = "failure" + ("s" if lf > 1 else "") |
| 116 | return ( |
| 117 | f"{red}{self.test_name} failed " |
| 118 | f"({le} {error_s}, {lf} {failure_s}){reset}" |
| 119 | ) |
| 120 | |
| 121 | if self.errors: |
| 122 | le = len(self.errors) |
| 123 | error_s = "error" + ("s" if le > 1 else "") |
| 124 | return f"{red}{self.test_name} failed ({le} {error_s}){reset}" |
| 125 | |
| 126 | if self.failures: |
| 127 | lf = len(self.failures) |
| 128 | failure_s = "failure" + ("s" if lf > 1 else "") |
| 129 | return f"{red}{self.test_name} failed ({lf} {failure_s}){reset}" |
| 130 | |
| 131 | return f"{red}{self.test_name} failed{reset}" |
| 132 | |
| 133 | def __str__(self) -> str: |
| 134 | ansi = get_colors() |
| 135 | green = ansi.GREEN |
| 136 | red = ansi.BOLD_RED |
| 137 | reset = ansi.RESET |
| 138 | yellow = ansi.YELLOW |
| 139 | |
| 140 | match self.state: |
| 141 | case State.PASSED: |
| 142 | return f"{green}{self.test_name} passed{reset}" |
| 143 | case State.FAILED: |
| 144 | return f"{red}{self._format_failed()}{reset}" |
| 145 | case State.SKIPPED: |
no outgoing calls
no test coverage detected
searching dependent graphs…