/unit_tests/test_xunit.py

https://bitbucket.org/jpellerin/nose/ · Python · 343 lines · 335 code · 8 blank · 0 comment · 0 complexity · b5aeb525449a60a794b3dc25ec95456c MD5 · raw file

  1. import sys
  2. import os
  3. import optparse
  4. import re
  5. import unittest
  6. from xml.sax import saxutils
  7. from nose.pyversion import UNICODE_STRINGS
  8. from nose.tools import eq_
  9. from nose.plugins.xunit import Xunit, escape_cdata, id_split
  10. from nose.exc import SkipTest
  11. from nose.config import Config
  12. def mktest():
  13. class TC(unittest.TestCase):
  14. def runTest(self):
  15. pass
  16. test = TC()
  17. return test
  18. mktest.__test__ = False
  19. time_taken = re.compile(r'\d\.\d\d')
  20. class TestEscaping(unittest.TestCase):
  21. def setUp(self):
  22. self.x = Xunit()
  23. def test_all(self):
  24. eq_(self.x._quoteattr(
  25. '''<baz src="http://foo?f=1&b=2" quote="inix hubris 'maximus'?" />'''),
  26. ('"&lt;baz src=&quot;http://foo?f=1&amp;b=2&quot; '
  27. 'quote=&quot;inix hubris \'maximus\'?&quot; /&gt;"'))
  28. def test_unicode_is_utf8_by_default(self):
  29. if not UNICODE_STRINGS:
  30. eq_(self.x._quoteattr(u'Ivan Krsti\u0107'),
  31. '"Ivan Krsti\xc4\x87"')
  32. def test_unicode_custom_utf16_madness(self):
  33. self.x.encoding = 'utf-16'
  34. utf16 = self.x._quoteattr(u'Ivan Krsti\u0107')[1:-1]
  35. if UNICODE_STRINGS:
  36. # If all internal strings are unicode, then _quoteattr shouldn't
  37. # have changed anything.
  38. eq_(utf16, u'Ivan Krsti\u0107')
  39. else:
  40. # to avoid big/little endian bytes, assert that we can put it back:
  41. eq_(utf16.decode('utf16'), u'Ivan Krsti\u0107')
  42. def test_control_characters(self):
  43. # quoting of \n, \r varies in diff. python versions
  44. n = saxutils.quoteattr('\n')[1:-1]
  45. r = saxutils.quoteattr('\r')[1:-1]
  46. eq_(self.x._quoteattr('foo\n\b\f\r'), '"foo%s??%s"' % (n, r))
  47. eq_(escape_cdata('foo\n\b\f\r'), 'foo\n??\r')
  48. class TestSplitId(unittest.TestCase):
  49. def check_id_split(self, cls, name):
  50. split = id_split('%s.%s' % (cls, name))
  51. eq_(split[0], cls)
  52. eq_(split[1], name)
  53. def test_no_parenthesis(self):
  54. self.check_id_split("test_parset", "test_args")
  55. def test_no_dot_in_args(self):
  56. self.check_id_split("test_parset", "test_args(('x', [1, 2]),)")
  57. def test_dot_in_args(self):
  58. self.check_id_split("test_parset", "test_args(('x.y', 1),)")
  59. def test_grandchild_has_dot_in_args(self):
  60. self.check_id_split("test_grandparset.test_parset",
  61. "test_args(('x.y', 1),)")
  62. class TestOptions(unittest.TestCase):
  63. def test_defaults(self):
  64. parser = optparse.OptionParser()
  65. x = Xunit()
  66. x.add_options(parser, env={})
  67. (options, args) = parser.parse_args([])
  68. eq_(options.xunit_file, "nosetests.xml")
  69. def test_file_from_environ(self):
  70. parser = optparse.OptionParser()
  71. x = Xunit()
  72. x.add_options(parser, env={'NOSE_XUNIT_FILE': "kangaroo.xml"})
  73. (options, args) = parser.parse_args([])
  74. eq_(options.xunit_file, "kangaroo.xml")
  75. def test_file_from_opt(self):
  76. parser = optparse.OptionParser()
  77. x = Xunit()
  78. x.add_options(parser, env={})
  79. (options, args) = parser.parse_args(["--xunit-file=blagojevich.xml"])
  80. eq_(options.xunit_file, "blagojevich.xml")
  81. class TestXMLOutputWithXML(unittest.TestCase):
  82. def setUp(self):
  83. self.xmlfile = os.path.abspath(
  84. os.path.join(os.path.dirname(__file__),
  85. 'support', 'xunit.xml'))
  86. parser = optparse.OptionParser()
  87. self.x = Xunit()
  88. self.x.add_options(parser, env={})
  89. (options, args) = parser.parse_args([
  90. "--with-xunit",
  91. "--xunit-file=%s" % self.xmlfile
  92. ])
  93. self.x.configure(options, Config())
  94. try:
  95. import xml.etree.ElementTree
  96. except ImportError:
  97. self.ET = False
  98. else:
  99. self.ET = xml.etree.ElementTree
  100. def tearDown(self):
  101. os.unlink(self.xmlfile)
  102. def get_xml_report(self):
  103. class DummyStream:
  104. pass
  105. self.x.report(DummyStream())
  106. f = open(self.xmlfile, 'rb')
  107. return f.read()
  108. f.close()
  109. def test_addFailure(self):
  110. test = mktest()
  111. self.x.startTest(test)
  112. try:
  113. raise AssertionError("one is not 'equal' to two")
  114. except AssertionError:
  115. some_err = sys.exc_info()
  116. self.x.addFailure(test, some_err)
  117. result = self.get_xml_report()
  118. print result
  119. if self.ET:
  120. tree = self.ET.fromstring(result)
  121. eq_(tree.attrib['name'], "nosetests")
  122. eq_(tree.attrib['tests'], "1")
  123. eq_(tree.attrib['errors'], "0")
  124. eq_(tree.attrib['failures'], "1")
  125. eq_(tree.attrib['skip'], "0")
  126. tc = tree.find("testcase")
  127. eq_(tc.attrib['classname'], "test_xunit.TC")
  128. eq_(tc.attrib['name'], "runTest")
  129. assert time_taken.match(tc.attrib['time']), (
  130. 'Expected decimal time: %s' % tc.attrib['time'])
  131. err = tc.find("failure")
  132. eq_(err.attrib['type'], "%s.AssertionError" % (AssertionError.__module__,))
  133. err_lines = err.text.strip().split("\n")
  134. eq_(err_lines[0], 'Traceback (most recent call last):')
  135. eq_(err_lines[-1], 'AssertionError: one is not \'equal\' to two')
  136. eq_(err_lines[-2], ' raise AssertionError("one is not \'equal\' to two")')
  137. else:
  138. # this is a dumb test for 2.4-
  139. assert '<?xml version="1.0" encoding="UTF-8"?>' in result
  140. assert '<testsuite name="nosetests" tests="1" errors="0" failures="1" skip="0">' in result
  141. assert '<testcase classname="test_xunit.TC" name="runTest"' in result
  142. assert '<failure type="exceptions.AssertionError"' in result
  143. assert "AssertionError: one is not 'equal' to two" in result
  144. assert "AssertionError(\"one is not 'equal' to two\")" in result
  145. assert '</failure></testcase></testsuite>' in result
  146. def test_addFailure_early(self):
  147. test = mktest()
  148. try:
  149. raise AssertionError("one is not equal to two")
  150. except AssertionError:
  151. some_err = sys.exc_info()
  152. # add failure without startTest, due to custom TestResult munging?
  153. self.x.addFailure(test, some_err)
  154. result = self.get_xml_report()
  155. print result
  156. if self.ET:
  157. tree = self.ET.fromstring(result)
  158. tc = tree.find("testcase")
  159. assert time_taken.match(tc.attrib['time']), (
  160. 'Expected decimal time: %s' % tc.attrib['time'])
  161. else:
  162. # this is a dumb test for 2.4-
  163. assert '<?xml version="1.0" encoding="UTF-8"?>' in result
  164. assert ('<testcase classname="test_xunit.TC" '
  165. 'name="runTest" time="0') in result
  166. def test_addError(self):
  167. test = mktest()
  168. self.x.startTest(test)
  169. try:
  170. raise RuntimeError("some error happened")
  171. except RuntimeError:
  172. some_err = sys.exc_info()
  173. self.x.addError(test, some_err)
  174. result = self.get_xml_report()
  175. print result
  176. if self.ET:
  177. tree = self.ET.fromstring(result)
  178. eq_(tree.attrib['name'], "nosetests")
  179. eq_(tree.attrib['tests'], "1")
  180. eq_(tree.attrib['errors'], "1")
  181. eq_(tree.attrib['failures'], "0")
  182. eq_(tree.attrib['skip'], "0")
  183. tc = tree.find("testcase")
  184. eq_(tc.attrib['classname'], "test_xunit.TC")
  185. eq_(tc.attrib['name'], "runTest")
  186. assert time_taken.match(tc.attrib['time']), (
  187. 'Expected decimal time: %s' % tc.attrib['time'])
  188. err = tc.find("error")
  189. eq_(err.attrib['type'], "%s.RuntimeError" % (RuntimeError.__module__,))
  190. err_lines = err.text.strip().split("\n")
  191. eq_(err_lines[0], 'Traceback (most recent call last):')
  192. eq_(err_lines[-1], 'RuntimeError: some error happened')
  193. eq_(err_lines[-2], ' raise RuntimeError("some error happened")')
  194. else:
  195. # this is a dumb test for 2.4-
  196. assert '<?xml version="1.0" encoding="UTF-8"?>' in result
  197. assert '<testsuite name="nosetests" tests="1" errors="1" failures="0" skip="0">' in result
  198. assert '<testcase classname="test_xunit.TC" name="runTest"' in result
  199. assert '<error type="exceptions.RuntimeError"' in result
  200. assert 'RuntimeError: some error happened' in result
  201. assert '</error></testcase></testsuite>' in result
  202. def test_non_utf8_error(self):
  203. # See http://code.google.com/p/python-nose/issues/detail?id=395
  204. test = mktest()
  205. self.x.startTest(test)
  206. try:
  207. raise RuntimeError(chr(128)) # cannot encode as utf8
  208. except RuntimeError:
  209. some_err = sys.exc_info()
  210. self.x.addError(test, some_err)
  211. result = self.get_xml_report()
  212. print repr(result)
  213. if self.ET:
  214. tree = self.ET.fromstring(result)
  215. tc = tree.find("testcase")
  216. err = tc.find("error")
  217. if UNICODE_STRINGS:
  218. eq_(err.attrib['message'],
  219. '\x80')
  220. else:
  221. eq_(err.attrib['message'],
  222. u'\ufffd')
  223. else:
  224. # this is a dumb test for 2.4-
  225. assert 'RuntimeError: \xef\xbf\xbd' in result
  226. def test_addError_early(self):
  227. test = mktest()
  228. try:
  229. raise RuntimeError("some error happened")
  230. except RuntimeError:
  231. some_err = sys.exc_info()
  232. # call addError without startTest
  233. # which can happen if setup() raises an error
  234. self.x.addError(test, some_err)
  235. result = self.get_xml_report()
  236. print result
  237. if self.ET:
  238. tree = self.ET.fromstring(result)
  239. tc = tree.find("testcase")
  240. assert time_taken.match(tc.attrib['time']), (
  241. 'Expected decimal time: %s' % tc.attrib['time'])
  242. else:
  243. # this is a dumb test for 2.4-
  244. assert '<?xml version="1.0" encoding="UTF-8"?>' in result
  245. assert ('<testcase classname="test_xunit.TC" '
  246. 'name="runTest" time="0') in result
  247. def test_addSuccess(self):
  248. test = mktest()
  249. self.x.startTest(test)
  250. self.x.addSuccess(test, (None,None,None))
  251. result = self.get_xml_report()
  252. print result
  253. if self.ET:
  254. tree = self.ET.fromstring(result)
  255. eq_(tree.attrib['name'], "nosetests")
  256. eq_(tree.attrib['tests'], "1")
  257. eq_(tree.attrib['errors'], "0")
  258. eq_(tree.attrib['failures'], "0")
  259. eq_(tree.attrib['skip'], "0")
  260. tc = tree.find("testcase")
  261. eq_(tc.attrib['classname'], "test_xunit.TC")
  262. eq_(tc.attrib['name'], "runTest")
  263. assert time_taken.match(tc.attrib['time']), (
  264. 'Expected decimal time: %s' % tc.attrib['time'])
  265. else:
  266. # this is a dumb test for 2.4-
  267. assert '<?xml version="1.0" encoding="UTF-8"?>' in result
  268. assert '<testsuite name="nosetests" tests="1" errors="0" failures="0" skip="0">' in result
  269. assert '<testcase classname="test_xunit.TC" name="runTest"' in result
  270. assert '</testsuite>' in result
  271. def test_addSuccess_early(self):
  272. test = mktest()
  273. # call addSuccess without startTest
  274. # which can happen (?) -- did happen with JsLint plugin
  275. self.x.addSuccess(test, (None,None,None))
  276. result = self.get_xml_report()
  277. print result
  278. if self.ET:
  279. tree = self.ET.fromstring(result)
  280. tc = tree.find("testcase")
  281. assert time_taken.match(tc.attrib['time']), (
  282. 'Expected decimal time: %s' % tc.attrib['time'])
  283. else:
  284. # this is a dumb test for 2.4-
  285. assert '<?xml version="1.0" encoding="UTF-8"?>' in result
  286. assert ('<testcase classname="test_xunit.TC" '
  287. 'name="runTest" time="0') in result