summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: ad99119)
raw | patch | inline | side by side (parent: ad99119)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Tue, 11 Nov 2003 00:35:14 +0000 (00:35 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Tue, 11 Nov 2003 00:35:14 +0000 (00:35 +0000) |
bug #817217, rfe #816994)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1974 57a73879-2fb5-44c3-a270-3262357dd7e2
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1974 57a73879-2fb5-44c3-a270-3262357dd7e2
CHANGES.txt | patch | blob | history | |
roundup/admin.py | patch | blob | history | |
roundup/cgi/client.py | patch | blob | history | |
roundup/hyperdb.py | patch | blob | history | |
roundup/mailgw.py | patch | blob | history | |
roundup/password.py | patch | blob | history | |
test/test_hyperdbvals.py | [new file with mode: 0644] | patch | blob |
test/test_mailgw.py | patch | blob | history |
diff --git a/CHANGES.txt b/CHANGES.txt
index ee5818e194139e9850bfa32b804c0b8f15ceb8a5..fed3b7593c5c94d1fcb6a7cdf93763611ca10ee3 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
- Date arithmetic was utterly broken, and has been for a long time.
Date +/- Interval now works, and Date - Date also works (produces
an Interval.
+- Centralised conversion of user-input data to hyperdb values (bug #802405,
+ bug #817217, rfe #816994)
Cleanup:
- Replace curuserid attribute on Database with the extended getuid() method.
diff --git a/roundup/admin.py b/roundup/admin.py
index 413509a61db7e280d044e4216366c036158d61c6..107e639b0c0774e099bccf3b0d5d99dd0d01eee4 100644 (file)
--- a/roundup/admin.py
+++ b/roundup/admin.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: admin.py,v 1.59 2003-10-24 19:48:05 jlgijsbers Exp $
+# $Id: admin.py,v 1.60 2003-11-11 00:35:13 richard Exp $
'''Administration commands for maintaining Roundup trackers.
'''
properties = cl.getprops()
for key, value in props.items():
- proptype = properties[key]
- if isinstance(proptype, hyperdb.Multilink):
- if value is None:
- props[key] = []
- else:
- props[key] = value.split(',')
- elif value is None:
- continue
- elif isinstance(proptype, hyperdb.String):
- continue
- elif isinstance(proptype, hyperdb.Password):
- m = pwre.match(value)
- if m:
- # password is being given to us encrypted
- p = password.Password()
- p.scheme = m.group(1)
- p.password = m.group(2)
- props[key] = p
- else:
- props[key] = password.Password(value)
- elif isinstance(proptype, hyperdb.Date):
- try:
- props[key] = date.Date(value)
- except ValueError, message:
- raise UsageError, '"%s": %s'%(value, message)
- elif isinstance(proptype, hyperdb.Interval):
- try:
- props[key] = date.Interval(value)
- except ValueError, message:
- raise UsageError, '"%s": %s'%(value, message)
- elif isinstance(proptype, hyperdb.Link):
- props[key] = value
- elif isinstance(proptype, hyperdb.Boolean):
- props[key] = value.lower() in ('yes', 'true', 'on', '1')
- elif isinstance(proptype, hyperdb.Number):
- props[key] = float(value)
+ try:
+ props[key] = hyperdb.rawToHyperdb(self.db, cl, itemid,
+ key, value)
+ except hyperdb.HyperdbValueError, message:
+ raise UsageError, message
# try the set
try:
# convert types
for propname, value in props.items():
- # get the property
try:
- proptype = properties[propname]
- except KeyError:
- raise UsageError, _('%(classname)s has no property '
- '"%(propname)s"')%locals()
-
- if isinstance(proptype, hyperdb.Date):
- try:
- props[propname] = date.Date(value)
- except ValueError, message:
- raise UsageError, _('"%(value)s": %(message)s')%locals()
- elif isinstance(proptype, hyperdb.Interval):
- try:
- props[propname] = date.Interval(value)
- except ValueError, message:
- raise UsageError, _('"%(value)s": %(message)s')%locals()
- elif isinstance(proptype, hyperdb.Password):
- m = pwre.match(value)
- if m:
- # password is being given to us encrypted
- p = password.Password()
- p.scheme = m.group(1)
- p.password = m.group(2)
- props[propname] = p
- else:
- props[propname] = password.Password(value)
- elif isinstance(proptype, hyperdb.Multilink):
- props[propname] = value.split(',')
- elif isinstance(proptype, hyperdb.Boolean):
- props[propname] = value.lower() in ('yes', 'true', 'on', '1')
- elif isinstance(proptype, hyperdb.Number):
- props[propname] = float(value)
+ props[key] = hyperdb.rawToHyperdb(self.db, cl, None,
+ propname, value)
+ except hyperdb.HyperdbValueError, message:
+ raise UsageError, message
# check for the key property
propname = cl.getkey()
diff --git a/roundup/cgi/client.py b/roundup/cgi/client.py
index 72edc6fa02c092c2d04e218b4cf1a3be2c3ac714..5e581b08757c40e28ea987c74384e9522f49df62 100644 (file)
--- a/roundup/cgi/client.py
+++ b/roundup/cgi/client.py
-# $Id: client.py,v 1.143 2003-10-24 09:32:19 jlgijsbers Exp $
+# $Id: client.py,v 1.144 2003-11-11 00:35:14 richard Exp $
__doc__ = """
WWW request handler (also used in the stand-alone server).
if value != confirm.value:
raise FormError, 'Password and confirmation text do '\
'not match'
- value = password.Password(value)
-
- elif isinstance(proptype, hyperdb.Link):
- # see if it's the "no selection" choice
- if value == '-1' or not value:
- # if we're creating, just don't include this property
- if not nodeid or nodeid.startswith('-'):
- continue
- value = None
- else:
- # handle key values
- link = proptype.classname
- if not num_re.match(value):
- try:
- value = db.classes[link].lookup(value)
- except KeyError:
- raise FormError, _('property "%(propname)s": '
- '%(value)s not a %(classname)s')%{
- 'propname': propname, 'value': value,
- 'classname': link}
- except TypeError, message:
- raise FormError, _('you may only enter ID values '
- 'for property "%(propname)s": %(message)s')%{
- 'propname': propname, 'message': message}
+ try:
+ value = password.Password(value)
+ except hyperdb.HyperdbValueError, msg:
+ raise FormError, msg
+
elif isinstance(proptype, hyperdb.Multilink):
- # perform link class key value lookup if necessary
- link = proptype.classname
- link_cl = db.classes[link]
- l = []
- for entry in value:
- if not entry: continue
- if not num_re.match(entry):
- try:
- entry = link_cl.lookup(entry)
- except KeyError:
- raise FormError, _('property "%(propname)s": '
- '"%(value)s" not an entry of %(classname)s')%{
- 'propname': propname, 'value': entry,
- 'classname': link}
- except TypeError, message:
- raise FormError, _('you may only enter ID values '
- 'for property "%(propname)s": %(message)s')%{
- 'propname': propname, 'message': message}
- l.append(entry)
- l.sort()
+ # convert input to list of ids
+ try:
+ l = hyperdb.rawToHyperdb(self.db, cl, nodeid,
+ propname, value)
+ except hyperdb.HyperdbValueError, msg:
+ raise FormError, msg
# now use that list of ids to modify the multilink
if mlaction == 'set':
value.sort()
elif value == '':
- # if we're creating, just don't include this property
- if not nodeid or nodeid.startswith('-'):
- continue
# other types should be None'd if there's no value
value = None
else:
- # handle ValueErrors for all these in a similar fashion
+ # handle all other types
try:
if isinstance(proptype, hyperdb.String):
if (hasattr(value, 'filename') and
props['type'] = mimetypes.guess_type(fn)[0]
if not props['type']:
props['type'] = "application/octet-stream"
- # finally, read the content
+ # finally, read the content RAW
value = value.value
else:
- # normal String fix the CRLF/CR -> LF stuff
- value = fixNewlines(value)
+ value = hyperdb.rawToHyperdb(self.db, cl,
+ nodeid, propname, value)
- elif isinstance(proptype, hyperdb.Date):
- value = date.Date(value, offset=timezone)
- elif isinstance(proptype, hyperdb.Interval):
- value = date.Interval(value)
- elif isinstance(proptype, hyperdb.Boolean):
- value = value.lower() in ('yes', 'true', 'on', '1')
- elif isinstance(proptype, hyperdb.Number):
- value = float(value)
- except ValueError, msg:
- raise FormError, _('Error with %s property: %s')%(
- propname, msg)
+ else:
+ value = hyperdb.rawToHyperdb(self.db, cl, nodeid,
+ propname, value)
+ except hyperdb.HyperdbValueError, msg:
+ raise FormError, msg
# register that we got this property
if value:
raise FormError, _('File is empty')
return all_props, all_links
-def fixNewlines(text):
- ''' Homogenise line endings.
-
- Different web clients send different line ending values, but
- other systems (eg. email) don't necessarily handle those line
- endings. Our solution is to convert all line endings to LF.
- '''
- text = text.replace('\r\n', '\n')
- return text.replace('\r', '\n')
-
def extractFormList(value):
''' Extract a list of values from the form value.
diff --git a/roundup/hyperdb.py b/roundup/hyperdb.py
index 6a1c83108d97b2a0534a22e8c5893dffa86304cd..245b917d4105ee06f69a5b484540b268e3511445 100644 (file)
--- a/roundup/hyperdb.py
+++ b/roundup/hyperdb.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: hyperdb.py,v 1.90 2003-10-24 22:52:48 richard Exp $
+# $Id: hyperdb.py,v 1.91 2003-11-11 00:35:13 richard Exp $
"""
Hyperdatabase implementation, especially field types.
'''
raise NotImplementedError
+class HyperdbValueError(ValueError):
+ ''' Error converting a raw value into a Hyperdb value '''
+ pass
+
+def convertLinkValue(db, propname, prop, value, idre=re.compile('\d+')):
+ ''' Convert the link value (may be id or key value) to an id value. '''
+ linkcl = db.classes[prop.classname]
+ if not idre.match(value):
+ if linkcl.getkey():
+ try:
+ value = linkcl.lookup(value)
+ except KeyError, message:
+ raise HyperdbValueError, 'property %s: %r is not a %s.'%(
+ propname, value, prop.classname)
+ else:
+ raise HyperdbValueError, 'you may only enter ID values '\
+ 'for property %s'%propname
+ return value
+
+def fixNewlines(text):
+ ''' Homogenise line endings.
+
+ Different web clients send different line ending values, but
+ other systems (eg. email) don't necessarily handle those line
+ endings. Our solution is to convert all line endings to LF.
+ '''
+ text = text.replace('\r\n', '\n')
+ return text.replace('\r', '\n')
+
+def rawToHyperdb(db, klass, itemid, propname, value,
+ pwre=re.compile(r'{(\w+)}(.+)')):
+ ''' Convert the raw (user-input) value to a hyperdb-storable value. The
+ value is for the "propname" property on itemid (may be None for a
+ new item) of "klass" in "db".
+
+ The value is usually a string, but in the case of multilink inputs
+ it may be either a list of strings or a string with comma-separated
+ values.
+ '''
+ properties = klass.getprops()
+
+ # ensure it's a valid property name
+ propname = propname.strip()
+ try:
+ proptype = properties[propname]
+ except KeyError:
+ raise HyperdbValueError, '%r is not a property of %s'%(propname,
+ klass.classname)
+
+ # if we got a string, strip it now
+ if isinstance(value, type('')):
+ value = value.strip()
+
+ # convert the input value to a real property value
+ if isinstance(proptype, String):
+ # fix the CRLF/CR -> LF stuff
+ value = fixNewlines(value)
+ if isinstance(proptype, Password):
+ m = pwre.match(value)
+ if m:
+ # password is being given to us encrypted
+ p = password.Password()
+ p.scheme = m.group(1)
+ if p.scheme not in 'SHA crypt plaintext'.split():
+ raise HyperdbValueError, 'property %s: unknown encryption '\
+ 'scheme %r'%(propname, p.scheme)
+ p.password = m.group(2)
+ value = p
+ else:
+ try:
+ value = password.Password(value)
+ except password.PasswordValueError, message:
+ raise HyperdbValueError, 'property %s: %s'%(propname, message)
+ elif isinstance(proptype, Date):
+ try:
+ tz = db.getUserTimezone()
+ value = date.Date(value).local(tz)
+ except ValueError, message:
+ raise HyperdbValueError, 'property %s: %r is an invalid '\
+ 'date (%s)'%(propname, value, message)
+ elif isinstance(proptype, Interval):
+ try:
+ value = date.Interval(value)
+ except ValueError, message:
+ raise HyperdbValueError, 'property %s: %r is an invalid '\
+ 'date interval (%s)'%(propname, value, message)
+ elif isinstance(proptype, Link):
+ if value == '-1' or not value:
+ value = None
+ else:
+ value = convertLinkValue(db, propname, proptype, value)
+
+ elif isinstance(proptype, Multilink):
+ # get the current item value if it's not a new item
+ if itemid and not itemid.startswith('-'):
+ curvalue = klass.get(itemid, propname)
+ else:
+ curvalue = []
+
+ # if the value is a comma-separated string then split it now
+ if isinstance(value, type('')):
+ value = value.split(',')
+
+ # handle each add/remove in turn
+ # keep an extra list for all items that are
+ # definitely in the new list (in case of e.g.
+ # <propname>=A,+B, which should replace the old
+ # list with A,B)
+ set = 1
+ newvalue = []
+ for item in value:
+ item = item.strip()
+
+ # skip blanks
+ if not item: continue
+
+ # handle +/-
+ remove = 0
+ if item.startswith('-'):
+ remove = 1
+ item = item[1:]
+ set = 0
+ elif item.startswith('+'):
+ item = item[1:]
+ set = 0
+
+ # look up the value
+ itemid = convertLinkValue(db, propname, proptype, item)
+
+ # perform the add/remove
+ if remove:
+ try:
+ curvalue.remove(itemid)
+ except ValueError:
+ raise HyperdbValueError, 'property %s: %r is not ' \
+ 'currently an element'%(propname, item)
+ else:
+ newvalue.append(itemid)
+ if itemid not in curvalue:
+ curvalue.append(itemid)
+
+ # that's it, set the new Multilink property value,
+ # or overwrite it completely
+ if set:
+ value = newvalue
+ else:
+ value = curvalue
+
+ # TODO: one day, we'll switch to numeric ids and this will be
+ # unnecessary :(
+ value = [int(x) for x in value]
+ value.sort()
+ value = [str(x) for x in value]
+ elif isinstance(proptype, Boolean):
+ value = value.strip()
+ value = value.lower() in ('yes', 'true', 'on', '1')
+ elif isinstance(proptype, Number):
+ value = value.strip()
+ try:
+ value = float(value)
+ except ValueError:
+ raise HyperdbValueError, 'property %s: %r is not a number'%(
+ propname, value)
+ return value
+
class FileClass:
''' A class that requires the "content" property and stores it on
disk.
diff --git a/roundup/mailgw.py b/roundup/mailgw.py
index ab03bda4e1fbb2db97200ae80d4e1d61b066398b..a45f9e96ee438bc99933cdf517f214559ed8277f 100644 (file)
--- a/roundup/mailgw.py
+++ b/roundup/mailgw.py
an exception, the original message is bounced back to the sender with the
explanatory message given in the exception.
-$Id: mailgw.py,v 1.136 2003-11-03 18:34:03 jlgijsbers Exp $
+$Id: mailgw.py,v 1.137 2003-11-11 00:35:13 richard Exp $
"""
import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri
return nodeid
-def setPropArrayFromString(self, cl, propString, nodeid = None):
+def setPropArrayFromString(self, cl, propString, nodeid=None):
''' takes string of form prop=value,value;prop2=value
and returns (error, prop[..])
'''
- properties = cl.getprops()
props = {}
errors = []
for prop in string.split(propString, ';'):
errors.append('not of form [arg=value,value,...;'
'arg=value,value,...]')
return (errors, props)
-
- # ensure it's a valid property name
+ # convert the value to a hyperdb-usable value
propname = propname.strip()
try:
- proptype = properties[propname]
- except KeyError:
- errors.append('refers to an invalid property: "%s"'%propname)
- continue
-
- # convert the string value to a real property value
- if isinstance(proptype, hyperdb.String):
- props[propname] = value.strip()
- if isinstance(proptype, hyperdb.Password):
- props[propname] = password.Password(value.strip())
- elif isinstance(proptype, hyperdb.Date):
- try:
- props[propname] = date.Date(value.strip()).local(self.db.getUserTimezone())
- except ValueError, message:
- errors.append('contains an invalid date for %s.'%propname)
- elif isinstance(proptype, hyperdb.Interval):
- try:
- props[propname] = date.Interval(value)
- except ValueError, message:
- errors.append('contains an invalid date interval for %s.'%
- propname)
- elif isinstance(proptype, hyperdb.Link):
- linkcl = self.db.classes[proptype.classname]
- propkey = linkcl.labelprop(default_to_id=1)
- try:
- props[propname] = linkcl.lookup(value)
- except KeyError, message:
- errors.append('"%s" is not a value for %s.'%(value, propname))
- elif isinstance(proptype, hyperdb.Multilink):
- # get the linked class
- linkcl = self.db.classes[proptype.classname]
- propkey = linkcl.labelprop(default_to_id=1)
- if nodeid:
- curvalue = cl.get(nodeid, propname)
- else:
- curvalue = []
-
- # handle each add/remove in turn
- # keep an extra list for all items that are
- # definitely in the new list (in case of e.g.
- # <propname>=A,+B, which should replace the old
- # list with A,B)
- set = 0
- newvalue = []
- for item in value.split(','):
- item = item.strip()
-
- # handle +/-
- remove = 0
- if item.startswith('-'):
- remove = 1
- item = item[1:]
- elif item.startswith('+'):
- item = item[1:]
- else:
- set = 1
-
- # look up the value
- try:
- item = linkcl.lookup(item)
- except KeyError, message:
- errors.append('"%s" is not a value for %s.'%(item,
- propname))
- continue
-
- # perform the add/remove
- if remove:
- try:
- curvalue.remove(item)
- except ValueError:
- errors.append('"%s" is not currently in for %s.'%(item,
- propname))
- continue
- else:
- newvalue.append(item)
- if item not in curvalue:
- curvalue.append(item)
-
- # that's it, set the new Multilink property value,
- # or overwrite it completely
- if set:
- props[propname] = newvalue
- else:
- props[propname] = curvalue
- elif isinstance(proptype, hyperdb.Boolean):
- value = value.strip()
- props[propname] = value.lower() in ('yes', 'true', 'on', '1')
- elif isinstance(proptype, hyperdb.Number):
- value = value.strip()
- props[propname] = float(value)
+ props[propname] = hyperdb.rawToHyperdb(self.db, cl, nodeid,
+ propname, value)
+ except hyperdb.HyperdbValueError, message:
+ errors.append(message)
return errors, props
diff --git a/roundup/password.py b/roundup/password.py
index a2f01f52c4c71e569f5b877f3f419c46a3272a03..97de75d08be5cd4a4d2ca7dfbd9eaedb726c4f73 100644 (file)
--- a/roundup/password.py
+++ b/roundup/password.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: password.py,v 1.9 2003-04-10 05:12:41 richard Exp $
+# $Id: password.py,v 1.10 2003-11-11 00:35:13 richard Exp $
__doc__ = """
Password handling (encoding, decoding).
crypt = None
pass
+class PasswordValueError(ValueError):
+ ''' The password value is not valid '''
+ pass
+
def encodePassword(plaintext, scheme, other=None):
'''Encrypt the plaintext password.
'''
elif scheme == 'plaintext':
s = plaintext
else:
- raise ValueError, 'Unknown encryption scheme "%s"'%scheme
+ raise PasswordValueError, 'unknown encryption scheme %r'%scheme
return s
def generatePassword(length=8):
diff --git a/test/test_hyperdbvals.py b/test/test_hyperdbvals.py
--- /dev/null
+++ b/test/test_hyperdbvals.py
@@ -0,0 +1,129 @@
+#
+# Copyright (c) 2003 Richard Jones, richard@commonground.com.au
+# This module is free software, and you may redistribute it and/or modify
+# under the same terms as Python, so long as this copyright message and
+# disclaimer are retained in their original form.
+#
+# This module is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# $Id: test_hyperdbvals.py,v 1.1 2003-11-11 00:35:14 richard Exp $
+
+import unittest, os, shutil, errno, sys, difflib, cgi, re, sha
+
+from roundup import init, instance, password, hyperdb, date
+
+class TestClass:
+ def getprops(self):
+ return {
+ 'string': hyperdb.String(),
+ 'number': hyperdb.Number(),
+ 'boolean': hyperdb.Boolean(),
+ 'password': hyperdb.Password(),
+ 'date': hyperdb.Date(),
+ 'interval': hyperdb.Interval(),
+ 'link': hyperdb.Link('test'),
+ 'link2': hyperdb.Link('test2'),
+ 'multilink': hyperdb.Multilink('test'),
+ 'multilink2': hyperdb.Multilink('test2'),
+ }
+ def getkey(self):
+ return 'string'
+ def lookup(self, value):
+ if value == 'valid':
+ return '1'
+ raise KeyError
+ def get(self, nodeid, propname):
+ assert propname.startswith('multilink')
+ assert nodeid is not None
+ return ['2', '3']
+
+class TestClass2:
+ def properties(self):
+ return {
+ 'string': hyperdb.String(),
+ }
+ def getkey(self):
+ return None
+ def labelprop(self, default_to_id=1):
+ return 'id'
+
+class TestDatabase:
+ classes = {'test': TestClass(), 'test2': TestClass2()}
+ def getUserTimezone(self):
+ return 0
+
+class RawToHyperdbTest(unittest.TestCase):
+ def _test(self, propname, value, itemid=None):
+ return hyperdb.rawToHyperdb(TestDatabase(), TestClass(), itemid,
+ propname, value)
+ def testString(self):
+ self.assertEqual(self._test('string', ' a string '), 'a string')
+ def testNumber(self):
+ self.assertEqual(self._test('number', ' 10 '), 10)
+ self.assertEqual(self._test('number', ' 1.5 '), 1.5)
+ def testBoolean(self):
+ for true in 'yes true on 1'.split():
+ self.assertEqual(self._test('boolean', ' %s '%true), 1)
+ for false in 'no false off 0'.split():
+ self.assertEqual(self._test('boolean', ' %s '%false), 0)
+ def testPassword(self):
+ self.assertEqual(self._test('password', ' a string '), 'a string')
+ val = self._test('password', ' a string ')
+ self.assert_(isinstance(val, password.Password))
+ val = self._test('password', '{plaintext}a string')
+ self.assert_(isinstance(val, password.Password))
+ val = self._test('password', '{crypt}a string')
+ self.assert_(isinstance(val, password.Password))
+ s = sha.sha('a string').hexdigest()
+ val = self._test('password', '{SHA}'+s)
+ self.assert_(isinstance(val, password.Password))
+ self.assertEqual(val, 'a string')
+ self.assertRaises(hyperdb.HyperdbValueError, self._test,
+ 'password', '{fubar}a string')
+ def testDate(self):
+ val = self._test('date', ' 2003-01-01 ')
+ self.assert_(isinstance(val, date.Date))
+ val = self._test('date', ' 2003/01/01 ')
+ self.assert_(isinstance(val, date.Date))
+ val = self._test('date', ' 2003/1/1 ')
+ self.assert_(isinstance(val, date.Date))
+ val = self._test('date', ' 2003-1-1 ')
+ self.assert_(isinstance(val, date.Date))
+ self.assertRaises(hyperdb.HyperdbValueError, self._test, 'date',
+ 'fubar')
+ def testInterval(self):
+ val = self._test('interval', ' +1d ')
+ self.assert_(isinstance(val, date.Interval))
+ self.assertRaises(hyperdb.HyperdbValueError, self._test, 'interval',
+ 'fubar')
+ def testLink(self):
+ self.assertEqual(self._test('link', '1'), '1')
+ self.assertEqual(self._test('link', 'valid'), '1')
+ self.assertRaises(hyperdb.HyperdbValueError, self._test, 'link',
+ 'invalid')
+ def testMultilink(self):
+ self.assertEqual(self._test('multilink', '', '1'), [])
+ self.assertEqual(self._test('multilink', '1', '1'), ['1'])
+ self.assertEqual(self._test('multilink', 'valid', '1'), ['1'])
+ self.assertRaises(hyperdb.HyperdbValueError, self._test, 'multilink',
+ 'invalid', '1')
+ self.assertEqual(self._test('multilink', '+1', '1'), ['1', '2', '3'])
+ self.assertEqual(self._test('multilink', '+valid', '1'), ['1', '2',
+ '3'])
+ self.assertEqual(self._test('multilink', '+1,-2', '1'), ['1', '3'])
+ self.assertEqual(self._test('multilink', '+valid,-3', '1'), ['1', '2'])
+ self.assertEqual(self._test('multilink', '+1', None), ['1'])
+ self.assertEqual(self._test('multilink', '+valid', None), ['1'])
+ self.assertEqual(self._test('multilink', '', None), [])
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(RawToHyperdbTest))
+ return suite
+
+if __name__ == '__main__':
+ runner = unittest.TextTestRunner()
+ unittest.main(testRunner=runner)
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/test/test_mailgw.py b/test/test_mailgw.py
index b8019c3116ccd1a569a0e67eeabb9a5ac7a2a899..211b4c458a827c714488a3f4c4a11f8a33c09cc7 100644 (file)
--- a/test/test_mailgw.py
+++ b/test/test_mailgw.py
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
-# $Id: test_mailgw.py,v 1.60 2003-11-03 22:23:02 jlgijsbers Exp $
+# $Id: test_mailgw.py,v 1.61 2003-11-11 00:35:14 richard Exp $
import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822
init.install(self.dirname, 'templates/classic')
init.write_select_db(self.dirname, 'anydbm')
init.initialise(self.dirname, 'sekrit')
-
+
# check we can load the package
self.instance = instance.open(self.dirname)