183    def build_xml_doc(self, encoding=None):
  184        """
  185        Builds the XML document for the JUnit test suite.
  186        Produces clean unicode strings and decodes non-unicode with the help of encoding.
  187        @param encoding: Used to decode encoded strings.
  188        @return: XML document with unicode string elements
  189        """
  190 
  191        
  192        test_suite_attributes = dict()
  193        test_suite_attributes['name'] = self.name
  194        if any(c.assertions for c in self.test_cases):
  195            test_suite_attributes['assertions'] = \
  196                str(sum([int(c.assertions) for c in self.test_cases if c.assertions]))
  197        test_suite_attributes['disabled'] = \
  198            str(len([c for c in self.test_cases if not c.is_enabled]))
  199        test_suite_attributes['failures'] = \
  200            str(len([c for c in self.test_cases if c.is_failure()]))
  201        test_suite_attributes['errors'] = \
  202            str(len([c for c in self.test_cases if c.is_error()]))
  203        test_suite_attributes['skipped'] = \
  204            str(len([c for c in self.test_cases if c.is_skipped()]))
  205        test_suite_attributes['time'] = \
  206            str(sum(c.elapsed_sec for c in self.test_cases if c.elapsed_sec))
  207        test_suite_attributes['tests'] = str(len(self.test_cases))
  208 
  209        if self.hostname:
  210            test_suite_attributes['hostname'] = self.hostname
  211        if self.id:
  212            test_suite_attributes['id'] = self.id
  213        if self.package:
  214            test_suite_attributes['package'] = self.package
  215        if self.timestamp:
  216            test_suite_attributes['timestamp'] = self.timestamp
  217        if self.file:
  218            test_suite_attributes['file'] = self.file
  219        if self.log:
  220            test_suite_attributes['log'] = self.log
  221        if self.url:
  222            test_suite_attributes['url'] = self.url
  223 
  224        xml_element = ET.Element("testsuite", test_suite_attributes)
  225 
  226        
  227        if self.properties:
  228            props_element = ET.SubElement(xml_element, "properties")
  229            for k, v in self.properties.items():
  230                attrs = {
  231                    'name': k,
  232                    'value': v
  233                }
  234                ET.SubElement(props_element, "property", attrs)
  235 
  236        
  237        if self.stdout:
  238            stdout_element = ET.SubElement(xml_element, "system-out")
  239            stdout_element.text = self.stdout
  240 
  241        
  242        if self.stderr:
  243            stderr_element = ET.SubElement(xml_element, "system-err")
  244            stderr_element.text = self.stderr
  245 
  246        
  247        for case in self.test_cases:
  248            test_case_attributes = dict()
  249            test_case_attributes['name'] = case.name
  250            if case.assertions:
  251                
  252                test_case_attributes['assertions'] = "%d" % case.assertions
  253            if case.elapsed_sec:
  254                test_case_attributes['time'] = "%f" % case.elapsed_sec
  255            if case.timestamp:
  256                test_case_attributes['timestamp'] = case.timestamp
  257            if case.classname:
  258                test_case_attributes['classname'] = case.classname
  259            if case.status:
  260                test_case_attributes['status'] = case.status
  261            if case.category:
  262                test_case_attributes['class'] = case.category
  263            if case.file:
  264                test_case_attributes['file'] = case.file
  265            if case.line:
  266                test_case_attributes['line'] = case.line
  267            if case.log:
  268                test_case_attributes['log'] = case.log
  269            if case.url:
  270                test_case_attributes['url'] = case.url
  271 
  272            test_case_element = ET.SubElement(xml_element, "testcase",
  273                                              test_case_attributes)
  274 
  275            
  276            if case.is_failure():
  277                attrs = {'type': 'failure'}
  278                if case.failure_message:
  279                    attrs['message'] = case.failure_message
  280                if case.failure_type:
  281                    attrs['type'] = case.failure_type
  282                failure_element = ET.Element("failure", attrs)
  283                if case.failure_output:
  284                    failure_element.text = case.failure_output
  285                test_case_element.append(failure_element)
  286 
  287            
  288            if case.is_error():
  289                attrs = {'type': 'error'}
  290                if case.error_message:
  291                    attrs['message'] = case.error_message
  292                if case.error_type:
  293                    attrs['type'] = case.error_type
  294                error_element = ET.Element("error", attrs)
  295                if case.error_output:
  296                    error_element.text = case.error_output
  297                test_case_element.append(error_element)
  298 
  299            
  300            if case.is_skipped():
  301                attrs = {'type': 'skipped'}
  302                if case.skipped_message:
  303                    attrs['message'] = case.skipped_message
  304                skipped_element = ET.Element("skipped", attrs)
  305                if case.skipped_output:
  306                    skipped_element.text = case.skipped_output
  307                test_case_element.append(skipped_element)
  308 
  309            
  310            if case.stdout:
  311                stdout_element = ET.Element("system-out")
  312                stdout_element.text = case.stdout
  313                test_case_element.append(stdout_element)
  314 
  315            
  316            if case.stderr:
  317                stderr_element = ET.Element("system-err")
  318                stderr_element.text = case.stderr
  319                test_case_element.append(stderr_element)
  320 
  321        return xml_element
  322