Coverage for tests/test_diagnostics.py: 22%

92 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-01-13 10:31 +0000

1# This file is part of daf_relation. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21 

22from __future__ import annotations 

23 

24import unittest 

25from collections.abc import Set 

26from typing import Any 

27 

28from lsst.daf.relation import ( 

29 ColumnTag, 

30 Diagnostics, 

31 GenericConcreteEngine, 

32 LeafRelation, 

33 Predicate, 

34 Relation, 

35 tests, 

36) 

37 

38 

39class EmptyLookupEngine(GenericConcreteEngine[str]): 

40 """A toy Engine for testing Diagnostics.""" 

41 

42 def __init__(self) -> None: 

43 self.empty: set[Relation] = set() 

44 

45 def get_join_identity_payload(self) -> str: 

46 return "I" 

47 

48 def get_doomed_payload(self, columns: Set[ColumnTag]) -> str: 

49 return "0" 

50 

51 def make_leaf(self, name: str, *columns: ColumnTag, **kwargs: Any) -> Relation: 

52 return LeafRelation(self, frozenset(columns), name=name, payload=name, **kwargs) 

53 

54 def is_relation_nonempty(self, relation: Relation) -> bool: 

55 return relation not in self.empty and relation.max_rows != 0 

56 

57 

58class DiagnosticsTestCase(tests.RelationTestCase): 

59 """Tests for the Diagnostics class.""" 

60 

61 def setUp(self) -> None: 

62 self.maxDiff = None 

63 

64 def test_static_leaf(self) -> None: 

65 """Test Diagnostics on LeafRelations with max_rows=0 and 

66 empty-invariant operations acting on them. 

67 """ 

68 engine = EmptyLookupEngine() 

69 leaf = engine.make_leaf("leaf", max_rows=0) 

70 self.assertEqual( 

71 Diagnostics.run(leaf), 

72 Diagnostics( 

73 is_doomed=True, 

74 messages=["Relation 'leaf' has no rows (static)."], 

75 ), 

76 ) 

77 self.assertEqual( 

78 Diagnostics.run(leaf, engine.is_relation_nonempty), 

79 Diagnostics( 

80 is_doomed=True, 

81 messages=["Relation 'leaf' has no rows (static)."], 

82 ), 

83 ) 

84 self.assertEqual( 

85 Diagnostics.run(leaf.without_duplicates(), engine.is_relation_nonempty), 

86 Diagnostics( 

87 is_doomed=True, 

88 messages=["Relation 'leaf' has no rows (static)."], 

89 ), 

90 ) 

91 

92 def test_executed_leaf(self) -> None: 

93 """Test Diagnostics on LeafRelations with max_rows != 0 and 

94 empty-invariant operations acting on them.""" 

95 engine = EmptyLookupEngine() 

96 leaf = engine.make_leaf("leaf") 

97 self.assertEqual( 

98 Diagnostics.run(leaf), 

99 Diagnostics( 

100 is_doomed=False, 

101 messages=[], 

102 ), 

103 ) 

104 self.assertEqual( 

105 Diagnostics.run(leaf.without_duplicates()), 

106 Diagnostics( 

107 is_doomed=False, 

108 messages=[], 

109 ), 

110 ) 

111 engine.empty.add(leaf) 

112 self.assertEqual( 

113 Diagnostics.run(leaf, engine.is_relation_nonempty), 

114 Diagnostics( 

115 is_doomed=True, 

116 messages=["Relation 'leaf' has no rows (executed)."], 

117 ), 

118 ) 

119 self.assertEqual( 

120 Diagnostics.run(leaf.without_duplicates(), engine.is_relation_nonempty), 

121 Diagnostics( 

122 is_doomed=True, 

123 messages=["Relation 'leaf' has no rows (executed)."], 

124 ), 

125 ) 

126 

127 def test_slice(self) -> None: 

128 """Test Diagnostics on Slice operations.""" 

129 engine = EmptyLookupEngine() 

130 leaf = engine.make_leaf("leaf") 

131 self.assertEqual( 

132 Diagnostics.run(leaf[2:2]), 

133 Diagnostics( 

134 is_doomed=True, 

135 messages=["Slice with limit=0 applied to 'leaf'"], 

136 ), 

137 ) 

