Skip to content

Commit

Permalink
Add unit test for all passed case and fixed problems unit test found.
Browse files Browse the repository at this point in the history
Refs #9874
  • Loading branch information
martyngigg committed Aug 1, 2014
1 parent 9ed63ac commit 87a17c6
Show file tree
Hide file tree
Showing 2 changed files with 211 additions and 27 deletions.
103 changes: 76 additions & 27 deletions Code/Mantid/docs/sphinxext/mantiddoc/doctest.py
Expand Up @@ -20,15 +20,22 @@
- All Passed:
============
Document: bar/FooDoc
--------------------
1 items passed all tests:
Document: algorithms/AllPassed
------------------------------
2 items passed all tests:
1 tests in Ex 2
2 tests in default
1 tests in ExForFoo
2 tests in 1 items.
2 passed and 0 failed.
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Doctest summary
===============
3 tests
0 failures in tests
0 failures in setup code
0 failures in cleanup code
- All Failed:
============
Expand Down Expand Up @@ -60,6 +67,12 @@
0 passed and 2 failed.
***Test Failed*** 2 failures.
Doctest summary
===============
2 tests
2 failures in tests
0 failures in setup code
0 failures in cleanup code
- Some pass some fail:
====================
Expand Down Expand Up @@ -92,12 +105,30 @@
2 passed and 2 failed.
***Test Failed*** 2 failures.
Doctest summary
===============
4 tests
2 failures in tests
0 failures in setup code
0 failures in cleanup code
"""
import re

#-------------------------------------------------------------------------------
# Define parts of lines that denote a document
DOCTEST_DOCUMENT_BEGIN = "Document:"
DOCTEST_SUMMARY_TITLE = "Doctest summary"

# Regexes
ALLPASS_TEST_NAMES_RE = re.compile(r"^\s+(\d+) tests in (.+)$")
NUMBER_PASSED_RE = re.compile(r"^(\d+) items passed all tests:$")

#-------------------------------------------------------------------------------
class TestSuite(object):
class TestSuiteReport(object):

def __init__(self, name, cases, package=None):
if len(cases) == 0:
raise ValueError("No test cases provided")
self.name = name
self.testcases = cases
self.package = package
Expand All @@ -107,27 +138,30 @@ def ntests(self):
return len(self.testcases)

@property
def nfailures(self):
def nfailed(self):
def sum_failure(fails, case):
if case.failed: return fails + 1
else: return fails
return reduce(sum_failure, self.testcases, 0)

@property
def npassed(self):
return self.ntests - self.nfailures
return self.ntests - self.nfailed

#-------------------------------------------------------------------------------
class TestCase(object):
class TestCaseReport(object):

def __init__(self, classname, name, failure_descr):
self.classname = classname
self.name = name
self.failure_descr = failure_descr
if failure_descr is not None:
self.failure_descr = failure_descr
else:
self.failure_descr = ""

@property
def passed(self):
return (self.failure_descr is None)
return (self.failure_descr == "")

@property
def failed(self):
Expand All @@ -140,9 +174,21 @@ class DocTestOutputParser(object):
to a different format
"""

def __init__(self, filename):
with open(filename,'r') as result_file:
self.testsuite = self.__parse(result_file)
def __init__(self, doctest_output, isfile):
"""
Parses the given doctest output
Args:
doctest_output (str): String giving either doctest output as plain
text or a filename
isfile (bool): If True then the doctest_output argument is treated
as a filename
"""
if isfile:
with open(filename,'r') as result_file:
self.testsuite = self.__parse(result_file)
else:
self.testsuite = self.__parse(doctest_output.splitlines())

def as_xunit(self, filename):
"""
Expand All @@ -165,40 +211,43 @@ def as_xunit(self, filename):
tree = ElementTree.ElementTree(suite_node)
tree.write(filename, encoding="utf-8", xml_declaration=True)

def __parse(self, result_file):
def __parse(self, results):
"""
Parse a doctest output file and a TestSuite
Parse a doctest output file and a TestSuiteReport
object that describe the results of the
all tests on a single document
Arguments:
result_file (File): File-like object
results (iterable): Iterable where each element contains
a line of the results
Returns:
TestSuite: TestSuite object
"""
in_doc = False
document_txt = []
in_doc = False
document_txt = None
cases = []
for line in result_file:
for line in results:
if line.startswith(DOCTEST_DOCUMENT_BEGIN):
# parse previous results
if document_txt:
cases.extend(self.__parse_document(document_txt))
document_txt = [line]
in_doc = True
continue
if line.startswith(DOCTEST_SUMMARY_TITLE):
if line.startswith(DOCTEST_SUMMARY_TITLE): # end of tests
in_doc = False
cases.extend(self.__parse_document(document_txt))
document_txt = None
if in_doc and line != "":
document_txt.append(line)
# endif
return TestSuite(name="doctests", cases=cases,
package="doctests")
# endfor
return TestSuiteReport(name="doctests", cases=cases,
package="docs")

def __parse_document(self, text):
"""
Create a list of TestCase object for this document
Create a list of TestCaseReport object for this document
Args:
text (str): String containing doctest output
Expand Down Expand Up @@ -256,7 +305,7 @@ def __parse_success(self, fullname, result_txt):
"all pass case: %s" % line)
ntests, name = int(match.group(1)), match.group(2)
for idx in range(ntests):
cases.append(TestCase(classname, name, failure_descr=None))
cases.append(TestCaseReport(classname, name, failure_descr=None))
#endfor
return cases

