3 # Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 # SPDX-License-Identifier: GPL-2.0-only
10 from typing
import Optional
13 class InvalidTestPlan(RuntimeError):
14 def __init__(self
, msg
: str):
18 class BailOut(RuntimeError):
19 def __init__(self
, msg
: str):
24 def __init__(self
, tap_generator
: "TapGenerator", description
: str):
25 self
._tap
_generator
= tap_generator
26 self
._result
: Optional
[bool] = None
27 self
._description
= description
30 def result(self
) -> Optional
[bool]:
34 def description(self
) -> str:
35 return self
._description
37 def _set_result(self
, result
: bool) -> None:
38 if self
._result
is not None:
39 raise RuntimeError("Can't set test case result twice")
42 self
._tap
_generator
.test(result
, self
._description
)
44 def success(self
) -> None:
45 self
._set
_result
(True)
47 def fail(self
) -> None:
48 self
._set
_result
(False)
51 # Produces a test execution report in the TAP format.
53 def __init__(self
, total_test_count
: int):
54 if total_test_count
<= 0:
55 raise ValueError("Test count must be greater than zero")
57 self
._total
_test
_count
: int = total_test_count
58 self
._last
_test
_case
_id
: int = 0
59 self
._printed
_plan
: bool = False
60 self
._has
_failure
: bool = False
63 if self
.remaining_test_cases
> 0:
65 "Missing {remaining_test_cases} test cases".format(
66 remaining_test_cases
=self
.remaining_test_cases
71 def remaining_test_cases(self
) -> int:
72 return self
._total
_test
_count
- self
._last
_test
_case
_id
74 def _print(self
, msg
: str) -> None:
75 if not self
._printed
_plan
:
77 "1..{total_test_count}".format(total_test_count
=self
._total
_test
_count
),
80 self
._printed
_plan
= True
82 print(msg
, flush
=True)
84 def skip_all(self
, reason
) -> None:
85 if self
._last
_test
_case
_id
!= 0:
86 raise RuntimeError("Can't skip all tests after running test cases")
89 self
._print
("1..0 # Skip all: {reason}".format(reason
=reason
))
91 self
._last
_test
_case
_id
= self
._total
_test
_count
93 def skip(self
, reason
, skip_count
: int = 1) -> None:
94 for i
in range(skip_count
):
95 self
._last
_test
_case
_id
= self
._last
_test
_case
_id
+ 1
97 "ok {test_number} # Skip: {reason}".format(
98 reason
=reason
, test_number
=(i
+ self
._last
_test
_case
_id
)
102 def bail_out(self
, reason
: str) -> None:
103 self
._print
("Bail out! {reason}".format(reason
=reason
))
104 self
._last
_test
_case
_id
= self
._total
_test
_count
105 raise BailOut(reason
)
107 def test(self
, result
: bool, description
: str) -> None:
108 if self
._last
_test
_case
_id
== self
._total
_test
_count
:
109 raise InvalidTestPlan("Executing too many tests")
112 self
._has
_failure
= True
114 result_string
= "ok" if result
else "not ok"
115 self
._last
_test
_case
_id
= self
._last
_test
_case
_id
+ 1
117 "{result_string} {case_id} - {description}".format(
118 result_string
=result_string
,
119 case_id
=self
._last
_test
_case
_id
,
120 description
=description
,
124 def ok(self
, description
: str) -> None:
125 self
.test(True, description
)
127 def fail(self
, description
: str) -> None:
128 self
.test(False, description
)
131 def is_successful(self
) -> bool:
133 self
._last
_test
_case
_id
== self
._total
_test
_count
and not self
._has
_failure
136 @contextlib.contextmanager
137 def case(self
, description
: str):
138 test_case
= TestCase(self
, description
)
141 except Exception as e
:
143 "Exception `{exception_type}` thrown during test case `{description}`, marking as failure.".format(
144 description
=test_case
.description
, exception_type
=type(e
).__name
__
149 self
.diagnostic(str(e
))
153 if test_case
.result
is None:
156 def diagnostic(self
, msg
) -> None:
157 print("# {msg}".format(msg
=msg
), file=sys
.stderr
, flush
=True)
This page took 0.036832 seconds and 5 git commands to generate.