138 sliced = leaf[1:3] 

139 self.assertEqual( 

140 Diagnostics.run(sliced), 

141 Diagnostics( 

142 is_doomed=False, 

143 messages=[], 

144 ), 

145 ) 

146 engine.empty.add(sliced) 

147 self.assertEqual( 

148 Diagnostics.run(sliced, engine.is_relation_nonempty), 

149 Diagnostics( 

150 is_doomed=True, 

151 messages=["Operation slice[1:3] yields no results when applied to 'leaf'"], 

152 ), 

153 ) 

154 

155 def test_selection(self) -> None: 

156 """Test Diagnostics on Selection operations.""" 

157 engine = EmptyLookupEngine() 

158 a = tests.ColumnTag("a") 

159 leaf = engine.make_leaf("leaf", a) 

160 self.assertEqual( 

161 Diagnostics.run(leaf.with_rows_satisfying(Predicate.literal(False))), 

162 Diagnostics( 

163 is_doomed=True, 

164 messages=["Predicate 'False' is trivially false (applied to 'leaf')"], 

165 ), 

166 ) 

167 selected = leaf.with_rows_satisfying(Predicate.reference(a)) 

168 self.assertEqual( 

169 Diagnostics.run(selected), 

170 Diagnostics( 

171 is_doomed=False, 

172 messages=[], 

173 ), 

174 ) 

175 engine.empty.add(selected) 

176 self.assertEqual( 

177 Diagnostics.run(selected, engine.is_relation_nonempty), 

178 Diagnostics( 

179 is_doomed=True, 

180 messages=["Operation σ[a] yields no results when applied to 'leaf'"], 

181 ), 

182 ) 

183 

184 def test_chain(self) -> None: 

185 """Test Diagnostics on Chain operations.""" 

186 engine = EmptyLookupEngine() 

187 a = tests.ColumnTag("a") 

188 leaf1 = engine.make_leaf("leaf1", a) 

189 leaf2 = engine.make_leaf("leaf2", a) 

190 leaf3 = engine.make_leaf("leaf3", a, max_rows=0) 

191 leaf4 = engine.make_leaf("leaf4", a, max_rows=0) 

192 self.assertEqual( 

193 Diagnostics.run(leaf1.chain(leaf2)), 

194 Diagnostics( 

195 is_doomed=False, 

196 messages=[], 

197 ), 

198 ) 

199 self.assertEqual( 

200 Diagnostics.run(leaf1.chain(leaf3)), 

201 Diagnostics( 

202 is_doomed=False, 

203 messages=["Relation 'leaf3' has no rows (static)."], 

204 ), 

205 ) 

206 self.assertEqual( 

207 Diagnostics.run(leaf3.chain(leaf1)), 

208 Diagnostics( 

209 is_doomed=False, 

210 messages=["Relation 'leaf3' has no rows (static)."], 

211 ), 

212 ) 

213 self.assertEqual( 

214 Diagnostics.run(leaf3.chain(leaf4)), 

215 Diagnostics( 

216 is_doomed=True, 

217 messages=[ 

218 "Relation 'leaf3' has no rows (static).", 

219 "Relation 'leaf4' has no rows (static).", 

220 ], 

221 ), 

222 ) 

223 engine.empty.add(leaf1) 

224 self.assertEqual( 

225 Diagnostics.run(leaf1.chain(leaf2), engine.is_relation_nonempty), 

226 Diagnostics( 

227 is_doomed=False, 

228 messages=["Relation 'leaf1' has no rows (executed)."], 

229 ), 

230 ) 

231 self.assertEqual( 

232 Diagnostics.run(leaf1.chain(leaf3), engine.is_relation_nonempty), 

233 Diagnostics( 

234 is_doomed=True, 

235 messages=[ 

236 "Relation 'leaf1' has no rows (executed).", 

237 "Relation 'leaf3' has no rows (static).", 

238 ], 

239 ), 

240 ) 

241 self.assertEqual( 

242 Diagnostics.run(leaf3.chain(leaf1), engine.is_relation_nonempty), 

243 Diagnostics( 

244 is_doomed=True, 

245 messages=[ 

246 "Relation 'leaf3' has no rows (static).", 

247 "Relation 'leaf1' has no rows (executed).", 

248 ], 

249 ), 

250 ) 

