3 # Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 # SPDX-License-Identifier: GPL-2.0-only
10 from typing
import Iterator
, Optional
13 class InvalidTestPlan(RuntimeError):
14 def __init__(self
, msg
):
19 class BailOut(RuntimeError):
20 def __init__(self
, msg
):
28 tap_generator
, # type: "TapGenerator"
29 description
, # type: str
31 self
._tap
_generator
= tap_generator
# type: "TapGenerator"
32 self
._result
= None # type: Optional[bool]
33 self
._description
= description
# type: str
37 # type: () -> Optional[bool]
41 def description(self
):
43 return self
._description
45 def _set_result(self
, result
):
46 # type: (bool) -> None
47 if self
._result
is not None:
48 raise RuntimeError("Can't set test case result twice")
51 self
._tap
_generator
.test(result
, self
._description
)
55 self
._set
_result
(True)
59 self
._set
_result
(False)
62 # Produces a test execution report in the TAP format.
64 def __init__(self
, total_test_count
):
66 if total_test_count
<= 0:
67 raise ValueError("Test count must be greater than zero")
69 self
._total
_test
_count
= total_test_count
# type: int
70 self
._last
_test
_case
_id
= 0 # type: int
71 self
._printed
_plan
= False # type: bool
72 self
._has
_failure
= False # type: bool
75 if self
.remaining_test_cases
> 0:
77 "Missing {remaining_test_cases} test cases".format(
78 remaining_test_cases
=self
.remaining_test_cases
83 def remaining_test_cases(self
):
85 return self
._total
_test
_count
- self
._last
_test
_case
_id
87 def _print(self
, msg
):
89 if not self
._printed
_plan
:
91 "1..{total_test_count}".format(total_test_count
=self
._total
_test
_count
),
94 self
._printed
_plan
= True
96 print(msg
, flush
=True)
98 def skip_all(self
, reason
):
100 if self
._last
_test
_case
_id
!= 0:
101 raise RuntimeError("Can't skip all tests after running test cases")
104 self
._print
("1..0 # Skip all: {reason}".format(reason
=reason
))
106 self
._last
_test
_case
_id
= self
._total
_test
_count
108 def skip(self
, reason
, skip_count
=1):
109 # type: (str, int) -> None
110 for i
in range(skip_count
):
111 self
._last
_test
_case
_id
= self
._last
_test
_case
_id
+ 1
113 "ok {test_number} # Skip: {reason}".format(
114 reason
=reason
, test_number
=(i
+ self
._last
_test
_case
_id
)
118 def bail_out(self
, reason
):
119 # type: (str) -> None
120 self
._print
("Bail out! {reason}".format(reason
=reason
))
121 self
._last
_test
_case
_id
= self
._total
_test
_count
122 raise BailOut(reason
)
124 def test(self
, result
, description
):
125 # type: (bool, str) -> None
126 if self
._last
_test
_case
_id
== self
._total
_test
_count
:
127 raise InvalidTestPlan("Executing too many tests")
130 self
._has
_failure
= True
132 result_string
= "ok" if result
else "not ok"
133 self
._last
_test
_case
_id
= self
._last
_test
_case
_id
+ 1
135 "{result_string} {case_id} - {description}".format(
136 result_string
=result_string
,
137 case_id
=self
._last
_test
_case
_id
,
138 description
=description
,
142 def ok(self
, description
):
143 # type: (str) -> None
144 self
.test(True, description
)
146 def fail(self
, description
):
147 # type: (str) -> None
148 self
.test(False, description
)
151 def is_successful(self
):
154 self
._last
_test
_case
_id
== self
._total
_test
_count
and not self
._has
_failure
157 @contextlib.contextmanager
158 def case(self
, description
):
159 # type: (str) -> Iterator[TestCase]
160 test_case
= TestCase(self
, description
)
163 except Exception as e
:
165 "Exception `{exception_type}` thrown during test case `{description}`, marking as failure.".format(
166 description
=test_case
.description
, exception_type
=type(e
).__name
__
171 self
.diagnostic(str(e
))
175 if test_case
.result
is None:
178 def diagnostic(self
, msg
):
179 # type: (str) -> None
180 print("# {msg}".format(msg
=msg
), file=sys
.stderr
, flush
=True)
This page took 0.034794 seconds and 4 git commands to generate.