Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 1 | """ |
| 2 | Tests for the mhlib module |
| 3 | Nick Mathewson |
| 4 | """ |
| 5 | |
| 6 | ### BUG: This suite doesn't currently test the mime functionality of |
| 7 | ### mhlib. It should. |
| 8 | |
| 9 | import unittest |
Barry Warsaw | 04f357c | 2002-07-23 19:04:11 +0000 | [diff] [blame] | 10 | from test.test_support import run_unittest, TESTFN, TestSkipped |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 11 | import os, StringIO |
Tim Peters | c7ca3ff | 2001-08-09 21:34:54 +0000 | [diff] [blame] | 12 | import sys |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 13 | import mhlib |
| 14 | |
Tim Peters | 32ef169 | 2002-08-04 22:35:31 +0000 | [diff] [blame] | 15 | if (sys.platform.startswith("win") or sys.platform=="riscos" or |
Tim Peters | 283ead8 | 2002-08-04 22:52:30 +0000 | [diff] [blame] | 16 | sys.platform.startswith("atheos")): |
Tim Peters | 32ef169 | 2002-08-04 22:35:31 +0000 | [diff] [blame] | 17 | # mhlib.updateline() renames a file to the name of a file that already |
| 18 | # exists. That causes a reasonable OS <wink> to complain in test_sequence |
| 19 | # here, like the "OSError: [Errno 17] File exists" raised on Windows. |
| 20 | # mhlib's listsubfolders() and listallfolders() do something with |
| 21 | # link counts, and that causes test_listfolders() here to get back |
| 22 | # an empty list from its call of listallfolders(). |
| 23 | # The other tests here pass on Windows. |
Tim Peters | 6782d6a | 2002-08-04 22:55:35 +0000 | [diff] [blame] | 24 | raise TestSkipped("skipped on %s -- " % sys.platform + |
Tim Peters | c7ca3ff | 2001-08-09 21:34:54 +0000 | [diff] [blame] | 25 | "too many Unix assumptions") |
| 26 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 27 | _mhroot = TESTFN+"_MH" |
| 28 | _mhpath = os.path.join(_mhroot, "MH") |
| 29 | _mhprofile = os.path.join(_mhroot, ".mh_profile") |
| 30 | |
| 31 | def normF(f): |
| 32 | return os.path.join(*f.split('/')) |
| 33 | |
| 34 | def writeFile(fname, contents): |
| 35 | dir = os.path.split(fname)[0] |
| 36 | if dir and not os.path.exists(dir): |
| 37 | mkdirs(dir) |
| 38 | f = open(fname, 'w') |
| 39 | f.write(contents) |
| 40 | f.close() |
| 41 | |
| 42 | def readFile(fname): |
| 43 | f = open(fname) |
| 44 | r = f.read() |
| 45 | f.close() |
| 46 | return r |
| 47 | |
| 48 | def writeProfile(dict): |
| 49 | contents = [ "%s: %s\n" % (k, v) for k, v in dict.iteritems() ] |
| 50 | writeFile(_mhprofile, "".join(contents)) |
| 51 | |
| 52 | def writeContext(folder): |
| 53 | folder = normF(folder) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 54 | writeFile(os.path.join(_mhpath, "context"), |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 55 | "Current-Folder: %s\n" % folder) |
| 56 | |
| 57 | def writeCurMessage(folder, cur): |
| 58 | folder = normF(folder) |
| 59 | writeFile(os.path.join(_mhpath, folder, ".mh_sequences"), |
| 60 | "cur: %s\n"%cur) |
| 61 | |
| 62 | def writeMessage(folder, n, headers, body): |
| 63 | folder = normF(folder) |
| 64 | headers = "".join([ "%s: %s\n" % (k, v) for k, v in headers.iteritems() ]) |
| 65 | contents = "%s\n%s\n" % (headers,body) |
| 66 | mkdirs(os.path.join(_mhpath, folder)) |
| 67 | writeFile(os.path.join(_mhpath, folder, str(n)), contents) |
| 68 | |
| 69 | def getMH(): |
| 70 | return mhlib.MH(os.path.abspath(_mhpath), _mhprofile) |
| 71 | |
| 72 | def sortLines(s): |
| 73 | lines = s.split("\n") |
| 74 | lines = [ line.strip() for line in lines if len(line) >= 2 ] |
| 75 | lines.sort() |
| 76 | return lines |
| 77 | |
| 78 | # These next 2 functions are copied from test_glob.py. |
| 79 | def mkdirs(fname): |
| 80 | if os.path.exists(fname) or fname == '': |
| 81 | return |
| 82 | base, file = os.path.split(fname) |
| 83 | mkdirs(base) |
| 84 | os.mkdir(fname) |
| 85 | |
| 86 | def deltree(fname): |
| 87 | if not os.path.exists(fname): |
| 88 | return |
| 89 | for f in os.listdir(fname): |
| 90 | fullname = os.path.join(fname, f) |
| 91 | if os.path.isdir(fullname): |
| 92 | deltree(fullname) |
| 93 | else: |
| 94 | try: |
| 95 | os.unlink(fullname) |
| 96 | except: |
| 97 | pass |
| 98 | try: |
| 99 | os.rmdir(fname) |
| 100 | except: |
| 101 | pass |
| 102 | |
| 103 | class MhlibTests(unittest.TestCase): |
| 104 | def setUp(self): |
| 105 | deltree(_mhroot) |
| 106 | mkdirs(_mhpath) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 107 | writeProfile({'Path' : os.path.abspath(_mhpath), |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 108 | 'Editor': 'emacs', |
| 109 | 'ignored-attribute': 'camping holiday'}) |
| 110 | # Note: These headers aren't really conformant to RFC822, but |
| 111 | # mhlib shouldn't care about that. |
| 112 | |
| 113 | # An inbox with a couple of messages. |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 114 | writeMessage('inbox', 1, |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 115 | {'From': 'Mrs. Premise', |
| 116 | 'To': 'Mrs. Conclusion', |
| 117 | 'Date': '18 July 2001'}, "Hullo, Mrs. Conclusion!\n") |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 118 | writeMessage('inbox', 2, |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 119 | {'From': 'Mrs. Conclusion', |
| 120 | 'To': 'Mrs. Premise', |
| 121 | 'Date': '29 July 2001'}, "Hullo, Mrs. Premise!\n") |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 122 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 123 | # A folder with many messages |
| 124 | for i in range(5, 101)+range(101, 201, 2): |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 125 | writeMessage('wide', i, |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 126 | {'From': 'nowhere', 'Subject': 'message #%s' % i}, |
| 127 | "This is message number %s\n" % i) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 128 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 129 | # A deeply nested folder |
| 130 | def deep(folder, n): |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 131 | writeMessage(folder, n, |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 132 | {'Subject': 'Message %s/%s' % (folder, n) }, |
| 133 | "This is message number %s in %s\n" % (n, folder) ) |
| 134 | deep('deep/f1', 1) |
| 135 | deep('deep/f1', 2) |
| 136 | deep('deep/f1', 3) |
| 137 | deep('deep/f2', 4) |
| 138 | deep('deep/f2', 6) |
| 139 | deep('deep', 3) |
| 140 | deep('deep/f2/f3', 1) |
| 141 | deep('deep/f2/f3', 2) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 142 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 143 | def tearDown(self): |
| 144 | deltree(_mhroot) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 145 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 146 | def test_basic(self): |
| 147 | writeContext('inbox') |
| 148 | writeCurMessage('inbox', 2) |
| 149 | mh = getMH() |
| 150 | |
| 151 | eq = self.assertEquals |
| 152 | eq(mh.getprofile('Editor'), 'emacs') |
| 153 | eq(mh.getprofile('not-set'), None) |
| 154 | eq(mh.getpath(), os.path.abspath(_mhpath)) |
| 155 | eq(mh.getcontext(), 'inbox') |
| 156 | |
| 157 | mh.setcontext('wide') |
| 158 | eq(mh.getcontext(), 'wide') |
| 159 | eq(readFile(os.path.join(_mhpath, 'context')), |
| 160 | "Current-Folder: wide\n") |
| 161 | |
| 162 | mh.setcontext('inbox') |
| 163 | |
| 164 | inbox = mh.openfolder('inbox') |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 165 | eq(inbox.getfullname(), |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 166 | os.path.join(os.path.abspath(_mhpath), 'inbox')) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 167 | eq(inbox.getsequencesfilename(), |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 168 | os.path.join(os.path.abspath(_mhpath), 'inbox', '.mh_sequences')) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 169 | eq(inbox.getmessagefilename(1), |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 170 | os.path.join(os.path.abspath(_mhpath), 'inbox', '1')) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 171 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 172 | def test_listfolders(self): |
| 173 | mh = getMH() |
| 174 | eq = self.assertEquals |
| 175 | |
| 176 | folders = mh.listfolders() |
| 177 | folders.sort() |
| 178 | eq(folders, ['deep', 'inbox', 'wide']) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 179 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 180 | folders = mh.listallfolders() |
| 181 | folders.sort() |
Jack Jansen | dbc363c | 2001-08-11 23:22:43 +0000 | [diff] [blame] | 182 | tfolders = map(normF, ['deep', 'deep/f1', 'deep/f2', 'deep/f2/f3', |
| 183 | 'inbox', 'wide']) |
| 184 | tfolders.sort() |
| 185 | eq(folders, tfolders) |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 186 | |
| 187 | folders = mh.listsubfolders('deep') |
| 188 | folders.sort() |
| 189 | eq(folders, map(normF, ['deep/f1', 'deep/f2'])) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 190 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 191 | folders = mh.listallsubfolders('deep') |
| 192 | folders.sort() |
| 193 | eq(folders, map(normF, ['deep/f1', 'deep/f2', 'deep/f2/f3'])) |
| 194 | eq(mh.listsubfolders(normF('deep/f2')), [normF('deep/f2/f3')]) |
| 195 | |
| 196 | eq(mh.listsubfolders('inbox'), []) |
| 197 | eq(mh.listallsubfolders('inbox'), []) |
| 198 | |
| 199 | def test_sequence(self): |
| 200 | mh = getMH() |
| 201 | eq = self.assertEquals |
| 202 | writeCurMessage('wide', 55) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 203 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 204 | f = mh.openfolder('wide') |
| 205 | all = f.listmessages() |
| 206 | eq(all, range(5, 101)+range(101, 201, 2)) |
| 207 | eq(f.getcurrent(), 55) |
| 208 | f.setcurrent(99) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 209 | eq(readFile(os.path.join(_mhpath, 'wide', '.mh_sequences')), |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 210 | 'cur: 99\n') |
| 211 | |
| 212 | def seqeq(seq, val): |
| 213 | eq(f.parsesequence(seq), val) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 214 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 215 | seqeq('5-55', range(5, 56)) |
| 216 | seqeq('90-108', range(90, 101)+range(101, 109, 2)) |
| 217 | seqeq('90-108', range(90, 101)+range(101, 109, 2)) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 218 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 219 | seqeq('10:10', range(10, 20)) |
| 220 | seqeq('10:+10', range(10, 20)) |
| 221 | seqeq('101:10', range(101, 121, 2)) |
| 222 | |
| 223 | seqeq('cur', [99]) |
| 224 | seqeq('.', [99]) |
| 225 | seqeq('prev', [98]) |
| 226 | seqeq('next', [100]) |
| 227 | seqeq('cur:-3', [97, 98, 99]) |
| 228 | seqeq('first-cur', range(5, 100)) |
| 229 | seqeq('150-last', range(151, 201, 2)) |
| 230 | seqeq('prev-next', [98, 99, 100]) |
| 231 | |
| 232 | lowprimes = [5, 7, 11, 13, 17, 19, 23, 29] |
| 233 | lowcompos = [x for x in range(5, 31) if not x in lowprimes ] |
| 234 | f.putsequences({'cur': [5], |
| 235 | 'lowprime': lowprimes, |
| 236 | 'lowcompos': lowcompos}) |
| 237 | seqs = readFile(os.path.join(_mhpath, 'wide', '.mh_sequences')) |
| 238 | seqs = sortLines(seqs) |
| 239 | eq(seqs, ["cur: 5", |
| 240 | "lowcompos: 6 8-10 12 14-16 18 20-22 24-28 30", |
| 241 | "lowprime: 5 7 11 13 17 19 23 29"]) |
| 242 | |
| 243 | seqeq('lowprime', lowprimes) |
| 244 | seqeq('lowprime:1', [5]) |
| 245 | seqeq('lowprime:2', [5, 7]) |
| 246 | seqeq('lowprime:-2', [23, 29]) |
| 247 | |
| 248 | ## Not supported |
| 249 | #seqeq('lowprime:first', [5]) |
| 250 | #seqeq('lowprime:last', [29]) |
| 251 | #seqeq('lowprime:prev', [29]) |
| 252 | #seqeq('lowprime:next', [29]) |
| 253 | |
| 254 | def test_modify(self): |
| 255 | mh = getMH() |
| 256 | eq = self.assertEquals |
| 257 | |
| 258 | mh.makefolder("dummy1") |
| 259 | self.assert_("dummy1" in mh.listfolders()) |
| 260 | path = os.path.join(_mhpath, "dummy1") |
| 261 | self.assert_(os.path.exists(path)) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 262 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 263 | f = mh.openfolder('dummy1') |
| 264 | def create(n): |
| 265 | msg = "From: foo\nSubject: %s\n\nDummy Message %s\n" % (n,n) |
| 266 | f.createmessage(n, StringIO.StringIO(msg)) |
| 267 | |
| 268 | create(7) |
| 269 | create(8) |
| 270 | create(9) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 271 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 272 | eq(readFile(f.getmessagefilename(9)), |
| 273 | "From: foo\nSubject: 9\n\nDummy Message 9\n") |
| 274 | |
| 275 | eq(f.listmessages(), [7, 8, 9]) |
| 276 | files = os.listdir(path) |
| 277 | files.sort() |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 278 | eq(files, ['7', '8', '9']) |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 279 | |
| 280 | f.removemessages(['7', '8']) |
| 281 | files = os.listdir(path) |
| 282 | files.sort() |
| 283 | eq(files, [',7', ',8', '9']) |
| 284 | eq(f.listmessages(), [9]) |
| 285 | create(10) |
| 286 | create(11) |
| 287 | create(12) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 288 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 289 | mh.makefolder("dummy2") |
| 290 | f2 = mh.openfolder("dummy2") |
| 291 | eq(f2.listmessages(), []) |
| 292 | f.movemessage(10, f2, 3) |
| 293 | f.movemessage(11, f2, 5) |
| 294 | eq(f.listmessages(), [9, 12]) |
| 295 | eq(f2.listmessages(), [3, 5]) |
| 296 | eq(readFile(f2.getmessagefilename(3)), |
| 297 | "From: foo\nSubject: 10\n\nDummy Message 10\n") |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 298 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 299 | f.copymessage(9, f2, 4) |
| 300 | eq(f.listmessages(), [9, 12]) |
| 301 | eq(readFile(f2.getmessagefilename(4)), |
| 302 | "From: foo\nSubject: 9\n\nDummy Message 9\n") |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 303 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 304 | f.refilemessages([9, 12], f2) |
| 305 | eq(f.listmessages(), []) |
| 306 | eq(f2.listmessages(), [3, 4, 5, 6, 7]) |
| 307 | eq(readFile(f2.getmessagefilename(7)), |
| 308 | "From: foo\nSubject: 12\n\nDummy Message 12\n") |
| 309 | # XXX This should check that _copysequences does the right thing. |
| 310 | |
| 311 | mh.deletefolder('dummy1') |
| 312 | mh.deletefolder('dummy2') |
| 313 | self.assert_('dummy1' not in mh.listfolders()) |
| 314 | self.assert_(not os.path.exists(path)) |
| 315 | |
| 316 | def test_read(self): |
| 317 | mh = getMH() |
| 318 | eq = self.assertEquals |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 319 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 320 | f = mh.openfolder('inbox') |
| 321 | msg = f.openmessage(1) |
| 322 | # Check some basic stuff from rfc822 |
| 323 | eq(msg.getheader('From'), "Mrs. Premise") |
| 324 | eq(msg.getheader('To'), "Mrs. Conclusion") |
| 325 | |
| 326 | # Okay, we have the right message. Let's check the stuff from |
| 327 | # mhlib. |
| 328 | lines = sortLines(msg.getheadertext()) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 329 | eq(lines, ["Date: 18 July 2001", |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 330 | "From: Mrs. Premise", |
| 331 | "To: Mrs. Conclusion"]) |
| 332 | lines = sortLines(msg.getheadertext(lambda h: len(h)==4)) |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 333 | eq(lines, ["Date: 18 July 2001", |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 334 | "From: Mrs. Premise"]) |
| 335 | eq(msg.getbodytext(), "Hullo, Mrs. Conclusion!\n\n") |
| 336 | eq(msg.getbodytext(0), "Hullo, Mrs. Conclusion!\n\n") |
Tim Peters | ab9ba27 | 2001-08-09 21:40:30 +0000 | [diff] [blame] | 337 | |
Guido van Rossum | 0263c80 | 2001-08-09 18:18:08 +0000 | [diff] [blame] | 338 | # XXXX there should be a better way to reclaim the file handle |
| 339 | msg.fp.close() |
| 340 | del msg |
| 341 | |
Fred Drake | 2e2be37 | 2001-09-20 21:33:42 +0000 | [diff] [blame] | 342 | |
| 343 | def test_main(): |
| 344 | run_unittest(MhlibTests) |
| 345 | |
| 346 | |
| 347 | if __name__ == "__main__": |
| 348 | test_main() |