@@ -69,12 +69,37 @@ def repl(matchobj):
69
69
return py .xml .raw (illegal_xml_re .sub (repl , py .xml .escape (arg )))
70
70
71
71
72
+ def merge_family (left , right ):
73
+ result = {}
74
+ for kl , vl in left .items ():
75
+ for kr , vr in right .items ():
76
+ if not isinstance (vl , list ):
77
+ raise NotImplementedError (type (vl ))
78
+ result [kl ] = vl + vr
79
+ left .update (result )
80
+
81
+
82
+ families = {}
83
+ families ["_base" ] = {"testcase" : ["classname" , "name" ]}
84
+ families ["_base_old" ] = {"testcase" : ["file" , "line" , "url" ]}
85
+
86
+ # xUnit 1.x inherits old attributes
87
+ families ["xunit1" ] = families ["_base" ].copy ()
88
+ merge_family (families ["xunit1" ], families ["_base_old" ])
89
+
90
+ # Alias "old" to xUnit 1.x
91
+ families ["old" ] = families ["xunit1" ]
92
+
93
+ # xUnit 2.x uses strict base attributes
94
+ families ["xunit2" ] = families ["_base" ]
95
+
96
+
72
97
class _NodeReporter (object ):
73
98
def __init__ (self , nodeid , xml ):
74
-
75
99
self .id = nodeid
76
100
self .xml = xml
77
101
self .add_stats = self .xml .add_stats
102
+ self .family = self .xml .family
78
103
self .duration = 0
79
104
self .properties = []
80
105
self .nodes = []
@@ -110,12 +135,31 @@ def record_testreport(self, testreport):
110
135
classnames = names [:- 1 ]
111
136
if self .xml .prefix :
112
137
classnames .insert (0 , self .xml .prefix )
113
- attrs = {"classname" : "." .join (classnames ), "name" : bin_xml_escape (names [- 1 ])}
138
+ attrs = {
139
+ "classname" : "." .join (classnames ),
140
+ "name" : bin_xml_escape (names [- 1 ]),
141
+ "file" : testreport .location [0 ],
142
+ }
143
+ if testreport .location [1 ] is not None :
144
+ attrs ["line" ] = testreport .location [1 ]
114
145
if hasattr (testreport , "url" ):
115
146
attrs ["url" ] = testreport .url
116
147
self .attrs = attrs
117
148
self .attrs .update (existing_attrs ) # restore any user-defined attributes
118
149
150
+ # Preserve old testcase behavior
151
+ if self .family == "old" :
152
+ return
153
+
154
+ # Purge attributes not permitted by this test family
155
+ # This includes custom attributes, because they are not valid here.
156
+ # TODO: Convert invalid attributes to properties to preserve "something"
157
+ temp_attrs = {}
158
+ for key in self .attrs .keys ():
159
+ if key in families [self .family ]["testcase" ]:
160
+ temp_attrs [key ] = self .attrs [key ]
161
+ self .attrs = temp_attrs
162
+
119
163
def to_xml (self ):
120
164
testcase = Junit .testcase (time = "%.3f" % self .duration , ** self .attrs )
121
165
testcase .append (self .make_properties_node ())
@@ -234,7 +278,7 @@ def append_skipped(self, report):
234
278
def finalize (self ):
235
279
data = self .to_xml ().unicode (indent = 0 )
236
280
self .__dict__ .clear ()
237
- self .to_xml = lambda : py .xml .raw (data )
281
+ self .raw = lambda : py .xml .raw (data )
238
282
239
283
240
284
@pytest .fixture
@@ -356,19 +400,15 @@ def mangle_test_address(address):
356
400
357
401
class LogXML (object ):
358
402
def __init__ (
359
- self ,
360
- logfile ,
361
- prefix ,
362
- suite_name = "pytest" ,
363
- logging = "no" ,
364
- report_duration = "total" ,
403
+ self , logfile , prefix , suite_name = "pytest" , logging = "no" , report_duration = "total" , family = "old"
365
404
):
366
405
logfile = os .path .expanduser (os .path .expandvars (logfile ))
367
406
self .logfile = os .path .normpath (os .path .abspath (logfile ))
368
407
self .prefix = prefix
369
408
self .suite_name = suite_name
370
409
self .logging = logging
371
410
self .report_duration = report_duration
411
+ self .family = family
372
412
self .stats = dict .fromkeys (["error" , "passed" , "failure" , "skipped" ], 0 )
373
413
self .node_reporters = {} # nodeid -> _NodeReporter
374
414
self .node_reporters_ordered = []
@@ -542,7 +582,7 @@ def pytest_sessionfinish(self):
542
582
logfile .write (
543
583
Junit .testsuite (
544
584
self ._get_global_properties_node (),
545
- [x .to_xml () for x in self .node_reporters_ordered ],
585
+ [x .raw () for x in self .node_reporters_ordered ],
546
586
name = self .suite_name ,
547
587
errors = self .stats ["error" ],
548
588
failures = self .stats ["failure" ],
@@ -553,6 +593,10 @@ def pytest_sessionfinish(self):
553
593
)
554
594
logfile .close ()
555
595
596
+ # TODO: GET RID OF
597
+ with open (self .logfile ) as logfile :
598
+ print (logfile .read ())
599
+
556
600
def pytest_terminal_summary (self , terminalreporter ):
557
601
terminalreporter .write_sep ("-" , "generated xml file: %s" % (self .logfile ))
558
602
0 commit comments