diff options
author | Pierre-Yves David <pierre-yves.david@logilab.fr> | 2010-06-23 08:39:08 +0200 |
---|---|---|
committer | Pierre-Yves David <pierre-yves.david@logilab.fr> | 2010-06-23 08:39:08 +0200 |
commit | 025e34b17d6a9e66b57a91fe3361d58d23130d20 (patch) | |
tree | 633c704f9bb1c05be227fa33f225268f0a63045f | |
parent | 13825514749b3577d9c7df11a848c1ecbc0d1cba (diff) | |
parent | 26fa435967515a73138bbca2ac71754335d85aba (diff) | |
download | logilab-common-025e34b17d6a9e66b57a91fe3361d58d23130d20.tar.gz |
backport stable into default
-rw-r--r-- | test/unittest_testlib.py | 6 | ||||
-rw-r--r-- | testlib.py | 163 |
2 files changed, 125 insertions, 44 deletions
diff --git a/test/unittest_testlib.py b/test/unittest_testlib.py index 74a8c10..fff864b 100644 --- a/test/unittest_testlib.py +++ b/test/unittest_testlib.py @@ -870,7 +870,7 @@ class TagTC(TestCase): self.func = bob class TagTestTC(TestCase): - tags = Tags(('one', 'two')) + tags = Tags('one', 'two') def test_one(self): self.assertTrue(True) @@ -879,7 +879,7 @@ class TagTC(TestCase): def test_two(self): self.assertTrue(True) - @tag('three') + @tag('three', inherit=False) def test_three(self): self.assertTrue(True) self.cls = TagTestTC @@ -927,7 +927,7 @@ class TagTC(TestCase): runner = SkipAwareTextTestRunner(options=options('one')) self.assertTrue(runner.does_match_tags(cls.test_one)) - self.assertFalse(runner.does_match_tags(cls.test_two)) + self.assertTrue(runner.does_match_tags(cls.test_two)) self.assertFalse(runner.does_match_tags(cls.test_three)) runner = SkipAwareTextTestRunner(options=options('two')) @@ -508,13 +508,10 @@ class SkipAwareTextTestRunner(unittest.TextTestRunner): if self.options is not None: tags_pattern = getattr(self.options, 'tags_pattern', None) if tags_pattern is not None: - tags = getattr(test, 'tags', None) - if tags is not None: - return tags.match(tags_pattern) - if isinstance(test, types.MethodType): - tags = getattr(test.im_class, 'tags', Tags()) - return tags.match(tags_pattern) - return False + tags = getattr(test, 'tags', Tags()) + if tags.inherit and isinstance(test, types.MethodType): + tags = tags | getattr(test.im_class, 'tags', Tags()) + return tags.match(tags_pattern) return True # no pattern def _makeResult(self): @@ -1001,12 +998,30 @@ class InnerTest(tuple): instance.name = name return instance +class Tags(set): + """A set of tag able validate an expression""" + + def __init__(self, *tags, **kwargs): + self.inherit = kwargs.pop('inherit', True) + if kwargs: + raise TypeError("%s are an invalid keyword argument for this function" % kwargs.keys()) + + if len(tags) == 1 and not isinstance(tags[0], basestring): + tags = tags[0] + super(Tags, self).__init__(tags, **kwargs) + + def __getitem__(self, key): + return key in self + + def match(self, exp): + return eval(exp, {}, self) class TestCase(unittest.TestCase): - """unittest.TestCase with some additional methods""" + """A unittest.TestCase extension with some additional methods.""" capture = False pdbclass = Debugger + tags = Tags() def __init__(self, methodName='runTest'): super(TestCase, self).__init__(methodName) @@ -1260,11 +1275,19 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) raise InnerTestSkipped(msg) def assertIn(self, object, set): - """assert <object> are in <set>""" + """assert <object> is in <set> + + :param object: a Python Object + :param set: a Python Container + """ self.assert_(object in set, "%s not in %s" % (object, set)) def assertNotIn(self, object, set): - """assert <object> are not in <set>""" + """assert <object> is not in <set> + + :param object: a Python Object + :param set: the Python container to contain <object> + """ self.assert_(object not in set, "%s in %s" % (object, set)) def assertDictEquals(self, dict1, dict2): @@ -1272,6 +1295,8 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) If the two dict differ, the first difference is shown in the error message + :param dict1: a Python Dictionary + :param dict2: a Python Dictionary """ dict1 = dict(dict1) msgs = [] @@ -1290,9 +1315,13 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) assertDictEqual = assertDictEquals - def assertUnorderedIterableEquals(self, got, expected, msg=None): - """compares two iterable and shows difference between both""" + """compares two iterable and shows difference between both + + :param got: the unordered Iterable that we found + :param expected: the expected unordered Iterable + :param msg: custom message (String) in case of failure + """ got, expected = list(got), list(expected) self.assertSetEqual(set(got), set(expected), msg) if len(got) != len(expected): @@ -1318,6 +1347,15 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) assertUnordIterEquals = assertUnordIterEqual = assertUnorderedIterableEqual def assertSetEquals(self,got,expected, msg=None): + """compares two sets and shows difference between both + + Don't use it for iterables other than sets. + + :param got: the Set that we found + :param expected: the second Set to be compared to the first one + :param msg: custom message (String) in case of failure + """ + if not(isinstance(got, set) and isinstance(expected, set)): warnings.warn("the assertSetEquals function if now intended for set only."\ "use assertUnorderedIterableEquals instead.", @@ -1341,6 +1379,10 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) If the two list differ, the first difference is shown in the error message + + :param list_1: a Python List + :param list_2: a second Python List + :param msg: custom message (String) in case of failure """ _l1 = list_1[:] for i, value in enumerate(list_2): @@ -1362,21 +1404,29 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) self.fail(msg) assertListEqual = assertListEquals - def assertLinesEquals(self, list_1, list_2, msg=None, striplines=False): - """assert list of lines are equal""" - lines1 = list_1.splitlines() + def assertLinesEquals(self, string1, string2, msg=None, striplines=False): + """compare two strings and assert that the text lines of the strings + are equal. + + :param string1: a String + :param string2: a String + :param msg: custom message (String) in case of failure + :param striplines: Boolean to trigger line stripping before comparing + """ + lines1 = string1.splitlines() + lines2 = string2.splitlines() if striplines: lines1 = [l.strip() for l in lines1] - lines2 = list_2.splitlines() - if striplines: lines2 = [l.strip() for l in lines2] self.assertListEquals(lines1, lines2, msg) assertLineEqual = assertLinesEquals def assertXMLWellFormed(self, stream, msg=None, context=2): """asserts the XML stream is well-formed (no DTD conformance check) - :context: number of context lines in standard msg. all data if negativ - only available with element tree + + :param context: number of context lines in standard message + (show all data if negative). + Only available with element tree """ try: from xml.etree.ElementTree import parse @@ -1397,8 +1447,10 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) def assertXMLStringWellFormed(self, xml_string, msg=None, context=2): """asserts the XML string is well-formed (no DTD conformance check) - :context: number of context lines in standard msg. all data if negativ - only available with element tree + + :param context: number of context lines in standard message + (show all data if negative). + Only available with element tree """ try: from xml.etree.ElementTree import fromstring @@ -1408,11 +1460,13 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) def _assertETXMLWellFormed(self, data, parse, msg=None, context=2): """internal function used by /assertXML(String)?WellFormed/ functions - :data: xml_data - :parse: appropriate parser function for this data - :msg: error message - :context: number of context lines in standard msg. all data if negativ - only available with element tree + + :param data: xml_data + :param parse: appropriate parser function for this data + :param msg: error message + :param context: number of context lines in standard message + (show all data if negative). + Only available with element tree """ from xml.parsers.expat import ExpatError try: @@ -1496,7 +1550,14 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) def assertTextEquals(self, text1, text2, junk=None, msg_prefix='Text differ', striplines=False): - """compare two multiline strings (using difflib and splitlines())""" + """compare two multiline strings (using difflib and splitlines()) + + :param text1: a Python BaseString + :param text2: a second Python Basestring + :param junk: List of Caracters + :param msg_prefix: String (message prefix) + :param striplines: Boolean to trigger line stripping before comparing + """ msg = [] if not isinstance(text1, basestring): msg.append('text1 is not a string (%s)'%(type(text1))) @@ -1600,7 +1661,14 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) def assertIsInstance(self, obj, klass, msg=None, strict=False): - """compares two files using difflib""" + """check if an object is an instance of a class + + :param obj: the Python Object to be checked + :param klass: the target class + :param msg: a String for a custom message + :param strict: if True, check that the class of <obj> is <klass>; + else check with 'isinstance' + """ if msg is None: if strict: msg = '%r is not of class %s but of %s' @@ -1613,7 +1681,12 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) self.assert_(isinstance(obj, klass), msg) def assertIs(self, obj, other, msg=None): - """compares identity of two reference""" + """compares identity of two reference + + :param obj: a Python Object + :param other: another Python Object + :param msg: a String for a custom message + """ if msg is None: msg = "%r is not %r"%(obj, other) self.assert_(obj is other, msg) @@ -1626,7 +1699,10 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) self.assert_(obj is not other, msg ) def assertNone(self, obj, msg=None): - """assert obj is None""" + """assert obj is None + + :param obj: Python Object to be tested + """ if msg is None: msg = "reference to %r when None expected"%(obj,) self.assert_( obj is None, msg ) @@ -1638,7 +1714,15 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) self.assert_( obj is not None, msg ) def assertFloatAlmostEquals(self, obj, other, prec=1e-5, msg=None): - """compares two floats""" + """compares if two floats have a distance smaller than expected + precision. + + :param obj: a Float + :param other: another Float to be comparted to <obj> + :param prec: a Float describing the precision + :param msg: a String for a custom message + """ + if msg is None: msg = "%r != %r" % (obj, other) self.assert_(math.fabs(obj - other) < prec, msg) @@ -1653,6 +1737,11 @@ succeeded test into", osp.join(os.getcwd(),FILE_RESTART) thrown, it will not be caught, and the test case will be deemed to have suffered an error, exactly as for an unexpected exception. + + :param excClass: the Exception to be raised + :param callableObj: a callable Object which should raise <excClass> + :param args: a List of arguments for <callableObj> + :param kwargs: a List of keyword arguments for <callableObj> """ try: callableObj(*args, **kwargs) @@ -1875,22 +1964,14 @@ class AttrObject: # XXX cf mock_object def __init__(self, **kwargs): self.__dict__.update(kwargs) -def tag(*args): +def tag(*args, **kwargs): """descriptor adding tag to a function""" def desc(func): assert not hasattr(func, 'tags') - func.tags = Tags(args) + func.tags = Tags(*args, **kwargs) return func return desc -class Tags(set): - """A set of tag able validate an expression""" - def __getitem__(self, key): - return key in self - - def match(self, exp): - return eval(exp, {}, self) - def require_version(version): """ Compare version of python interpreter to the given one. Skip the test if older. |