def testwrapper(): """Run test and collect XML output""" total[0] += 1 start = time.time() refout, postout, diff = test() testtime = time.time() - start classname = path.decode(locale.getpreferredencoding(), 'replace') name = os.path.basename(classname) if postout is None: skipped[0] += 1 testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f">\n' ' <skipped/>\n' ' </testcase>\n') % { 'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime }) elif diff: failed[0] += 1 diff = list(diff) diffu = u('').join( l.decode(locale.getpreferredencoding(), 'replace') for l in diff) testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f">\n' ' <failure>%(diff)s</failure>\n' ' </testcase>\n') % { 'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime, 'diff': _cdata(diffu) }) else: testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f"/>\n') % { 'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime }) testcases.append(testcase) return refout, postout, diff
def testwrapper(): """Run test and collect XML output""" total[0] += 1 start = time.time() refout, postout, diff = test() testtime = time.time() - start classname = path.decode(locale.getpreferredencoding(), 'replace') name = os.path.basename(classname) if postout is None: skipped[0] += 1 testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f">\n' ' <skipped/>\n' ' </testcase>\n') % {'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime}) elif diff: failed[0] += 1 diff = list(diff) diffu = u('').join(l.decode(locale.getpreferredencoding(), 'replace') for l in diff) testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f">\n' ' <failure>%(diff)s</failure>\n' ' </testcase>\n') % {'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime, 'diff': _cdata(diffu)}) else: testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f"/>\n') % {'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime}) testcases.append(testcase) return refout, postout, diff
def _quoteattr(s): r"""Escape a string for use as an XML attribute value. >>> from cram._encoding import ul >>> (_quoteattr('1<\'2\'>&"3\x00]]>\t\r\n') == ... ul(r"'\"1<\'2\'>&"3\ufffd]]>	 \"'")) True """ return u('"%s"') % _quoteattrsub(_quoteattrreplace, s)
def _cdata(s): r"""Escape a string as an XML CDATA block. >>> from cram._encoding import ul >>> (_cdata('1<\'2\'>&"3\x00]]>\t\r\n') == ... ul(r"'<![CDATA[1<\'2\'>&\"3\ufffd]]>]]><![CDATA[\t\r\n]]>'")) True """ return u('<![CDATA[%s]]>') % _cdatasub(_cdatareplace, s)
def _timestamp(): """Return the current time in ISO 8601 format""" tm = time.localtime() if tm.tm_isdst == 1: tz = time.altzone else: tz = time.timezone timestamp = time.strftime('%Y-%m-%dT%H:%M:%S', tm) tzhours = int(-tz / 60 / 60) tzmins = int(abs(tz) / 60 % 60) timestamp += u('%+03d:%02d') % (tzhours, tzmins) return timestamp
def _timestamp(): """Return the current time in ISO 8601 format""" tm = time.localtime() if tm.tm_isdst == 1: # pragma: nocover tz = time.altzone else: # pragma: nocover tz = time.timezone timestamp = time.strftime('%Y-%m-%dT%H:%M:%S', tm) tzhours = int(-tz / 60 / 60) tzmins = int(abs(tz) / 60 % 60) timestamp += u('%+03d:%02d') % (tzhours, tzmins) return timestamp
def runxunit(tests, xmlpath): """Run tests with xUnit XML output. tests should be a sequence of 3-tuples containing the following: (test path, absolute test path, test function) This function yields a new sequence where each test function is wrapped with a function that writes test results to an xUnit XML file. """ suitestart = time.time() timestamp = _timestamp() hostname = socket.gethostname() total, skipped, failed = [0], [0], [0] testcases = [] for path, abspath, test in tests: def testwrapper(): """Run test and collect XML output""" total[0] += 1 start = time.time() refout, postout, diff = test() testtime = time.time() - start classname = path.decode(locale.getpreferredencoding(), 'replace') name = os.path.basename(classname) if postout is None: skipped[0] += 1 testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f">\n' ' <skipped/>\n' ' </testcase>\n') % {'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime}) elif diff: failed[0] += 1 diff = list(diff) diffu = u('').join(l.decode(locale.getpreferredencoding(), 'replace') for l in diff) testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f">\n' ' <failure>%(diff)s</failure>\n' ' </testcase>\n') % {'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime, 'diff': _cdata(diffu)}) else: testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f"/>\n') % {'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime}) testcases.append(testcase) return refout, postout, diff yield path, abspath, testwrapper suitetime = time.time() - suitestart header = (u('<?xml version="1.0" encoding="utf-8"?>\n' '<testsuite name="cram"\n' ' tests="%(total)d"\n' ' failures="%(failed)d"\n' ' skipped="%(skipped)d"\n' ' timestamp=%(timestamp)s\n' ' hostname=%(hostname)s\n' ' time="%(time).6f">\n') % {'total': total[0], 'failed': failed[0], 'skipped': skipped[0], 'timestamp': _quoteattr(timestamp), 'hostname': _quoteattr(hostname), 'time': suitetime}) footer = u('</testsuite>\n') xmlfile = open(xmlpath, 'wb') try: xmlfile.write(header.encode('utf-8')) for testcase in testcases: xmlfile.write(testcase.encode('utf-8')) xmlfile.write(footer.encode('utf-8')) finally: xmlfile.close()
def _quoteattrreplace(m): """Replace _quoteattrsub() regex match""" return {u('\t'): u('	'), u('\n'): u(' '), u('\r'): u(' '), u('"'): u('"'), u('&'): u('&'), u('<'): u('<'), u('>'): u('>')}.get(m.group(0), _replacementchar)
def _cdatareplace(m): """Replace _cdatasub() regex match""" if m.group(0) == u(']]>'): return u(']]>]]><![CDATA[') else: return _replacementchar
def runxunit(tests, xmlpath): """Run tests with xUnit XML output. tests should be a sequence of 2-tuples containing the following: (test path, test function) This function yields a new sequence where each test function is wrapped with a function that writes test results to an xUnit XML file. """ suitestart = time.time() timestamp = _timestamp() hostname = socket.gethostname() total, skipped, failed = [0], [0], [0] testcases = [] for path, test in tests: def testwrapper(): """Run test and collect XML output""" total[0] += 1 start = time.time() refout, postout, diff = test() testtime = time.time() - start classname = path.decode(locale.getpreferredencoding(), 'replace') name = os.path.basename(classname) if postout is None: skipped[0] += 1 testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f">\n' ' <skipped/>\n' ' </testcase>\n') % { 'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime }) elif diff: failed[0] += 1 diff = list(diff) diffu = u('').join( l.decode(locale.getpreferredencoding(), 'replace') for l in diff) testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f">\n' ' <failure>%(diff)s</failure>\n' ' </testcase>\n') % { 'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime, 'diff': _cdata(diffu) }) else: testcase = (u(' <testcase classname=%(classname)s\n' ' name=%(name)s\n' ' time="%(time).6f"/>\n') % { 'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime }) testcases.append(testcase) return refout, postout, diff yield path, testwrapper suitetime = time.time() - suitestart header = (u('<?xml version="1.0" encoding="utf-8"?>\n' '<testsuite name="cram"\n' ' tests="%(total)d"\n' ' failures="%(failed)d"\n' ' skipped="%(skipped)d"\n' ' timestamp=%(timestamp)s\n' ' hostname=%(hostname)s\n' ' time="%(time).6f">\n') % { 'total': total[0], 'failed': failed[0], 'skipped': skipped[0], 'timestamp': _quoteattr(timestamp), 'hostname': _quoteattr(hostname), 'time': suitetime }) footer = u('</testsuite>\n') xmlfile = open(xmlpath, 'wb') try: xmlfile.write(header.encode('utf-8')) for testcase in testcases: xmlfile.write(testcase.encode('utf-8')) xmlfile.write(footer.encode('utf-8')) finally: xmlfile.close()
def _quoteattrreplace(m): """Replace _quoteattrsub() regex match""" return { u('\t'): u('	'), u('\n'): u(' '), u('\r'): u(' '), u('"'): u('"'), u('&'): u('&'), u('<'): u('<'), u('>'): u('>') }.get(m.group(0), _replacementchar)