0001 """ 0002 Tests for the mhlib module 0003 Nick Mathewson 0004 """ 0005 0006 ### BUG: This suite doesn't currently test the mime functionality of 0007 ### mhlib. It should. 0008 0009 import unittest 0010 from test.test_support import run_unittest, TESTFN, TestSkipped 0011 import os, StringIO 0012 import sys 0013 import mhlib 0014 0015 if (sys.platform.startswith("win") or sys.platform=="riscos" or 0016 sys.platform.startswith("atheos")): 0017 # mhlib.updateline() renames a file to the name of a file that already 0018 # exists. That causes a reasonable OS <wink> to complain in test_sequence 0019 # here, like the "OSError: [Errno 17] File exists" raised on Windows. 0020 # mhlib's listsubfolders() and listallfolders() do something with 0021 # link counts, and that causes test_listfolders() here to get back 0022 # an empty list from its call of listallfolders(). 0023 # The other tests here pass on Windows. 0024 raise TestSkipped("skipped on %s -- " % sys.platform + 0025 "too many Unix assumptions") 0026 0027 _mhroot = TESTFN+"_MH" 0028 _mhpath = os.path.join(_mhroot, "MH") 0029 _mhprofile = os.path.join(_mhroot, ".mh_profile") 0030 0031 def normF(f): 0032 return os.path.join(*f.split('/')) 0033 0034 def writeFile(fname, contents): 0035 dir = os.path.split(fname)[0] 0036 if dir and not os.path.exists(dir): 0037 mkdirs(dir) 0038 f = open(fname, 'w') 0039 f.write(contents) 0040 f.close() 0041 0042 def readFile(fname): 0043 f = open(fname) 0044 r = f.read() 0045 f.close() 0046 return r 0047 0048 def writeProfile(dict): 0049 contents = [ "%s: %s\n" % (k, v) for k, v in dict.iteritems() ] 0050 writeFile(_mhprofile, "".join(contents)) 0051 0052 def writeContext(folder): 0053 folder = normF(folder) 0054 writeFile(os.path.join(_mhpath, "context"), 0055 "Current-Folder: %s\n" % folder) 0056 0057 def writeCurMessage(folder, cur): 0058 folder = normF(folder) 0059 writeFile(os.path.join(_mhpath, folder, ".mh_sequences"), 0060 "cur: %s\n"%cur) 0061 0062 def writeMessage(folder, n, headers, body): 0063 folder = normF(folder) 0064 headers = "".join([ "%s: %s\n" % (k, v) for k, v in headers.iteritems() ]) 0065 contents = "%s\n%s\n" % (headers,body) 0066 mkdirs(os.path.join(_mhpath, folder)) 0067 writeFile(os.path.join(_mhpath, folder, str(n)), contents) 0068 0069 def getMH(): 0070 return mhlib.MH(os.path.abspath(_mhpath), _mhprofile) 0071 0072 def sortLines(s): 0073 lines = s.split("\n") 0074 lines = [ line.strip() for line in lines if len(line) >= 2 ] 0075 lines.sort() 0076 return lines 0077 0078 # These next 2 functions are copied from test_glob.py. 0079 def mkdirs(fname): 0080 if os.path.exists(fname) or fname == '': 0081 return 0082 base, file = os.path.split(fname) 0083 mkdirs(base) 0084 os.mkdir(fname) 0085 0086 def deltree(fname): 0087 if not os.path.exists(fname): 0088 return 0089 for f in os.listdir(fname): 0090 fullname = os.path.join(fname, f) 0091 if os.path.isdir(fullname): 0092 deltree(fullname) 0093 else: 0094 try: 0095 os.unlink(fullname) 0096 except: 0097 pass 0098 try: 0099 os.rmdir(fname) 0100 except: 0101 pass 0102 0103 class MhlibTests(unittest.TestCase): 0104 def setUp(self): 0105 deltree(_mhroot) 0106 mkdirs(_mhpath) 0107 writeProfile({'Path' : os.path.abspath(_mhpath), 0108 'Editor': 'emacs', 0109 'ignored-attribute': 'camping holiday'}) 0110 # Note: These headers aren't really conformant to RFC822, but 0111 # mhlib shouldn't care about that. 0112 0113 # An inbox with a couple of messages. 0114 writeMessage('inbox', 1, 0115 {'From': 'Mrs. Premise', 0116 'To': 'Mrs. Conclusion', 0117 'Date': '18 July 2001'}, "Hullo, Mrs. Conclusion!\n") 0118 writeMessage('inbox', 2, 0119 {'From': 'Mrs. Conclusion', 0120 'To': 'Mrs. Premise', 0121 'Date': '29 July 2001'}, "Hullo, Mrs. Premise!\n") 0122 0123 # A folder with many messages 0124 for i in range(5, 101)+range(101, 201, 2): 0125 writeMessage('wide', i, 0126 {'From': 'nowhere', 'Subject': 'message #%s' % i}, 0127 "This is message number %s\n" % i) 0128 0129 # A deeply nested folder 0130 def deep(folder, n): 0131 writeMessage(folder, n, 0132 {'Subject': 'Message %s/%s' % (folder, n) }, 0133 "This is message number %s in %s\n" % (n, folder) ) 0134 deep('deep/f1', 1) 0135 deep('deep/f1', 2) 0136 deep('deep/f1', 3) 0137 deep('deep/f2', 4) 0138 deep('deep/f2', 6) 0139 deep('deep', 3) 0140 deep('deep/f2/f3', 1) 0141 deep('deep/f2/f3', 2) 0142 0143 def tearDown(self): 0144 deltree(_mhroot) 0145 0146 def test_basic(self): 0147 writeContext('inbox') 0148 writeCurMessage('inbox', 2) 0149 mh = getMH() 0150 0151 eq = self.assertEquals 0152 eq(mh.getprofile('Editor'), 'emacs') 0153 eq(mh.getprofile('not-set'), None) 0154 eq(mh.getpath(), os.path.abspath(_mhpath)) 0155 eq(mh.getcontext(), 'inbox') 0156 0157 mh.setcontext('wide') 0158 eq(mh.getcontext(), 'wide') 0159 eq(readFile(os.path.join(_mhpath, 'context')), 0160 "Current-Folder: wide\n") 0161 0162 mh.setcontext('inbox') 0163 0164 inbox = mh.openfolder('inbox') 0165 eq(inbox.getfullname(), 0166 os.path.join(os.path.abspath(_mhpath), 'inbox')) 0167 eq(inbox.getsequencesfilename(), 0168 os.path.join(os.path.abspath(_mhpath), 'inbox', '.mh_sequences')) 0169 eq(inbox.getmessagefilename(1), 0170 os.path.join(os.path.abspath(_mhpath), 'inbox', '1')) 0171 0172 def test_listfolders(self): 0173 mh = getMH() 0174 eq = self.assertEquals 0175 0176 folders = mh.listfolders() 0177 folders.sort() 0178 eq(folders, ['deep', 'inbox', 'wide']) 0179 0180 folders = mh.listallfolders() 0181 folders.sort() 0182 tfolders = map(normF, ['deep', 'deep/f1', 'deep/f2', 'deep/f2/f3', 0183 'inbox', 'wide']) 0184 tfolders.sort() 0185 eq(folders, tfolders) 0186 0187 folders = mh.listsubfolders('deep') 0188 folders.sort() 0189 eq(folders, map(normF, ['deep/f1', 'deep/f2'])) 0190 0191 folders = mh.listallsubfolders('deep') 0192 folders.sort() 0193 eq(folders, map(normF, ['deep/f1', 'deep/f2', 'deep/f2/f3'])) 0194 eq(mh.listsubfolders(normF('deep/f2')), [normF('deep/f2/f3')]) 0195 0196 eq(mh.listsubfolders('inbox'), []) 0197 eq(mh.listallsubfolders('inbox'), []) 0198 0199 def test_sequence(self): 0200 mh = getMH() 0201 eq = self.assertEquals 0202 writeCurMessage('wide', 55) 0203 0204 f = mh.openfolder('wide') 0205 all = f.listmessages() 0206 eq(all, range(5, 101)+range(101, 201, 2)) 0207 eq(f.getcurrent(), 55) 0208 f.setcurrent(99) 0209 eq(readFile(os.path.join(_mhpath, 'wide', '.mh_sequences')), 0210 'cur: 99\n') 0211 0212 def seqeq(seq, val): 0213 eq(f.parsesequence(seq), val) 0214 0215 seqeq('5-55', range(5, 56)) 0216 seqeq('90-108', range(90, 101)+range(101, 109, 2)) 0217 seqeq('90-108', range(90, 101)+range(101, 109, 2)) 0218 0219 seqeq('10:10', range(10, 20)) 0220 seqeq('10:+10', range(10, 20)) 0221 seqeq('101:10', range(101, 121, 2)) 0222 0223 seqeq('cur', [99]) 0224 seqeq('.', [99]) 0225 seqeq('prev', [98]) 0226 seqeq('next', [100]) 0227 seqeq('cur:-3', [97, 98, 99]) 0228 seqeq('first-cur', range(5, 100)) 0229 seqeq('150-last', range(151, 201, 2)) 0230 seqeq('prev-next', [98, 99, 100]) 0231 0232 lowprimes = [5, 7, 11, 13, 17, 19, 23, 29] 0233 lowcompos = [x for x in range(5, 31) if not x in lowprimes ] 0234 f.putsequences({'cur': [5], 0235 'lowprime': lowprimes, 0236 'lowcompos': lowcompos}) 0237 seqs = readFile(os.path.join(_mhpath, 'wide', '.mh_sequences')) 0238 seqs = sortLines(seqs) 0239 eq(seqs, ["cur: 5", 0240 "lowcompos: 6 8-10 12 14-16 18 20-22 24-28 30", 0241 "lowprime: 5 7 11 13 17 19 23 29"]) 0242 0243 seqeq('lowprime', lowprimes) 0244 seqeq('lowprime:1', [5]) 0245 seqeq('lowprime:2', [5, 7]) 0246 seqeq('lowprime:-2', [23, 29]) 0247 0248 ## Not supported 0249 #seqeq('lowprime:first', [5]) 0250 #seqeq('lowprime:last', [29]) 0251 #seqeq('lowprime:prev', [29]) 0252 #seqeq('lowprime:next', [29]) 0253 0254 def test_modify(self): 0255 mh = getMH() 0256 eq = self.assertEquals 0257 0258 mh.makefolder("dummy1") 0259 self.assert_("dummy1" in mh.listfolders()) 0260 path = os.path.join(_mhpath, "dummy1") 0261 self.assert_(os.path.exists(path)) 0262 0263 f = mh.openfolder('dummy1') 0264 def create(n): 0265 msg = "From: foo\nSubject: %s\n\nDummy Message %s\n" % (n,n) 0266 f.createmessage(n, StringIO.StringIO(msg)) 0267 0268 create(7) 0269 create(8) 0270 create(9) 0271 0272 eq(readFile(f.getmessagefilename(9)), 0273 "From: foo\nSubject: 9\n\nDummy Message 9\n") 0274 0275 eq(f.listmessages(), [7, 8, 9]) 0276 files = os.listdir(path) 0277 files.sort() 0278 eq(files, ['7', '8', '9']) 0279 0280 f.removemessages(['7', '8']) 0281 files = os.listdir(path) 0282 files.sort() 0283 eq(files, [',7', ',8', '9']) 0284 eq(f.listmessages(), [9]) 0285 create(10) 0286 create(11) 0287 create(12) 0288 0289 mh.makefolder("dummy2") 0290 f2 = mh.openfolder("dummy2") 0291 eq(f2.listmessages(), []) 0292 f.movemessage(10, f2, 3) 0293 f.movemessage(11, f2, 5) 0294 eq(f.listmessages(), [9, 12]) 0295 eq(f2.listmessages(), [3, 5]) 0296 eq(readFile(f2.getmessagefilename(3)), 0297 "From: foo\nSubject: 10\n\nDummy Message 10\n") 0298 0299 f.copymessage(9, f2, 4) 0300 eq(f.listmessages(), [9, 12]) 0301 eq(readFile(f2.getmessagefilename(4)), 0302 "From: foo\nSubject: 9\n\nDummy Message 9\n") 0303 0304 f.refilemessages([9, 12], f2) 0305 eq(f.listmessages(), []) 0306 eq(f2.listmessages(), [3, 4, 5, 6, 7]) 0307 eq(readFile(f2.getmessagefilename(7)), 0308 "From: foo\nSubject: 12\n\nDummy Message 12\n") 0309 # XXX This should check that _copysequences does the right thing. 0310 0311 mh.deletefolder('dummy1') 0312 mh.deletefolder('dummy2') 0313 self.assert_('dummy1' not in mh.listfolders()) 0314 self.assert_(not os.path.exists(path)) 0315 0316 def test_read(self): 0317 mh = getMH() 0318 eq = self.assertEquals 0319 0320 f = mh.openfolder('inbox') 0321 msg = f.openmessage(1) 0322 # Check some basic stuff from rfc822 0323 eq(msg.getheader('From'), "Mrs. Premise") 0324 eq(msg.getheader('To'), "Mrs. Conclusion") 0325 0326 # Okay, we have the right message. Let's check the stuff from 0327 # mhlib. 0328 lines = sortLines(msg.getheadertext()) 0329 eq(lines, ["Date: 18 July 2001", 0330 "From: Mrs. Premise", 0331 "To: Mrs. Conclusion"]) 0332 lines = sortLines(msg.getheadertext(lambda h: len(h)==4)) 0333 eq(lines, ["Date: 18 July 2001", 0334 "From: Mrs. Premise"]) 0335 eq(msg.getbodytext(), "Hullo, Mrs. Conclusion!\n\n") 0336 eq(msg.getbodytext(0), "Hullo, Mrs. Conclusion!\n\n") 0337 0338 # XXXX there should be a better way to reclaim the file handle 0339 msg.fp.close() 0340 del msg 0341 0342 0343 def test_main(): 0344 run_unittest(MhlibTests) 0345 0346 0347 if __name__ == "__main__": 0348 test_main() 0349
Generated by PyXR 0.9.4