1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
#!/usr/bin/python
"""$Id: validtest.py 1014 2008-05-21 20:43:22Z joe.walton.gglcd $"""
__author__ = "Sam Ruby <http://intertwingly.net/> and Mark Pilgrim <http://diveintomark.org/>"
__version__ = "$Revision: 1014 $"
__copyright__ = "Copyright (c) 2002 Sam Ruby and Mark Pilgrim"
import feedvalidator
import unittest, new, os, sys, glob, re
from feedvalidator.logging import Message,SelfDoesntMatchLocation,MissingSelf
from feedvalidator import compatibility
from feedvalidator.formatter.application_test import Formatter
class TestCase(unittest.TestCase):
def failIfNoMessage(self, theList):
filterFunc = compatibility.AA
events = filterFunc(theList)
output = Formatter(events)
for e in events:
if not output.format(e):
raise self.failureException, 'could not contruct message for %s' % e
def failUnlessContainsInstanceOf(self, theClass, params, theList, msg=None):
"""Fail if there are no instances of theClass in theList with given params"""
self.failIfNoMessage(theList)
failure=(msg or 'no %s instances in %s' % (theClass.__name__, `theList`))
for item in theList:
if issubclass(item.__class__, theClass):
if not params: return
for k, v in params.items():
if str(item.params[k]) <> v:
failure=("%s.%s value was %s, expected %s" %
(theClass.__name__, k, item.params[k], v))
break
else:
return
raise self.failureException, failure
def failIfContainsInstanceOf(self, theClass, params, theList, msg=None):
"""Fail if there are instances of theClass in theList with given params"""
self.failIfNoMessage(theList)
for item in theList:
if theClass==Message and isinstance(item,SelfDoesntMatchLocation):
continue
if theClass==Message and isinstance(item,MissingSelf):
continue
if issubclass(item.__class__, theClass):
if not params:
raise self.failureException, \
(msg or 'unexpected %s' % (theClass.__name__))
allmatch = 1
for k, v in params.items():
if item.params[k] != v:
allmatch = 0
if allmatch:
raise self.failureException, \
"unexpected %s.%s with a value of %s" % \
(theClass.__name__, k, v)
desc_re = re.compile("<!--\s*Description:\s*(.*?)\s*Expect:\s*(!?)(\w*)(?:{(.*?)})?\s*-->")
validome_re = re.compile("<!--\s*Description:\s*(.*?)\s*Message:\s*(!?)(\w*).*?\s*-->", re.S)
def getDescription(xmlfile):
"""Extract description and exception from XML file
The deal here is that each test case is an XML file which contains
not only a possibly invalid RSS feed but also the description of the
test, i.e. the exception that we would expect the RSS validator to
raise (or not) when it validates the feed. The expected exception and
the human-readable description are placed into an XML comment like this:
<!--
Description: channel must include title
Expect: MissingTitle
-->
"""
stream = open(xmlfile)
xmldoc = stream.read()
stream.close()
search_results = desc_re.search(xmldoc)
if search_results:
description, cond, excName, plist = list(search_results.groups())
else:
search_results = validome_re.search(xmldoc)
if search_results:
plist = ''
description, cond, excName = list(search_results.groups())
excName = excName.capitalize()
if excName=='Valid': cond,excName = '!', 'Message'
else:
raise RuntimeError, "can't parse %s" % xmlfile
if cond == "":
method = TestCase.failUnlessContainsInstanceOf
else:
method = TestCase.failIfContainsInstanceOf
params = {}
if plist:
for entry in plist.split(','):
name,value = entry.lstrip().split(':',1)
params[name] = value
exc = getattr(feedvalidator, excName)
description = xmlfile + ": " + description
return method, description, params, exc
def buildTestCase(xmlfile, xmlBase, description, method, exc, params):
"""factory to create functions which validate `xmlfile`
the returned function asserts that validating `xmlfile` (an XML file)
will return a list of exceptions that include an instance of
`exc` (an Exception class)
"""
func = lambda self, xmlfile=xmlfile, exc=exc, params=params: \
method(self, exc, params, feedvalidator.validateString(open(xmlfile).read(), fallback='US-ASCII', base=xmlBase)['loggedEvents'])
func.__doc__ = description
return func
def buildTestSuite():
curdir = os.path.dirname(os.path.abspath(__file__))
basedir = os.path.split(curdir)[0]
for xmlfile in sys.argv[1:] or (glob.glob(os.path.join(basedir, 'testcases', '**', '**', '*.xml')) + glob.glob(os.path.join(basedir, 'testcases', 'opml', '**', '*.opml'))):
method, description, params, exc = getDescription(xmlfile)
xmlBase = os.path.abspath(xmlfile).replace(basedir,"http://www.feedvalidator.org")
testName = 'test_' + xmlBase.replace(os.path.sep, "/")
testFunc = buildTestCase(xmlfile, xmlBase, description, method, exc, params)
instanceMethod = new.instancemethod(testFunc, None, TestCase)
setattr(TestCase, testName, instanceMethod)
return unittest.TestLoader().loadTestsFromTestCase(TestCase)
if __name__ == '__main__':
suite = buildTestSuite()
unittest.main(argv=sys.argv[:1])
|