Coverage for /home/crpier/Projects/snektest/snektest/assertions.py: 47%

105 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-07 00:30 +0300

1from types import TracebackType 

2from typing import Any, Self, TypeIs, cast 

3 

4from snektest.models import AssertionFailure, BadRequestError 

5 

6 

7def assert_raises[T]( 

8 *expected_exceptions: type[T], 

9 msg: str | None = None, 

10) -> RaisesContex[T]: 

11 return RaisesContex(*expected_exceptions, msg=msg) 

12 

13 

14class RaisesContex[T]: 

15 def __init__(self, *expected_exceptions: type[T], msg: str | None = None) -> None: 

16 self.msg = msg 

17 self.expected_exceptions = expected_exceptions 

18 self._exception: T | None = None 

19 self.has_exited = False 

20 

21 def __enter__(self) -> Self: 

22 return self 

23 

24 def __exit__( 

25 self, 

26 exc_type: type[BaseException] | None, 

27 exc_value: BaseException | None, 

28 traceback: TracebackType | None, 

29 ) -> bool: 

30 self.has_exited = True 

31 if exc_type is None: 

32 message = ( 

33 self.msg or "Expected to raise an exception but no exception was raised" 

34 ) 

35 raise AssertionFailure( 

36 message, 

37 actual=None, 

38 expected=self.expected_exceptions, 

39 ) 

40 if not isinstance(exc_value, self.expected_exceptions): 

41 expected_exceptions_display_name = " | ".join( 

42 e.__name__ for e in self.expected_exceptions 

43 ) 

44 message = ( 

45 self.msg 

46 or f"Expected to raise {expected_exceptions_display_name} but raised {type(exc_value).__name__}" 

47 ) 

48 raise AssertionFailure( 

49 message, 

50 actual=exc_value, 

51 expected=self.expected_exceptions, 

52 ) 

53 self._exception = exc_value 

54 return True 

55 

56 @property 

57 def exception(self) -> T: 

58 if not self.has_exited: 

59 msg = "Exception under assert_raises was accessed before exiting the context manager" 

60 raise BadRequestError(msg) 

61 return cast("T", self._exception) 

62 

63 

64def assert_eq(actual: Any, expected: Any, *, msg: str | None = None) -> None: 

65 """Assert that actual == expected.""" 

66 if actual != expected: 

67 message = msg or f"{actual!r} != {expected!r}" 

68 raise AssertionFailure( 

69 message, 

70 actual=actual, 

71 expected=expected, 

72 operator="==", 

73 ) 

74 

75 

76def assert_ne(actual: Any, expected: Any, *, msg: str | None = None) -> None: 

77 """Assert that actual != expected.""" 

78 if actual == expected: 

79 message = msg or f"{actual!r} == {expected!r}" 

80 raise AssertionFailure( 

81 message, 

82 actual=actual, 

83 expected=expected, 

84 operator="!=", 

85 ) 

86 

87 

88def assert_true(value: Any, *, msg: str | None = None) -> None: 

89 """Assert that value is True (identity check, not truthiness).""" 

90 if value is not True: 

91 message = msg or f"{value!r} is not True" 

92 raise AssertionFailure( 

93 message, 

94 actual=value, 

95 expected=True, 

96 operator="is", 

97 ) 

98 

99 

100def assert_false(value: Any, *, msg: str | None = None) -> None: 

101 """Assert that value is False (identity check, not falsiness).""" 

102 if value is not False: 

103 message = msg or f"{value!r} is not False" 

104 raise AssertionFailure( 

105 message, 

106 actual=value, 

107 expected=False, 

108 operator="is", 

109 ) 

110 

111 

112def assert_is_none(value: Any, *, msg: str | None = None) -> None: 

113 """Assert that value is None.""" 

114 if value is not None: 

115 message = msg or f"{value!r} is not None" 

116 raise AssertionFailure( 

117 message, 

118 actual=value, 

119 expected=None, 

120 operator="is", 

121 ) 

122 

123 

124def assert_is_not_none[T](value: T | None, *, msg: str | None = None) -> TypeIs[T]: 

125 """Assert that value is not None.""" 

126 if value is None: 

127 message = msg or "value is None" 

128 raise AssertionFailure( 

129 message, 

130 actual=value, 

131 expected="not None", 

132 operator="is not", 

133 ) 

134 return True 

135 

136 

137def assert_is(actual: Any, expected: Any, *, msg: str | None = None) -> None: 

138 """Assert that actual is expected (identity check).""" 

139 if actual is not expected: 

140 message = msg or f"{actual!r} is not {expected!r}" 

141 raise AssertionFailure( 

142 message, 

143 actual=actual, 

144 expected=expected, 

145 operator="is", 

146 ) 

