1# -*- coding: utf-8 -*- 2import pytest 3from _pytest.pathlib import Path 4from _pytest.reports import CollectReport 5from _pytest.reports import TestReport 6 7 8class TestReportSerialization(object): 9 def test_xdist_longrepr_to_str_issue_241(self, testdir): 10 """ 11 Regarding issue pytest-xdist#241 12 13 This test came originally from test_remote.py in xdist (ca03269). 14 """ 15 testdir.makepyfile( 16 """ 17 def test_a(): assert False 18 def test_b(): pass 19 """ 20 ) 21 reprec = testdir.inline_run() 22 reports = reprec.getreports("pytest_runtest_logreport") 23 assert len(reports) == 6 24 test_a_call = reports[1] 25 assert test_a_call.when == "call" 26 assert test_a_call.outcome == "failed" 27 assert test_a_call._to_json()["longrepr"]["reprtraceback"]["style"] == "long" 28 test_b_call = reports[4] 29 assert test_b_call.when == "call" 30 assert test_b_call.outcome == "passed" 31 assert test_b_call._to_json()["longrepr"] is None 32 33 def test_xdist_report_longrepr_reprcrash_130(self, testdir): 34 """Regarding issue pytest-xdist#130 35 36 This test came originally from test_remote.py in xdist (ca03269). 37 """ 38 reprec = testdir.inline_runsource( 39 """ 40 def test_fail(): 41 assert False, 'Expected Message' 42 """ 43 ) 44 reports = reprec.getreports("pytest_runtest_logreport") 45 assert len(reports) == 3 46 rep = reports[1] 47 added_section = ("Failure Metadata", str("metadata metadata"), "*") 48 rep.longrepr.sections.append(added_section) 49 d = rep._to_json() 50 a = TestReport._from_json(d) 51 # Check assembled == rep 52 assert a.__dict__.keys() == rep.__dict__.keys() 53 for key in rep.__dict__.keys(): 54 if key != "longrepr": 55 assert getattr(a, key) == getattr(rep, key) 56 assert rep.longrepr.reprcrash.lineno == a.longrepr.reprcrash.lineno 57 assert rep.longrepr.reprcrash.message == a.longrepr.reprcrash.message 58 assert rep.longrepr.reprcrash.path == a.longrepr.reprcrash.path 59 assert rep.longrepr.reprtraceback.entrysep == a.longrepr.reprtraceback.entrysep 60 assert ( 61 rep.longrepr.reprtraceback.extraline == a.longrepr.reprtraceback.extraline 62 ) 63 assert rep.longrepr.reprtraceback.style == a.longrepr.reprtraceback.style 64 assert rep.longrepr.sections == a.longrepr.sections 65 # Missing section attribute PR171 66 assert added_section in a.longrepr.sections 67 68 def test_reprentries_serialization_170(self, testdir): 69 """Regarding issue pytest-xdist#170 70 71 This test came originally from test_remote.py in xdist (ca03269). 72 """ 73 from _pytest._code.code import ReprEntry 74 75 reprec = testdir.inline_runsource( 76 """ 77 def test_repr_entry(): 78 x = 0 79 assert x 80 """, 81 "--showlocals", 82 ) 83 reports = reprec.getreports("pytest_runtest_logreport") 84 assert len(reports) == 3 85 rep = reports[1] 86 d = rep._to_json() 87 a = TestReport._from_json(d) 88 89 rep_entries = rep.longrepr.reprtraceback.reprentries 90 a_entries = a.longrepr.reprtraceback.reprentries 91 for i in range(len(a_entries)): 92 assert isinstance(rep_entries[i], ReprEntry) 93 assert rep_entries[i].lines == a_entries[i].lines 94 assert rep_entries[i].reprfileloc.lineno == a_entries[i].reprfileloc.lineno 95 assert ( 96 rep_entries[i].reprfileloc.message == a_entries[i].reprfileloc.message 97 ) 98 assert rep_entries[i].reprfileloc.path == a_entries[i].reprfileloc.path 99 assert rep_entries[i].reprfuncargs.args == a_entries[i].reprfuncargs.args 100 assert rep_entries[i].reprlocals.lines == a_entries[i].reprlocals.lines 101 assert rep_entries[i].style == a_entries[i].style 102 103 def test_reprentries_serialization_196(self, testdir): 104 """Regarding issue pytest-xdist#196 105 106 This test came originally from test_remote.py in xdist (ca03269). 107 """ 108 from _pytest._code.code import ReprEntryNative 109 110 reprec = testdir.inline_runsource( 111 """ 112 def test_repr_entry_native(): 113 x = 0 114 assert x 115 """, 116 "--tb=native", 117 ) 118 reports = reprec.getreports("pytest_runtest_logreport") 119 assert len(reports) == 3 120 rep = reports[1] 121 d = rep._to_json() 122 a = TestReport._from_json(d) 123 124 rep_entries = rep.longrepr.reprtraceback.reprentries 125 a_entries = a.longrepr.reprtraceback.reprentries 126 for i in range(len(a_entries)): 127 assert isinstance(rep_entries[i], ReprEntryNative) 128 assert rep_entries[i].lines == a_entries[i].lines 129 130 def test_itemreport_outcomes(self, testdir): 131 """ 132 This test came originally from test_remote.py in xdist (ca03269). 133 """ 134 reprec = testdir.inline_runsource( 135 """ 136 import py 137 def test_pass(): pass 138 def test_fail(): 0/0 139 @py.test.mark.skipif("True") 140 def test_skip(): pass 141 def test_skip_imperative(): 142 py.test.skip("hello") 143 @py.test.mark.xfail("True") 144 def test_xfail(): 0/0 145 def test_xfail_imperative(): 146 py.test.xfail("hello") 147 """ 148 ) 149 reports = reprec.getreports("pytest_runtest_logreport") 150 assert len(reports) == 17 # with setup/teardown "passed" reports 151 for rep in reports: 152 d = rep._to_json() 153 newrep = TestReport._from_json(d) 154 assert newrep.passed == rep.passed 155 assert newrep.failed == rep.failed 156 assert newrep.skipped == rep.skipped 157 if newrep.skipped and not hasattr(newrep, "wasxfail"): 158 assert len(newrep.longrepr) == 3 159 assert newrep.outcome == rep.outcome 160 assert newrep.when == rep.when 161 assert newrep.keywords == rep.keywords 162 if rep.failed: 163 assert newrep.longreprtext == rep.longreprtext 164 165 def test_collectreport_passed(self, testdir): 166 """This test came originally from test_remote.py in xdist (ca03269).""" 167 reprec = testdir.inline_runsource("def test_func(): pass") 168 reports = reprec.getreports("pytest_collectreport") 169 for rep in reports: 170 d = rep._to_json() 171 newrep = CollectReport._from_json(d) 172 assert newrep.passed == rep.passed 173 assert newrep.failed == rep.failed 174 assert newrep.skipped == rep.skipped 175 176 def test_collectreport_fail(self, testdir): 177 """This test came originally from test_remote.py in xdist (ca03269).""" 178 reprec = testdir.inline_runsource("qwe abc") 179 reports = reprec.getreports("pytest_collectreport") 180 assert reports 181 for rep in reports: 182 d = rep._to_json() 183 newrep = CollectReport._from_json(d) 184 assert newrep.passed == rep.passed 185 assert newrep.failed == rep.failed 186 assert newrep.skipped == rep.skipped 187 if rep.failed: 188 assert newrep.longrepr == str(rep.longrepr) 189 190 def test_extended_report_deserialization(self, testdir): 191 """This test came originally from test_remote.py in xdist (ca03269).""" 192 reprec = testdir.inline_runsource("qwe abc") 193 reports = reprec.getreports("pytest_collectreport") 194 assert reports 195 for rep in reports: 196 rep.extra = True 197 d = rep._to_json() 198 newrep = CollectReport._from_json(d) 199 assert newrep.extra 200 assert newrep.passed == rep.passed 201 assert newrep.failed == rep.failed 202 assert newrep.skipped == rep.skipped 203 if rep.failed: 204 assert newrep.longrepr == str(rep.longrepr) 205 206 def test_paths_support(self, testdir): 207 """Report attributes which are py.path or pathlib objects should become strings.""" 208 testdir.makepyfile( 209 """ 210 def test_a(): 211 assert False 212 """ 213 ) 214 reprec = testdir.inline_run() 215 reports = reprec.getreports("pytest_runtest_logreport") 216 assert len(reports) == 3 217 test_a_call = reports[1] 218 test_a_call.path1 = testdir.tmpdir 219 test_a_call.path2 = Path(testdir.tmpdir) 220 data = test_a_call._to_json() 221 assert data["path1"] == str(testdir.tmpdir) 222 assert data["path2"] == str(testdir.tmpdir) 223 224 def test_unserialization_failure(self, testdir): 225 """Check handling of failure during unserialization of report types.""" 226 testdir.makepyfile( 227 """ 228 def test_a(): 229 assert False 230 """ 231 ) 232 reprec = testdir.inline_run() 233 reports = reprec.getreports("pytest_runtest_logreport") 234 assert len(reports) == 3 235 test_a_call = reports[1] 236 data = test_a_call._to_json() 237 entry = data["longrepr"]["reprtraceback"]["reprentries"][0] 238 assert entry["type"] == "ReprEntry" 239 240 entry["type"] = "Unknown" 241 with pytest.raises( 242 RuntimeError, match="INTERNALERROR: Unknown entry type returned: Unknown" 243 ): 244 TestReport._from_json(data) 245 246 247class TestHooks: 248 """Test that the hooks are working correctly for plugins""" 249 250 def test_test_report(self, testdir, pytestconfig): 251 testdir.makepyfile( 252 """ 253 def test_a(): assert False 254 def test_b(): pass 255 """ 256 ) 257 reprec = testdir.inline_run() 258 reports = reprec.getreports("pytest_runtest_logreport") 259 assert len(reports) == 6 260 for rep in reports: 261 data = pytestconfig.hook.pytest_report_to_serializable( 262 config=pytestconfig, report=rep 263 ) 264 assert data["_report_type"] == "TestReport" 265 new_rep = pytestconfig.hook.pytest_report_from_serializable( 266 config=pytestconfig, data=data 267 ) 268 assert new_rep.nodeid == rep.nodeid 269 assert new_rep.when == rep.when 270 assert new_rep.outcome == rep.outcome 271 272 def test_collect_report(self, testdir, pytestconfig): 273 testdir.makepyfile( 274 """ 275 def test_a(): assert False 276 def test_b(): pass 277 """ 278 ) 279 reprec = testdir.inline_run() 280 reports = reprec.getreports("pytest_collectreport") 281 assert len(reports) == 2 282 for rep in reports: 283 data = pytestconfig.hook.pytest_report_to_serializable( 284 config=pytestconfig, report=rep 285 ) 286 assert data["_report_type"] == "CollectReport" 287 new_rep = pytestconfig.hook.pytest_report_from_serializable( 288 config=pytestconfig, data=data 289 ) 290 assert new_rep.nodeid == rep.nodeid 291 assert new_rep.when == "collect" 292 assert new_rep.outcome == rep.outcome 293 294 @pytest.mark.parametrize( 295 "hook_name", ["pytest_runtest_logreport", "pytest_collectreport"] 296 ) 297 def test_invalid_report_types(self, testdir, pytestconfig, hook_name): 298 testdir.makepyfile( 299 """ 300 def test_a(): pass 301 """ 302 ) 303 reprec = testdir.inline_run() 304 reports = reprec.getreports(hook_name) 305 assert reports 306 rep = reports[0] 307 data = pytestconfig.hook.pytest_report_to_serializable( 308 config=pytestconfig, report=rep 309 ) 310 data["_report_type"] = "Unknown" 311 with pytest.raises(AssertionError): 312 _ = pytestconfig.hook.pytest_report_from_serializable( 313 config=pytestconfig, data=data 314 ) 315