251 engine.empty.add(leaf2) 

252 self.assertEqual( 

253 Diagnostics.run(leaf1.chain(leaf2), engine.is_relation_nonempty), 

254 Diagnostics( 

255 is_doomed=True, 

256 messages=[ 

257 "Relation 'leaf1' has no rows (executed).", 

258 "Relation 'leaf2' has no rows (executed).", 

259 ], 

260 ), 

261 ) 

262 

263 def test_join(self) -> None: 

264 """Test Diagnostics on Join operations.""" 

265 engine = EmptyLookupEngine() 

266 a = tests.ColumnTag("a") 

267 b = tests.ColumnTag("b") 

268 c = tests.ColumnTag("c") 

269 leaf1 = engine.make_leaf("leaf1", a, b) 

270 leaf2 = engine.make_leaf("leaf2", a, c) 

271 leaf3 = engine.make_leaf("leaf3", a, b, max_rows=0) 

272 leaf4 = engine.make_leaf("leaf4", a, c, max_rows=0) 

273 self.assertEqual( 

274 Diagnostics.run(leaf1.join(leaf2)), 

275 Diagnostics( 

276 is_doomed=False, 

277 messages=[], 

278 ), 

279 ) 

280 self.assertEqual( 

281 Diagnostics.run(leaf1.join(leaf4)), 

282 Diagnostics( 

283 is_doomed=True, 

284 messages=["Relation 'leaf4' has no rows (static)."], 

285 ), 

286 ) 

287 self.assertEqual( 

288 Diagnostics.run(leaf3.join(leaf2)), 

289 Diagnostics( 

290 is_doomed=True, 

291 messages=["Relation 'leaf3' has no rows (static)."], 

292 ), 

293 ) 

294 self.assertEqual( 

295 Diagnostics.run(leaf3.join(leaf4)), 

296 Diagnostics( 

297 is_doomed=True, 

298 messages=[ 

299 "Relation 'leaf3' has no rows (static).", 

300 "Relation 'leaf4' has no rows (static).", 

301 ], 

302 ), 

303 ) 

304 

305 engine.empty.add(leaf1) 

306 self.assertEqual( 

307 Diagnostics.run(leaf1.join(leaf2), engine.is_relation_nonempty), 

308 Diagnostics( 

309 is_doomed=True, 

310 messages=["Relation 'leaf1' has no rows (executed)."], 

311 ), 

312 ) 

313 self.assertEqual( 

314 Diagnostics.run(leaf1.join(leaf4), engine.is_relation_nonempty), 

315 Diagnostics( 

316 is_doomed=True, 

317 messages=[ 

318 "Relation 'leaf1' has no rows (executed).", 

319 "Relation 'leaf4' has no rows (static).", 

320 ], 

321 ), 

322 ) 

323 engine.empty.add(leaf2) 

324 self.assertEqual( 

325 Diagnostics.run(leaf1.join(leaf2), engine.is_relation_nonempty), 

326 Diagnostics( 

327 is_doomed=True, 

328 messages=[ 

329 "Relation 'leaf1' has no rows (executed).", 

330 "Relation 'leaf2' has no rows (executed).", 

331 ], 

332 ), 

333 ) 

334 engine.empty.clear() 

335 self.assertEqual( 

336 Diagnostics.run(leaf1.join(leaf2, Predicate.literal(False))), 

337 Diagnostics( 

338 is_doomed=True, 

339 messages=["Join predicate 'False' is trivially false in 'leaf1 ⋈ leaf2'."], 

340 ), 

341 ) 

342 joined = leaf1.join(leaf2) 

343 engine.empty.add(joined) 

344 self.assertEqual( 

345 Diagnostics.run(joined, engine.is_relation_nonempty), 

346 Diagnostics( 

347 is_doomed=True, 

348 messages=["Operation ⋈ yields no results when executed: 'leaf1 ⋈ leaf2'"], 

349 ), 

350 ) 

351 

352 

353if __name__ == "__main__": 353 ↛ 354line 353 didn't jump to line 354, because the condition on line 353 was never true

354 unittest.main()