Expand Down
135 changes: 135 additions & 0 deletions Code/Mantid/docs/sphinxext/mantiddoc/tests/test_doctest.py
@@ -0,0 +1,135 @@
"""
Tests for the doctest addons
"""
from mantiddoc.doctest import DocTestOutputParser, TestCaseReport, TestSuiteReport

import unittest

class TestCaseReportTest(unittest.TestCase):

def test_report_stores_expected_attributes_about_test(self):
name = "DummyTest"
classname = "DummySuite"
failure_txt = "Test failed"
report = TestCaseReport(classname, name, failure_txt)

self.assertEquals(name, report.name)
self.assertEquals(classname, report.classname)
self.assertEquals(failure_txt, report.failure_descr)

def test_case_passed_with_empty_failure_description(self):
name = "DummyTest"
classname = "DummySuite"
failure_txt = ""
report = TestCaseReport(classname, name, failure_txt)

self.assertTrue(report.passed)
self.assertFalse(report.failed)

def test_case_passed_with_failure_description_as_None(self):
name = "DummyTest"
classname = "DummySuite"
failure_txt = None
report = TestCaseReport(classname, name, failure_txt)

self.assertTrue(report.passed)
self.assertFalse(report.failed)

def test_case_failed_with_non_empty_failure_description(self):
name = "DummyTest"
classname = "DummySuite"
failure_txt = "Test failed"
report = TestCaseReport(classname, name, failure_txt)

self.assertTrue(report.failed)
self.assertFalse(report.passed)

#------------------------------------------------------------------------------

class TestSuiteReportTest(unittest.TestCase):

def test_report_stores_expected_attributes_about_test(self):
name = "DummySuite"
package = "tests"
testcases = [TestCaseReport("doctests", "DummyTest", "failed")]
report = TestSuiteReport(name, testcases, package)

self.assertEquals(name, report.name)
self.assertEquals(package, report.package)
self.assertEquals(testcases, report.testcases)

def test_report_gives_corret_number_test_passed_and_failed(self):
report = self.__createDummyReport()

self.assertEquals(1, report.npassed)
self.assertEquals(1, report.nfailed)
self.assertEquals(2, report.ntests)

#========================= Failure cases ==================================

def test_report_raises_error_with_empty_tests_cases_list(self):
self.assertRaises(ValueError, self.__createDummyReport, empty = True)

#========================= Helpers ========================================

def __createDummyReport(self, empty = False):
name = "DummySuite"
package = "tests"
if empty:
testcases = []
else:
testcases = [TestCaseReport("doctests", "DummyTest", "failed"),
TestCaseReport("doctests", "DummyTest2", "")]

return TestSuiteReport(name, testcases, package)

#------------------------------------------------------------------------------

ALL_PASS_EX = \
"""
Document: algorithms/AllPassed
------------------------------
2 items passed all tests:
1 tests in Ex 2
2 tests in default
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Doctest summary
===============
3 tests
0 failures in tests
0 failures in setup code
0 failures in cleanup code
"""

class DocTestOutputParserTest(unittest.TestCase):

def test_all_passed_gives_expected_results(self):
parser = DocTestOutputParser(ALL_PASS_EX, isfile = False)

self.assertTrue(hasattr(parser, "testsuite"))
suite = parser.testsuite
self.assertEquals("doctests", suite.name)
self.assertEquals("docs", suite.package)
self.assertEquals(3, suite.ntests)

cases = suite.testcases
expected_names = ["Ex 2", "default", "default"]
for idx, case in enumerate(cases):
self.assertTrue(case.passed)
self.assertEquals(expected_names[idx], case.name)
self.assertEquals("AllPassed", case.classname)

#========================= Failure cases ==================================

def test_no_document_start_gives_valueerror(self):
self.assertRaises(ValueError, DocTestOutputParser,
"----------\n 1 items passed", isfile = False)

#------------------------------------------------------------------------------

if __name__ == '__main__':
unittest.main()

0 comments on commit 87a17c6

Please sign in to comment.