147 

148 

149def assert_is_not(actual: Any, expected: Any, *, msg: str | None = None) -> None: 

150 """Assert that actual is not expected (identity check).""" 

151 if actual is expected: 

152 message = msg or f"{actual!r} is {expected!r}" 

153 raise AssertionFailure( 

154 message, 

155 actual=actual, 

156 expected=expected, 

157 operator="is not", 

158 ) 

159 

160 

161def assert_lt(actual: Any, expected: Any, *, msg: str | None = None) -> None: 

162 """Assert that actual < expected.""" 

163 if not actual < expected: 

164 message = msg or f"{actual!r} >= {expected!r}" 

165 raise AssertionFailure( 

166 message, 

167 actual=actual, 

168 expected=expected, 

169 operator="<", 

170 ) 

171 

172 

173def assert_gt(actual: Any, expected: Any, *, msg: str | None = None) -> None: 

174 """Assert that actual > expected.""" 

175 if not actual > expected: 

176 message = msg or f"{actual!r} <= {expected!r}" 

177 raise AssertionFailure( 

178 message, 

179 actual=actual, 

180 expected=expected, 

181 operator=">", 

182 ) 

183 

184 

185def assert_le(actual: Any, expected: Any, *, msg: str | None = None) -> None: 

186 """Assert that actual <= expected.""" 

187 if not actual <= expected: 

188 message = msg or f"{actual!r} > {expected!r}" 

189 raise AssertionFailure( 

190 message, 

191 actual=actual, 

192 expected=expected, 

193 operator="<=", 

194 ) 

195 

196 

197def assert_ge(actual: Any, expected: Any, *, msg: str | None = None) -> None: 

198 """Assert that actual >= expected.""" 

199 if not actual >= expected: 

200 message = msg or f"{actual!r} < {expected!r}" 

201 raise AssertionFailure( 

202 message, 

203 actual=actual, 

204 expected=expected, 

205 operator=">=", 

206 ) 

207 

208 

209def assert_in(member: Any, container: Any, *, msg: str | None = None) -> None: 

210 """Assert that member in container.""" 

211 if member not in container: 

212 message = msg or f"{member!r} not found in {container!r}" 

213 raise AssertionFailure( 

214 message, 

215 actual=member, 

216 expected=container, 

217 operator="in", 

218 ) 

219 

220 

221def assert_not_in(member: Any, container: Any, *, msg: str | None = None) -> None: 

222 """Assert that member not in container.""" 

223 if member in container: 

224 message = msg or f"{member!r} found in {container!r}" 

225 raise AssertionFailure( 

226 message, 

227 actual=member, 

228 expected=container, 

229 operator="not in", 

230 ) 

231 

232 

233def assert_isinstance( 

234 obj: Any, classinfo: type | tuple[type, ...], *, msg: str | None = None 

235) -> None: 

236 """Assert that isinstance(obj, classinfo) is True.""" 

237 if not isinstance(obj, classinfo): 

238 type_name = ( 

239 classinfo.__name__ if isinstance(classinfo, type) else str(classinfo) 

240 ) 

241 message = msg or f"{obj!r} is not an instance of {type_name}" 

242 raise AssertionFailure( 

243 message, 

244 actual=type(obj).__name__, 

245 expected=type_name, 

246 operator="isinstance", 

247 ) 

248 

249 

250def assert_not_isinstance( 

251 obj: Any, classinfo: type | tuple[type, ...], *, msg: str | None = None 

252) -> None: 

253 """Assert that isinstance(obj, classinfo) is False.""" 

254 if isinstance(obj, classinfo): 

255 type_name = ( 

256 classinfo.__name__ if isinstance(classinfo, type) else str(classinfo) 

257 ) 

258 message = msg or f"{obj!r} is an instance of {type_name}" 

259 raise AssertionFailure( 

260 message, 

261 actual=type(obj).__name__, 

262 expected=f"not {type_name}", 

263 operator="not isinstance", 

264 ) 

265 

266 

267def assert_len(obj: Any, expected_length: int, *, msg: str | None = None) -> None: 

268 """Assert that len(obj) == expected_length.""" 

269 actual_length = len(obj) 

270 if actual_length != expected_length: 

271 message = msg or f"Length {actual_length} != {expected_length}" 

272 raise AssertionFailure( 

273 message, 

274 actual=actual_length, 

275 expected=expected_length, 

276 operator="len ==", 

277 ) 

278 

279 

280def fail(msg: str | None = None) -> None: 

281 """Unconditionally raise an AssertionFailure. 

282 

283 Args: 

284 msg: Optional custom message 

285 """ 

286 message = msg or "Assertion failed" 

287 raise AssertionFailure(message)