Mercurial > p > roundup > code
changeset 563:0f58d6a35a8b
Wrote more unit tests for htmltemplate...
...and while I was at it, I polished off the implementation of some of
the functions so they behave sanely.
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Tue, 22 Jan 2002 00:12:07 +0000 |
| parents | 62febbd7ffec |
| children | 6f45494f84af |
| files | CHANGES.txt roundup/htmltemplate.py test/__init__.py test/test_htmltemplate.py |
| diffstat | 4 files changed, 203 insertions(+), 91 deletions(-) [+] |
line wrap: on
line diff
--- a/CHANGES.txt Mon Jan 21 16:33:20 2002 +0000 +++ b/CHANGES.txt Tue Jan 22 00:12:07 2002 +0000 @@ -12,6 +12,8 @@ . modified unit test to check nosy and assignedto when specified as arguments . you can now use the roundup-admin tool pack the database + . unit tests for html templating (and re-enabled the listbox field for + multilinks) Fixed: . handle attachments with no name (eg tnef)
--- a/roundup/htmltemplate.py Mon Jan 21 16:33:20 2002 +0000 +++ b/roundup/htmltemplate.py Tue Jan 22 00:12:07 2002 +0000 @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: htmltemplate.py,v 1.64 2002-01-21 03:25:59 richard Exp $ +# $Id: htmltemplate.py,v 1.65 2002-01-22 00:12:06 richard Exp $ __doc__ = """ Template engine. @@ -109,43 +109,61 @@ return s return StructuredText(s,level=1,header=0) - def do_field(self, property, size=None, height=None, showid=0): + def determine_value(self, property): + '''determine the value of a property using the node, form or + filterspec + ''' + propclass = self.properties[property] + if self.nodeid: + value = self.cl.get(self.nodeid, property, None) + if isinstance(propclass, hyperdb.Multilink) and value is None: + return [] + return value + elif self.filterspec is not None: + if isinstance(propclass, hyperdb.Multilink): + return self.filterspec.get(property, []) + else: + return self.filterspec.get(property, '') + # TODO: pull the value from the form + if isinstance(propclass, hyperdb.Multilink): + return [] + else: + return '' + + def make_sort_function(self, classname): + '''Make a sort function for a given class + ''' + linkcl = self.db.classes[classname] + if linkcl.getprops().has_key('order'): + sort_on = 'order' + else: + sort_on = linkcl.labelprop() + def sortfunc(a, b, linkcl=linkcl, sort_on=sort_on): + return cmp(linkcl.get(a, sort_on), linkcl.get(b, sort_on)) + return sortfunc + + def do_field(self, property, size=None, showid=0): ''' display a property like the plain displayer, but in a text field to be edited + + Note: if you would prefer an option list style display for + link or multilink editing, use menu(). ''' if not self.nodeid and self.form is None and self.filterspec is None: return _('[Field: not called from item]') + + if size is None: + size = 30 + propclass = self.properties[property] - if (isinstance(propclass, hyperdb.Link) or - isinstance(propclass, hyperdb.Multilink)): - linkcl = self.db.classes[propclass.classname] - def sortfunc(a, b, cl=linkcl): - if cl.getprops().has_key('order'): - sort_on = 'order' - else: - sort_on = cl.labelprop() - r = cmp(cl.get(a, sort_on), cl.get(b, sort_on)) - return r - if self.nodeid: - value = self.cl.get(self.nodeid, property, None) - # TODO: remove this from the code ... it's only here for - # handling schema changes, and they should be handled outside - # of this code... - if isinstance(propclass, hyperdb.Multilink) and value is None: - value = [] - elif self.filterspec is not None: - if isinstance(propclass, hyperdb.Multilink): - value = self.filterspec.get(property, []) - else: - value = self.filterspec.get(property, '') - else: - # TODO: pull the value from the form - if isinstance(propclass, hyperdb.Multilink): value = [] - else: value = '' + + # get the value + value = self.determine_value(property) + + # now display if (isinstance(propclass, hyperdb.String) or isinstance(propclass, hyperdb.Date) or isinstance(propclass, hyperdb.Interval)): - size = size or 30 if value is None: value = '' else: @@ -153,9 +171,13 @@ value = '"'.join(value.split('"')) s = '<input name="%s" value="%s" size="%s">'%(property, value, size) elif isinstance(propclass, hyperdb.Password): - size = size or 30 s = '<input type="password" name="%s" size="%s">'%(property, size) elif isinstance(propclass, hyperdb.Link): + sortfunc = self.make_sort_function(propclass.classname) + linkcl = self.db.classes[propclass.classname] + options = linkcl.list() + options.sort(sortfunc) + # TODO: make this a field display, not a menu one! l = ['<select name="%s">'%property] k = linkcl.labelprop() if value is None: @@ -163,6 +185,65 @@ else: s = '' l.append(_('<option %svalue="-1">- no selection -</option>')%s) + for optionid in options: + option = linkcl.get(optionid, k) + s = '' + if optionid == value: + s = 'selected ' + if showid: + lab = '%s%s: %s'%(propclass.classname, optionid, option) + else: + lab = option + if size is not None and len(lab) > size: + lab = lab[:size-3] + '...' + lab = cgi.escape(lab) + l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab)) + l.append('</select>') + s = '\n'.join(l) + elif isinstance(propclass, hyperdb.Multilink): + sortfunc = self.make_sort_function(propclass.classname) + linkcl = self.db.classes[propclass.classname] + list = linkcl.list() + list.sort(sortfunc) + l = [] + # map the id to the label property + if not showid: + k = linkcl.labelprop() + value = [linkcl.get(v, k) for v in value] + value = cgi.escape(','.join(value)) + s = '<input name="%s" size="%s" value="%s">'%(property, size, value) + else: + s = _('Plain: bad propclass "%(propclass)s"')%locals() + return s + + def do_menu(self, property, size=None, height=None, showid=0): + ''' for a Link property, display a menu of the available choices + ''' + if not self.nodeid and self.form is None and self.filterspec is None: + return _('[Field: not called from item]') + + propclass = self.properties[property] + + # make sure this is a link property + if not (isinstance(propclass, hyperdb.Link) or + isinstance(propclass, hyperdb.Multilink)): + return _('[Menu: not a link]') + + # sort function + sortfunc = self.make_sort_function(propclass.classname) + + # get the value + value = self.determine_value(property) + + # display + if isinstance(propclass, hyperdb.Link): + linkcl = self.db.classes[propclass.classname] + l = ['<select name="%s">'%property] + k = linkcl.labelprop() + s = '' + if value is None: + s = 'selected ' + l.append(_('<option %svalue="-1">- no selection -</option>')%s) options = linkcl.list() options.sort(sortfunc) for optionid in options: @@ -176,60 +257,18 @@ lab = option if size is not None and len(lab) > size: lab = lab[:size-3] + '...' + lab = cgi.escape(lab) l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab)) l.append('</select>') - s = '\n'.join(l) - elif isinstance(propclass, hyperdb.Multilink): - list = linkcl.list() - list.sort(sortfunc) - l = [] - # map the id to the label property - # TODO: allow reversion to the older <select> box style display - if not showid: - k = linkcl.labelprop() - value = [linkcl.get(v, k) for v in value] - if size is None: - size = '10' - l.insert(0,'<input name="%s" size="%s" value="%s">'%(property, - size, ','.join(value))) - s = "<br>\n".join(l) - else: - s = _('Plain: bad propclass "%(propclass)s"')%locals() - return s - - def do_menu(self, property, size=None, height=None, showid=0): - ''' for a Link property, display a menu of the available choices - ''' - propclass = self.properties[property] - if self.nodeid: - value = self.cl.get(self.nodeid, property) - else: - # TODO: pull the value from the form - if isinstance(propclass, hyperdb.Multilink): value = [] - else: value = None - if isinstance(propclass, hyperdb.Link): - linkcl = self.db.classes[propclass.classname] - l = ['<select name="%s">'%property] - k = linkcl.labelprop() - s = '' - if value is None: - s = 'selected ' - l.append(_('<option %svalue="-1">- no selection -</option>')%s) - for optionid in linkcl.list(): - option = linkcl.get(optionid, k) - s = '' - if optionid == value: - s = 'selected ' - l.append('<option %svalue="%s">%s</option>'%(s, optionid, option)) - l.append('</select>') return '\n'.join(l) if isinstance(propclass, hyperdb.Multilink): linkcl = self.db.classes[propclass.classname] - list = linkcl.list() - height = height or min(len(list), 7) + options = linkcl.list() + options.sort(sortfunc) + height = height or min(len(options), 7) l = ['<select multiple name="%s" size="%s">'%(property, height)] k = linkcl.labelprop() - for optionid in list: + for optionid in options: option = linkcl.get(optionid, k) s = '' if optionid in value: @@ -240,7 +279,9 @@ lab = option if size is not None and len(lab) > size: lab = lab[:size-3] + '...' - l.append('<option %svalue="%s">%s</option>'%(s, optionid, option)) + lab = cgi.escape(lab) + l.append('<option %svalue="%s">%s</option>'%(s, optionid, + lab)) l.append('</select>') return '\n'.join(l) return _('[Menu: not a link]') @@ -1002,6 +1043,9 @@ # # $Log: not supported by cvs2svn $ +# Revision 1.64 2002/01/21 03:25:59 richard +# oops +# # Revision 1.63 2002/01/21 02:59:10 richard # Fixed up the HTML display of history so valid links are actually displayed. # Oh for some unit tests! :(
--- a/test/__init__.py Mon Jan 21 16:33:20 2002 +0000 +++ b/test/__init__.py Tue Jan 22 00:12:07 2002 +0000 @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: __init__.py,v 1.13 2002-01-21 11:05:48 richard Exp $ +# $Id: __init__.py,v 1.14 2002-01-22 00:12:06 richard Exp $ import unittest import os, tempfile @@ -26,14 +26,14 @@ def go(): suite = unittest.TestSuite(( - test_dates.suite(), - test_schema.suite(), - test_db.suite(), - test_init.suite(), - test_multipart.suite(), - test_mailsplit.suite(), - test_mailgw.suite(), - test_token.suite(), +# test_dates.suite(), +# test_schema.suite(), +# test_db.suite(), +# test_init.suite(), +# test_multipart.suite(), +# test_mailsplit.suite(), +# test_mailgw.suite(), +# test_token.suite(), test_htmltemplate.suite(), )) runner = unittest.TextTestRunner() @@ -42,6 +42,9 @@ # # $Log: not supported by cvs2svn $ +# Revision 1.13 2002/01/21 11:05:48 richard +# New tests for htmltemplate (well, it's a beginning) +# # Revision 1.12 2002/01/14 06:53:28 richard # had commented out some tests #
--- a/test/test_htmltemplate.py Mon Jan 21 16:33:20 2002 +0000 +++ b/test/test_htmltemplate.py Tue Jan 22 00:12:07 2002 +0000 @@ -8,13 +8,14 @@ # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # -# $Id: test_htmltemplate.py,v 1.1 2002-01-21 11:05:48 richard Exp $ +# $Id: test_htmltemplate.py,v 1.2 2002-01-22 00:12:07 richard Exp $ import unittest, cgi from roundup.htmltemplate import TemplateFunctions from roundup import date -from roundup.hyperdb import String, Date, Interval, Link, Multilink +from roundup import password +from roundup.hyperdb import String, Password, Date, Interval, Link, Multilink class Class: def get(self, nodeid, attribute, default=None): @@ -28,6 +29,8 @@ return '1' elif attribute == 'multilink': return ['1', '2'] + elif attribute == 'password': + return password.Password('sekrit') elif attribute == 'key': return 'the key' elif attribute == 'html': @@ -37,7 +40,7 @@ def getprops(self): return {'string': String(), 'date': Date(), 'interval': Interval(), 'link': Link('other'), 'multilink': Multilink('other'), - 'html': String(), 'key': String()} + 'password': Password(), 'html': String(), 'key': String()} def labelprop(self): return 'key' @@ -63,6 +66,9 @@ s = 'Node 1: I am a string' self.assertEqual(self.tf.do_plain('string'), s) + def testPlain_password(self): + self.assertEqual(self.tf.do_plain('password'), '*encrypted*') + def testPlain_html(self): s = '<html>hello, I am HTML</html>' self.assertEqual(self.tf.do_plain('html', escape=0), s) @@ -82,22 +88,37 @@ self.assertEqual(self.tf.do_plain('multilink'), '1, 2') -# def do_field(self, property, size=None, height=None, showid=0): +# def do_field(self, property, size=None, showid=0): def testField_string(self): self.assertEqual(self.tf.do_field('string'), '<input name="string" value="Node 1: I am a string" size="30">') + self.assertEqual(self.tf.do_field('string', size=10), + '<input name="string" value="Node 1: I am a string" size="10">') + + def testField_password(self): + self.assertEqual(self.tf.do_field('password'), + '<input type="password" name="password" size="30">') + self.assertEqual(self.tf.do_field('password', size=10), + '<input type="password" name="password" size="10">') def testField_html(self): self.assertEqual(self.tf.do_field('html'), '<input name="html" ' 'value="<html>hello, I am HTML</html>" size="30">') + self.assertEqual(self.tf.do_field('html', size=10), + '<input name="html" value="<html>hello, I am ' + 'HTML</html>" size="10">') def testField_date(self): self.assertEqual(self.tf.do_field('date'), '<input name="date" value="2000-01-01.00:00:00" size="30">') + self.assertEqual(self.tf.do_field('date', size=10), + '<input name="date" value="2000-01-01.00:00:00" size="10">') def testField_interval(self): self.assertEqual(self.tf.do_field('interval'), '<input name="interval" value="- 3d" size="30">') + self.assertEqual(self.tf.do_field('interval', size=10), + '<input name="interval" value="- 3d" size="10">') def testField_link(self): self.assertEqual(self.tf.do_field('link'), '''<select name="link"> @@ -108,14 +129,56 @@ def testField_multilink(self): self.assertEqual(self.tf.do_field('multilink'), + '<input name="multilink" size="30" value="the key,the key">') + self.assertEqual(self.tf.do_field('multilink', size=10), '<input name="multilink" size="10" value="the key,the key">') +# def do_menu(self, property, size=None, height=None, showid=0): + def testMenu_link(self): + self.assertEqual(self.tf.do_menu('link'), '''<select name="link"> +<option value="-1">- no selection -</option> +<option selected value="1">the key</option> +<option value="2">the key</option> +</select>''') + self.assertEqual(self.tf.do_menu('link', size=6), + '''<select name="link"> +<option value="-1">- no selection -</option> +<option selected value="1">the...</option> +<option value="2">the...</option> +</select>''') + self.assertEqual(self.tf.do_menu('link', showid=1), + '''<select name="link"> +<option value="-1">- no selection -</option> +<option selected value="1">other1: the key</option> +<option value="2">other2: the key</option> +</select>''') + + def testMenu_multilink(self): + self.assertEqual(self.tf.do_menu('multilink', height=10), + '''<select multiple name="multilink" size="10"> +<option selected value="1">the key</option> +<option selected value="2">the key</option> +</select>''') + self.assertEqual(self.tf.do_menu('multilink', size=6, height=10), + '''<select multiple name="multilink" size="10"> +<option selected value="1">the...</option> +<option selected value="2">the...</option> +</select>''') + self.assertEqual(self.tf.do_menu('multilink', showid=1), + '''<select multiple name="multilink" size="2"> +<option selected value="1">other1: the key</option> +<option selected value="2">other2: the key</option> +</select>''') + def suite(): return unittest.makeSuite(NodeCase, 'test') # # $Log: not supported by cvs2svn $ +# Revision 1.1 2002/01/21 11:05:48 richard +# New tests for htmltemplate (well, it's a beginning) +# # # # vim: set filetype=python ts=4 sw=4 et si
