Skip to content

Commit 62f6e96

Browse files
author
Richard Jones
committed
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.
1 parent 3932ea2 commit 62f6e96

File tree

4 files changed

+172
-60
lines changed

4 files changed

+172
-60
lines changed

CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Feature:
1212
. modified unit test to check nosy and assignedto when specified as
1313
arguments
1414
. you can now use the roundup-admin tool pack the database
15+
. unit tests for html templating (and re-enabled the listbox field for
16+
multilinks)
1517

1618
Fixed:
1719
. handle attachments with no name (eg tnef)

roundup/htmltemplate.py

Lines changed: 91 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: htmltemplate.py,v 1.64 2002-01-21 03:25:59 richard Exp $
18+
# $Id: htmltemplate.py,v 1.65 2002-01-22 00:12:06 richard Exp $
1919

2020
__doc__ = """
2121
Template engine.
@@ -109,62 +109,82 @@ def do_stext(self, property, escape=0):
109109
return s
110110
return StructuredText(s,level=1,header=0)
111111

112-
def do_field(self, property, size=None, height=None, showid=0):
113-
''' display a property like the plain displayer, but in a text field
114-
to be edited
112+
def determine_value(self, property):
113+
'''determine the value of a property using the node, form or
114+
filterspec
115115
'''
116-
if not self.nodeid and self.form is None and self.filterspec is None:
117-
return _('[Field: not called from item]')
118116
propclass = self.properties[property]
119-
if (isinstance(propclass, hyperdb.Link) or
120-
isinstance(propclass, hyperdb.Multilink)):
121-
linkcl = self.db.classes[propclass.classname]
122-
def sortfunc(a, b, cl=linkcl):
123-
if cl.getprops().has_key('order'):
124-
sort_on = 'order'
125-
else:
126-
sort_on = cl.labelprop()
127-
r = cmp(cl.get(a, sort_on), cl.get(b, sort_on))
128-
return r
129117
if self.nodeid:
130118
value = self.cl.get(self.nodeid, property, None)
131-
# TODO: remove this from the code ... it's only here for
132-
# handling schema changes, and they should be handled outside
133-
# of this code...
134119
if isinstance(propclass, hyperdb.Multilink) and value is None:
135-
value = []
120+
return []
121+
return value
136122
elif self.filterspec is not None:
137123
if isinstance(propclass, hyperdb.Multilink):
138-
value = self.filterspec.get(property, [])
124+
return self.filterspec.get(property, [])
139125
else:
140-
value = self.filterspec.get(property, '')
126+
return self.filterspec.get(property, '')
127+
# TODO: pull the value from the form
128+
if isinstance(propclass, hyperdb.Multilink):
129+
return []
141130
else:
142-
# TODO: pull the value from the form
143-
if isinstance(propclass, hyperdb.Multilink): value = []
144-
else: value = ''
131+
return ''
132+
133+
def make_sort_function(self, classname):
134+
'''Make a sort function for a given class
135+
'''
136+
linkcl = self.db.classes[classname]
137+
if linkcl.getprops().has_key('order'):
138+
sort_on = 'order'
139+
else:
140+
sort_on = linkcl.labelprop()
141+
def sortfunc(a, b, linkcl=linkcl, sort_on=sort_on):
142+
return cmp(linkcl.get(a, sort_on), linkcl.get(b, sort_on))
143+
return sortfunc
144+
145+
def do_field(self, property, size=None, showid=0):
146+
''' display a property like the plain displayer, but in a text field
147+
to be edited
148+
149+
Note: if you would prefer an option list style display for
150+
link or multilink editing, use menu().
151+
'''
152+
if not self.nodeid and self.form is None and self.filterspec is None:
153+
return _('[Field: not called from item]')
154+
155+
if size is None:
156+
size = 30
157+
158+
propclass = self.properties[property]
159+
160+
# get the value
161+
value = self.determine_value(property)
162+
163+
# now display
145164
if (isinstance(propclass, hyperdb.String) or
146165
isinstance(propclass, hyperdb.Date) or
147166
isinstance(propclass, hyperdb.Interval)):
148-
size = size or 30
149167
if value is None:
150168
value = ''
151169
else:
152170
value = cgi.escape(str(value))
153171
value = '"'.join(value.split('"'))
154172
s = '<input name="%s" value="%s" size="%s">'%(property, value, size)
155173
elif isinstance(propclass, hyperdb.Password):
156-
size = size or 30
157174
s = '<input type="password" name="%s" size="%s">'%(property, size)
158175
elif isinstance(propclass, hyperdb.Link):
176+
sortfunc = self.make_sort_function(propclass.classname)
177+
linkcl = self.db.classes[propclass.classname]
178+
options = linkcl.list()
179+
options.sort(sortfunc)
180+
# TODO: make this a field display, not a menu one!
159181
l = ['<select name="%s">'%property]
160182
k = linkcl.labelprop()
161183
if value is None:
162184
s = 'selected '
163185
else:
164186
s = ''
165187
l.append(_('<option %svalue="-1">- no selection -</option>')%s)
166-
options = linkcl.list()
167-
options.sort(sortfunc)
168188
for optionid in options:
169189
option = linkcl.get(optionid, k)
170190
s = ''
@@ -176,37 +196,46 @@ def sortfunc(a, b, cl=linkcl):
176196
lab = option
177197
if size is not None and len(lab) > size:
178198
lab = lab[:size-3] + '...'
199+
lab = cgi.escape(lab)
179200
l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab))
180201
l.append('</select>')
181202
s = '\n'.join(l)
182203
elif isinstance(propclass, hyperdb.Multilink):
204+
sortfunc = self.make_sort_function(propclass.classname)
205+
linkcl = self.db.classes[propclass.classname]
183206
list = linkcl.list()
184207
list.sort(sortfunc)
185208
l = []
186209
# map the id to the label property
187-
# TODO: allow reversion to the older <select> box style display
188210
if not showid:
189211
k = linkcl.labelprop()
190212
value = [linkcl.get(v, k) for v in value]
191-
if size is None:
192-
size = '10'
193-
l.insert(0,'<input name="%s" size="%s" value="%s">'%(property,
194-
size, ','.join(value)))
195-
s = "<br>\n".join(l)
213+
value = cgi.escape(','.join(value))
214+
s = '<input name="%s" size="%s" value="%s">'%(property, size, value)
196215
else:
197216
s = _('Plain: bad propclass "%(propclass)s"')%locals()
198217
return s
199218

200219
def do_menu(self, property, size=None, height=None, showid=0):
201220
''' for a Link property, display a menu of the available choices
202221
'''
222+
if not self.nodeid and self.form is None and self.filterspec is None:
223+
return _('[Field: not called from item]')
224+
203225
propclass = self.properties[property]
204-
if self.nodeid:
205-
value = self.cl.get(self.nodeid, property)
206-
else:
207-
# TODO: pull the value from the form
208-
if isinstance(propclass, hyperdb.Multilink): value = []
209-
else: value = None
226+
227+
# make sure this is a link property
228+
if not (isinstance(propclass, hyperdb.Link) or
229+
isinstance(propclass, hyperdb.Multilink)):
230+
return _('[Menu: not a link]')
231+
232+
# sort function
233+
sortfunc = self.make_sort_function(propclass.classname)
234+
235+
# get the value
236+
value = self.determine_value(property)
237+
238+
# display
210239
if isinstance(propclass, hyperdb.Link):
211240
linkcl = self.db.classes[propclass.classname]
212241
l = ['<select name="%s">'%property]
@@ -215,21 +244,31 @@ def do_menu(self, property, size=None, height=None, showid=0):
215244
if value is None:
216245
s = 'selected '
217246
l.append(_('<option %svalue="-1">- no selection -</option>')%s)
218-
for optionid in linkcl.list():
247+
options = linkcl.list()
248+
options.sort(sortfunc)
249+
for optionid in options:
219250
option = linkcl.get(optionid, k)
220251
s = ''
221252
if optionid == value:
222253
s = 'selected '
223-
l.append('<option %svalue="%s">%s</option>'%(s, optionid, option))
254+
if showid:
255+
lab = '%s%s: %s'%(propclass.classname, optionid, option)
256+
else:
257+
lab = option
258+
if size is not None and len(lab) > size:
259+
lab = lab[:size-3] + '...'
260+
lab = cgi.escape(lab)
261+
l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab))
224262
l.append('</select>')
225263
return '\n'.join(l)
226264
if isinstance(propclass, hyperdb.Multilink):
227265
linkcl = self.db.classes[propclass.classname]
228-
list = linkcl.list()
229-
height = height or min(len(list), 7)
266+
options = linkcl.list()
267+
options.sort(sortfunc)
268+
height = height or min(len(options), 7)
230269
l = ['<select multiple name="%s" size="%s">'%(property, height)]
231270
k = linkcl.labelprop()
232-
for optionid in list:
271+
for optionid in options:
233272
option = linkcl.get(optionid, k)
234273
s = ''
235274
if optionid in value:
@@ -240,7 +279,9 @@ def do_menu(self, property, size=None, height=None, showid=0):
240279
lab = option
241280
if size is not None and len(lab) > size:
242281
lab = lab[:size-3] + '...'
243-
l.append('<option %svalue="%s">%s</option>'%(s, optionid, option))
282+
lab = cgi.escape(lab)
283+
l.append('<option %svalue="%s">%s</option>'%(s, optionid,
284+
lab))
244285
l.append('</select>')
245286
return '\n'.join(l)
246287
return _('[Menu: not a link]')
@@ -1002,6 +1043,9 @@ def render(self, form):
10021043

10031044
#
10041045
# $Log: not supported by cvs2svn $
1046+
# Revision 1.64 2002/01/21 03:25:59 richard
1047+
# oops
1048+
#
10051049
# Revision 1.63 2002/01/21 02:59:10 richard
10061050
# Fixed up the HTML display of history so valid links are actually displayed.
10071051
# Oh for some unit tests! :(

test/__init__.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: __init__.py,v 1.13 2002-01-21 11:05:48 richard Exp $
18+
# $Id: __init__.py,v 1.14 2002-01-22 00:12:06 richard Exp $
1919

2020
import unittest
2121
import os, tempfile
@@ -26,14 +26,14 @@
2626

2727
def go():
2828
suite = unittest.TestSuite((
29-
test_dates.suite(),
30-
test_schema.suite(),
31-
test_db.suite(),
32-
test_init.suite(),
33-
test_multipart.suite(),
34-
test_mailsplit.suite(),
35-
test_mailgw.suite(),
36-
test_token.suite(),
29+
# test_dates.suite(),
30+
# test_schema.suite(),
31+
# test_db.suite(),
32+
# test_init.suite(),
33+
# test_multipart.suite(),
34+
# test_mailsplit.suite(),
35+
# test_mailgw.suite(),
36+
# test_token.suite(),
3737
test_htmltemplate.suite(),
3838
))
3939
runner = unittest.TextTestRunner()
@@ -42,6 +42,9 @@ def go():
4242

4343
#
4444
# $Log: not supported by cvs2svn $
45+
# Revision 1.13 2002/01/21 11:05:48 richard
46+
# New tests for htmltemplate (well, it's a beginning)
47+
#
4548
# Revision 1.12 2002/01/14 06:53:28 richard
4649
# had commented out some tests
4750
#

0 commit comments

Comments
 (0)