Code

issue2550729: Fix password history display for anydbm backend, thanks to
[roundup.git] / test / test_templating.py
1 import unittest
2 from cgi import FieldStorage, MiniFieldStorage
4 from roundup.cgi.templating import *
5 from test_actions import MockNull, true
7 class MockDatabase(MockNull):
8     def getclass(self, name):
9         return self.classes[name]
11 class TemplatingTestCase(unittest.TestCase):
12     def setUp(self):
13         self.form = FieldStorage()
14         self.client = MockNull()
15         self.client.db = db = MockDatabase()
16         db.security.hasPermission = lambda *args, **kw: True
17         self.client.form = self.form
19 class HTMLDatabaseTestCase(TemplatingTestCase):
20     def test_HTMLDatabase___getitem__(self):
21         db = HTMLDatabase(self.client)
22         self.assert_(isinstance(db['issue'], HTMLClass))
23         # following assertions are invalid
24         # since roundup/cgi/templating.py r1.173.
25         # HTMLItem is function, not class,
26         # but HTMLUserClass and HTMLUser are passed on.
27         # these classes are no more.  they have ceased to be.
28         #self.assert_(isinstance(db['user'], HTMLUserClass))
29         #self.assert_(isinstance(db['issue1'], HTMLItem))
30         #self.assert_(isinstance(db['user1'], HTMLUser))
32     def test_HTMLDatabase___getattr__(self):
33         db = HTMLDatabase(self.client)
34         self.assert_(isinstance(db.issue, HTMLClass))
35         # see comment in test_HTMLDatabase___getitem__
36         #self.assert_(isinstance(db.user, HTMLUserClass))
37         #self.assert_(isinstance(db.issue1, HTMLItem))
38         #self.assert_(isinstance(db.user1, HTMLUser))
40     def test_HTMLDatabase_classes(self):
41         db = HTMLDatabase(self.client)
42         db._db.classes = {'issue':MockNull(), 'user': MockNull()}
43         db.classes()
45 class FunctionsTestCase(TemplatingTestCase):
46     def test_lookupIds(self):
47         db = HTMLDatabase(self.client)
48         def lookup(key):
49             if key == 'ok':
50                 return '1'
51             if key == 'fail':
52                 raise KeyError, 'fail'
53             return key
54         db._db.classes = {'issue': MockNull(lookup=lookup)}
55         prop = MockNull(classname='issue')
56         self.assertEqual(lookupIds(db._db, prop, ['1','2']), ['1','2'])
57         self.assertEqual(lookupIds(db._db, prop, ['ok','2']), ['1','2'])
58         self.assertEqual(lookupIds(db._db, prop, ['ok', 'fail'], 1),
59             ['1', 'fail'])
60         self.assertEqual(lookupIds(db._db, prop, ['ok', 'fail']), ['1'])
62     def test_lookupKeys(self):
63         db = HTMLDatabase(self.client)
64         def get(entry, key):
65             return {'1': 'green', '2': 'eggs'}.get(entry, entry)
66         shrubbery = MockNull(get=get)
67         db._db.classes = {'shrubbery': shrubbery}
68         self.assertEqual(lookupKeys(shrubbery, 'spam', ['1','2']),
69             ['green', 'eggs'])
70         self.assertEqual(lookupKeys(shrubbery, 'spam', ['ok','2']), ['ok',
71             'eggs'])
73 class HTMLClassTestCase(TemplatingTestCase) :
75     def test_link(self):
76         """Make sure lookup of a Link property works even in the
77         presence of multiple values in the form."""
78         def lookup(key) :
79             self.assertEqual(key, key.strip())
80             return "Status%s"%key
81         self.form.list.append(MiniFieldStorage("status", "1"))
82         self.form.list.append(MiniFieldStorage("status", "2"))
83         status = hyperdb.Link("status")
84         self.client.db.classes = dict \
85             ( issue = MockNull(getprops = lambda : dict(status = status))
86             , status  = MockNull(get = lambda id, name : id, lookup = lookup)
87             )
88         cls = HTMLClass(self.client, "issue")
89         cls["status"]
91     def test_multilink(self):
92         """`lookup` of an item will fail if leading or trailing whitespace
93            has not been stripped.
94         """
95         def lookup(key) :
96             self.assertEqual(key, key.strip())
97             return "User%s"%key
98         self.form.list.append(MiniFieldStorage("nosy", "1, 2"))
99         nosy = hyperdb.Multilink("user")
100         self.client.db.classes = dict \
101             ( issue = MockNull(getprops = lambda : dict(nosy = nosy))
102             , user  = MockNull(get = lambda id, name : id, lookup = lookup)
103             )
104         cls = HTMLClass(self.client, "issue")
105         cls["nosy"]
107     def test_url_match(self):
108         '''Test the URL regular expression in StringHTMLProperty.
109         '''
110         def t(s, nothing=False, **groups):
111             m = StringHTMLProperty.hyper_re.search(s)
112             if nothing:
113                 if m:
114                     self.assertEquals(m, None, '%r matched (%r)'%(s, m.groupdict()))
115                 return
116             else:
117                 self.assertNotEquals(m, None, '%r did not match'%s)
118             d = m.groupdict()
119             for g in groups:
120                 self.assertEquals(d[g], groups[g], '%s %r != %r in %r'%(g, d[g],
121                     groups[g], s))
123         #t('123.321.123.321', 'url')
124         t('http://localhost/', url='http://localhost/')
125         t('http://roundup.net/', url='http://roundup.net/')
126         t('http://richard@localhost/', url='http://richard@localhost/')
127         t('http://richard:sekrit@localhost/',
128             url='http://richard:sekrit@localhost/')
129         t('<HTTP://roundup.net/>', url='HTTP://roundup.net/')
130         t('www.a.ex', url='www.a.ex')
131         t('foo.a.ex', nothing=True)
132         t('StDevValidTimeSeries.GetObservation', nothing=True)
133         t('http://a.ex', url='http://a.ex')
134         t('http://a.ex/?foo&bar=baz\\.@!$%()qwerty',
135             url='http://a.ex/?foo&bar=baz\\.@!$%()qwerty')
136         t('www.foo.net', url='www.foo.net')
137         t('richard@com.example', email='richard@com.example')
138         t('r@a.com', email='r@a.com')
139         t('i1', **{'class':'i', 'id':'1'})
140         t('item123', **{'class':'item', 'id':'123'})
141         t('www.user:pass@host.net', email='pass@host.net')
142         t('user:pass@www.host.net', url='user:pass@www.host.net')
143         t('123.35', nothing=True)
144         t('-.3535', nothing=True)
146     def test_url_replace(self):
147         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', '')
148         def t(s): return p.hyper_re.sub(p._hyper_repl, s)
149         ae = self.assertEqual
150         ae(t('item123123123123'), 'item123123123123')
151         ae(t('http://roundup.net/'),
152            '<a href="http://roundup.net/">http://roundup.net/</a>')
153         ae(t('&lt;HTTP://roundup.net/&gt;'),
154            '&lt;<a href="HTTP://roundup.net/">HTTP://roundup.net/</a>&gt;')
155         ae(t('&lt;http://roundup.net/&gt;.'),
156             '&lt;<a href="http://roundup.net/">http://roundup.net/</a>&gt;.')
157         ae(t('&lt;www.roundup.net&gt;'),
158            '&lt;<a href="http://www.roundup.net">www.roundup.net</a>&gt;')
159         ae(t('(www.roundup.net)'),
160            '(<a href="http://www.roundup.net">www.roundup.net</a>)')
161         ae(t('foo http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx bar'),
162            'foo <a href="http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx">'
163            'http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx</a> bar')
164         ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language))'),
165            '(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)">'
166            'http://en.wikipedia.org/wiki/Python_(programming_language)</a>)')
167         ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language)).'),
168            '(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)">'
169            'http://en.wikipedia.org/wiki/Python_(programming_language)</a>).')
170         ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language))&gt;.'),
171            '(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)">'
172            'http://en.wikipedia.org/wiki/Python_(programming_language)</a>)&gt;.')
173         ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language&gt;)).'),
174            '(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language">'
175            'http://en.wikipedia.org/wiki/Python_(programming_language</a>&gt;)).')
177 '''
178 class HTMLPermissions:
179     def is_edit_ok(self):
180     def is_view_ok(self):
181     def is_only_view_ok(self):
182     def view_check(self):
183     def edit_check(self):
185 def input_html4(**attrs):
186 def input_xhtml(**attrs):
188 class HTMLInputMixin:
189     def __init__(self):
191 class HTMLClass(HTMLInputMixin, HTMLPermissions):
192     def __init__(self, client, classname, anonymous=0):
193     def __repr__(self):
194     def __getitem__(self, item):
195     def __getattr__(self, attr):
196     def designator(self):
197     def getItem(self, itemid, num_re=re.compile('-?\d+')):
198     def properties(self, sort=1):
199     def list(self, sort_on=None):
200     def csv(self):
201     def propnames(self):
202     def filter(self, request=None, filterspec={}, sort=(None,None),
203     def classhelp(self, properties=None, label='(list)', width='500',
204     def submit(self, label="Submit New Entry"):
205     def history(self):
206     def renderWith(self, name, **kwargs):
208 class HTMLItem(HTMLInputMixin, HTMLPermissions):
209     def __init__(self, client, classname, nodeid, anonymous=0):
210     def __repr__(self):
211     def __getitem__(self, item):
212     def __getattr__(self, attr):
213     def designator(self):
214     def is_retired(self):
215     def submit(self, label="Submit Changes"):
216     def journal(self, direction='descending'):
217     def history(self, direction='descending', dre=re.compile('\d+')):
218     def renderQueryForm(self):
220 class HTMLUserPermission:
221     def is_edit_ok(self):
222     def is_view_ok(self):
223     def _user_perm_check(self, type):
225 class HTMLUserClass(HTMLUserPermission, HTMLClass):
227 class HTMLUser(HTMLUserPermission, HTMLItem):
228     def __init__(self, client, classname, nodeid, anonymous=0):
229     def hasPermission(self, permission, classname=_marker):
231 class HTMLProperty(HTMLInputMixin, HTMLPermissions):
232     def __init__(self, client, classname, nodeid, prop, name, value,
233     def __repr__(self):
234     def __str__(self):
235     def __cmp__(self, other):
236     def is_edit_ok(self):
237     def is_view_ok(self):
239 class StringHTMLProperty(HTMLProperty):
240     def _hyper_repl(self, match):
241     def hyperlinked(self):
242     def plain(self, escape=0, hyperlink=0):
243     def stext(self, escape=0):
244     def field(self, size = 30):
245     def multiline(self, escape=0, rows=5, cols=40):
246     def email(self, escape=1):
248 class PasswordHTMLProperty(HTMLProperty):
249     def plain(self):
250     def field(self, size = 30):
251     def confirm(self, size = 30):
253 class NumberHTMLProperty(HTMLProperty):
254     def plain(self):
255     def field(self, size = 30):
256     def __int__(self):
257     def __float__(self):
259 class BooleanHTMLProperty(HTMLProperty):
260     def plain(self):
261     def field(self):
263 class DateHTMLProperty(HTMLProperty):
264     def plain(self):
265     def now(self):
266     def field(self, size = 30):
267     def reldate(self, pretty=1):
268     def pretty(self, format=_marker):
269     def local(self, offset):
271 class IntervalHTMLProperty(HTMLProperty):
272     def plain(self):
273     def pretty(self):
274     def field(self, size = 30):
276 class LinkHTMLProperty(HTMLProperty):
277     def __init__(self, *args, **kw):
278     def __getattr__(self, attr):
279     def plain(self, escape=0):
280     def field(self, showid=0, size=None):
281     def menu(self, size=None, height=None, showid=0, additional=[],
283 class MultilinkHTMLProperty(HTMLProperty):
284     def __init__(self, *args, **kwargs):
285     def __len__(self):
286     def __getattr__(self, attr):
287     def __getitem__(self, num):
288     def __contains__(self, value):
289     def reverse(self):
290     def plain(self, escape=0):
291     def field(self, size=30, showid=0):
292     def menu(self, size=None, height=None, showid=0, additional=[],
294 def make_sort_function(db, classname, sort_on=None):
295     def sortfunc(a, b):
297 def find_sort_key(linkcl):
299 def handleListCGIValue(value):
301 class ShowDict:
302     def __init__(self, columns):
303     def __getitem__(self, name):
305 class HTMLRequest(HTMLInputMixin):
306     def __init__(self, client):
307     def _post_init(self):
308     def updateFromURL(self, url):
309     def update(self, kwargs):
310     def description(self):
311     def __str__(self):
312     def indexargs_form(self, columns=1, sort=1, group=1, filter=1,
313     def indexargs_url(self, url, args):
314     def base_javascript(self):
315     def batch(self):
317 class Batch(ZTUtils.Batch):
318     def __init__(self, client, sequence, size, start, end=0, orphan=0,
319     def __getitem__(self, index):
320     def propchanged(self, property):
321     def previous(self):
322     def next(self):
324 class TemplatingUtils:
325     def __init__(self, client):
326     def Batch(self, sequence, size, start, end=0, orphan=0, overlap=0):
328 class NoTemplate(Exception):
329 class Unauthorised(Exception):
330     def __init__(self, action, klass):
331     def __str__(self):
332 def find_template(dir, name, extension):
334 class Templates:
335     def __init__(self, dir):
336     def precompileTemplates(self):
337     def get(self, name, extension=None):
338     def __getitem__(self, name):
340 class RoundupPageTemplate(PageTemplate.PageTemplate):
341     def getContext(self, client, classname, request):
342     def render(self, client, classname, request, **options):
343     def __repr__(self):
344 '''
347 def test_suite():
348     suite = unittest.TestSuite()
349     suite.addTest(unittest.makeSuite(HTMLDatabaseTestCase))
350     suite.addTest(unittest.makeSuite(FunctionsTestCase))
351     suite.addTest(unittest.makeSuite(HTMLClassTestCase))
352     return suite
354 if __name__ == '__main__':
355     runner = unittest.TextTestRunner()
356     unittest.main(testRunner=runner)
358 # vim: set et sts=4 sw=4 :