blob: 30f8ca3f10fa3456cf776fac2c12c1667327b157 [file] [log] [blame]
Guido van Rossum0263c802001-08-09 18:18:08 +00001"""
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
9import unittest
Tim Petersc7ca3ff2001-08-09 21:34:54 +000010from test_support import run_unittest, TESTFN, TestSkipped
Guido van Rossum0263c802001-08-09 18:18:08 +000011import os, StringIO
Tim Petersc7ca3ff2001-08-09 21:34:54 +000012import sys
Guido van Rossum0263c802001-08-09 18:18:08 +000013import mhlib
14
Tim Petersc7ca3ff2001-08-09 21:34:54 +000015if sys.platform.startswith("win"):
16 raise TestSkipped("test_mhlib skipped on Windows -- "
17 "too many Unix assumptions")
18
Guido van Rossum0263c802001-08-09 18:18:08 +000019_mhroot = TESTFN+"_MH"
20_mhpath = os.path.join(_mhroot, "MH")
21_mhprofile = os.path.join(_mhroot, ".mh_profile")
22
23def normF(f):
24 return os.path.join(*f.split('/'))
25
26def writeFile(fname, contents):
27 dir = os.path.split(fname)[0]
28 if dir and not os.path.exists(dir):
29 mkdirs(dir)
30 f = open(fname, 'w')
31 f.write(contents)
32 f.close()
33
34def readFile(fname):
35 f = open(fname)
36 r = f.read()
37 f.close()
38 return r
39
40def writeProfile(dict):
41 contents = [ "%s: %s\n" % (k, v) for k, v in dict.iteritems() ]
42 writeFile(_mhprofile, "".join(contents))
43
44def writeContext(folder):
45 folder = normF(folder)
Tim Petersab9ba272001-08-09 21:40:30 +000046 writeFile(os.path.join(_mhpath, "context"),
Guido van Rossum0263c802001-08-09 18:18:08 +000047 "Current-Folder: %s\n" % folder)
48
49def writeCurMessage(folder, cur):
50 folder = normF(folder)
51 writeFile(os.path.join(_mhpath, folder, ".mh_sequences"),
52 "cur: %s\n"%cur)
53
54def writeMessage(folder, n, headers, body):
55 folder = normF(folder)
56 headers = "".join([ "%s: %s\n" % (k, v) for k, v in headers.iteritems() ])
57 contents = "%s\n%s\n" % (headers,body)
58 mkdirs(os.path.join(_mhpath, folder))
59 writeFile(os.path.join(_mhpath, folder, str(n)), contents)
60
61def getMH():
62 return mhlib.MH(os.path.abspath(_mhpath), _mhprofile)
63
64def sortLines(s):
65 lines = s.split("\n")
66 lines = [ line.strip() for line in lines if len(line) >= 2 ]
67 lines.sort()
68 return lines
69
70# These next 2 functions are copied from test_glob.py.
71def mkdirs(fname):
72 if os.path.exists(fname) or fname == '':
73 return
74 base, file = os.path.split(fname)
75 mkdirs(base)
76 os.mkdir(fname)
77
78def deltree(fname):
79 if not os.path.exists(fname):
80 return
81 for f in os.listdir(fname):
82 fullname = os.path.join(fname, f)
83 if os.path.isdir(fullname):
84 deltree(fullname)
85 else:
86 try:
87 os.unlink(fullname)
88 except:
89 pass
90 try:
91 os.rmdir(fname)
92 except:
93 pass
94
95class MhlibTests(unittest.TestCase):
96 def setUp(self):
97 deltree(_mhroot)
98 mkdirs(_mhpath)
Tim Petersab9ba272001-08-09 21:40:30 +000099 writeProfile({'Path' : os.path.abspath(_mhpath),
Guido van Rossum0263c802001-08-09 18:18:08 +0000100 'Editor': 'emacs',
101 'ignored-attribute': 'camping holiday'})
102 # Note: These headers aren't really conformant to RFC822, but
103 # mhlib shouldn't care about that.
104
105 # An inbox with a couple of messages.
Tim Petersab9ba272001-08-09 21:40:30 +0000106 writeMessage('inbox', 1,
Guido van Rossum0263c802001-08-09 18:18:08 +0000107 {'From': 'Mrs. Premise',
108 'To': 'Mrs. Conclusion',
109 'Date': '18 July 2001'}, "Hullo, Mrs. Conclusion!\n")
Tim Petersab9ba272001-08-09 21:40:30 +0000110 writeMessage('inbox', 2,
Guido van Rossum0263c802001-08-09 18:18:08 +0000111 {'From': 'Mrs. Conclusion',
112 'To': 'Mrs. Premise',
113 'Date': '29 July 2001'}, "Hullo, Mrs. Premise!\n")
Tim Petersab9ba272001-08-09 21:40:30 +0000114
Guido van Rossum0263c802001-08-09 18:18:08 +0000115 # A folder with many messages
116 for i in range(5, 101)+range(101, 201, 2):
Tim Petersab9ba272001-08-09 21:40:30 +0000117 writeMessage('wide', i,
Guido van Rossum0263c802001-08-09 18:18:08 +0000118 {'From': 'nowhere', 'Subject': 'message #%s' % i},
119 "This is message number %s\n" % i)
Tim Petersab9ba272001-08-09 21:40:30 +0000120
Guido van Rossum0263c802001-08-09 18:18:08 +0000121 # A deeply nested folder
122 def deep(folder, n):
Tim Petersab9ba272001-08-09 21:40:30 +0000123 writeMessage(folder, n,
Guido van Rossum0263c802001-08-09 18:18:08 +0000124 {'Subject': 'Message %s/%s' % (folder, n) },
125 "This is message number %s in %s\n" % (n, folder) )
126 deep('deep/f1', 1)
127 deep('deep/f1', 2)
128 deep('deep/f1', 3)
129 deep('deep/f2', 4)
130 deep('deep/f2', 6)
131 deep('deep', 3)
132 deep('deep/f2/f3', 1)
133 deep('deep/f2/f3', 2)
Tim Petersab9ba272001-08-09 21:40:30 +0000134
Guido van Rossum0263c802001-08-09 18:18:08 +0000135 def tearDown(self):
136 deltree(_mhroot)
Tim Petersab9ba272001-08-09 21:40:30 +0000137
Guido van Rossum0263c802001-08-09 18:18:08 +0000138 def test_basic(self):
139 writeContext('inbox')
140 writeCurMessage('inbox', 2)
141 mh = getMH()
142
143 eq = self.assertEquals
144 eq(mh.getprofile('Editor'), 'emacs')
145 eq(mh.getprofile('not-set'), None)
146 eq(mh.getpath(), os.path.abspath(_mhpath))
147 eq(mh.getcontext(), 'inbox')
148
149 mh.setcontext('wide')
150 eq(mh.getcontext(), 'wide')
151 eq(readFile(os.path.join(_mhpath, 'context')),
152 "Current-Folder: wide\n")
153
154 mh.setcontext('inbox')
155
156 inbox = mh.openfolder('inbox')
Tim Petersab9ba272001-08-09 21:40:30 +0000157 eq(inbox.getfullname(),
Guido van Rossum0263c802001-08-09 18:18:08 +0000158 os.path.join(os.path.abspath(_mhpath), 'inbox'))
Tim Petersab9ba272001-08-09 21:40:30 +0000159 eq(inbox.getsequencesfilename(),
Guido van Rossum0263c802001-08-09 18:18:08 +0000160 os.path.join(os.path.abspath(_mhpath), 'inbox', '.mh_sequences'))
Tim Petersab9ba272001-08-09 21:40:30 +0000161 eq(inbox.getmessagefilename(1),
Guido van Rossum0263c802001-08-09 18:18:08 +0000162 os.path.join(os.path.abspath(_mhpath), 'inbox', '1'))
Tim Petersab9ba272001-08-09 21:40:30 +0000163
Guido van Rossum0263c802001-08-09 18:18:08 +0000164 def test_listfolders(self):
165 mh = getMH()
166 eq = self.assertEquals
167
168 folders = mh.listfolders()
169 folders.sort()
170 eq(folders, ['deep', 'inbox', 'wide'])
Tim Petersab9ba272001-08-09 21:40:30 +0000171
Guido van Rossum0263c802001-08-09 18:18:08 +0000172 folders = mh.listallfolders()
173 folders.sort()
Jack Jansendbc363c2001-08-11 23:22:43 +0000174 tfolders = map(normF, ['deep', 'deep/f1', 'deep/f2', 'deep/f2/f3',
175 'inbox', 'wide'])
176 tfolders.sort()
177 eq(folders, tfolders)
Guido van Rossum0263c802001-08-09 18:18:08 +0000178
179 folders = mh.listsubfolders('deep')
180 folders.sort()
181 eq(folders, map(normF, ['deep/f1', 'deep/f2']))
Tim Petersab9ba272001-08-09 21:40:30 +0000182
Guido van Rossum0263c802001-08-09 18:18:08 +0000183 folders = mh.listallsubfolders('deep')
184 folders.sort()
185 eq(folders, map(normF, ['deep/f1', 'deep/f2', 'deep/f2/f3']))
186 eq(mh.listsubfolders(normF('deep/f2')), [normF('deep/f2/f3')])
187
188 eq(mh.listsubfolders('inbox'), [])
189 eq(mh.listallsubfolders('inbox'), [])
190
191 def test_sequence(self):
192 mh = getMH()
193 eq = self.assertEquals
194 writeCurMessage('wide', 55)
Tim Petersab9ba272001-08-09 21:40:30 +0000195
Guido van Rossum0263c802001-08-09 18:18:08 +0000196 f = mh.openfolder('wide')
197 all = f.listmessages()
198 eq(all, range(5, 101)+range(101, 201, 2))
199 eq(f.getcurrent(), 55)
200 f.setcurrent(99)
Tim Petersab9ba272001-08-09 21:40:30 +0000201 eq(readFile(os.path.join(_mhpath, 'wide', '.mh_sequences')),
Guido van Rossum0263c802001-08-09 18:18:08 +0000202 'cur: 99\n')
203
204 def seqeq(seq, val):
205 eq(f.parsesequence(seq), val)
Tim Petersab9ba272001-08-09 21:40:30 +0000206
Guido van Rossum0263c802001-08-09 18:18:08 +0000207 seqeq('5-55', range(5, 56))
208 seqeq('90-108', range(90, 101)+range(101, 109, 2))
209 seqeq('90-108', range(90, 101)+range(101, 109, 2))
Tim Petersab9ba272001-08-09 21:40:30 +0000210
Guido van Rossum0263c802001-08-09 18:18:08 +0000211 seqeq('10:10', range(10, 20))
212 seqeq('10:+10', range(10, 20))
213 seqeq('101:10', range(101, 121, 2))
214
215 seqeq('cur', [99])
216 seqeq('.', [99])
217 seqeq('prev', [98])
218 seqeq('next', [100])
219 seqeq('cur:-3', [97, 98, 99])
220 seqeq('first-cur', range(5, 100))
221 seqeq('150-last', range(151, 201, 2))
222 seqeq('prev-next', [98, 99, 100])
223
224 lowprimes = [5, 7, 11, 13, 17, 19, 23, 29]
225 lowcompos = [x for x in range(5, 31) if not x in lowprimes ]
226 f.putsequences({'cur': [5],
227 'lowprime': lowprimes,
228 'lowcompos': lowcompos})
229 seqs = readFile(os.path.join(_mhpath, 'wide', '.mh_sequences'))
230 seqs = sortLines(seqs)
231 eq(seqs, ["cur: 5",
232 "lowcompos: 6 8-10 12 14-16 18 20-22 24-28 30",
233 "lowprime: 5 7 11 13 17 19 23 29"])
234
235 seqeq('lowprime', lowprimes)
236 seqeq('lowprime:1', [5])
237 seqeq('lowprime:2', [5, 7])
238 seqeq('lowprime:-2', [23, 29])
239
240 ## Not supported
241 #seqeq('lowprime:first', [5])
242 #seqeq('lowprime:last', [29])
243 #seqeq('lowprime:prev', [29])
244 #seqeq('lowprime:next', [29])
245
246 def test_modify(self):
247 mh = getMH()
248 eq = self.assertEquals
249
250 mh.makefolder("dummy1")
251 self.assert_("dummy1" in mh.listfolders())
252 path = os.path.join(_mhpath, "dummy1")
253 self.assert_(os.path.exists(path))
Tim Petersab9ba272001-08-09 21:40:30 +0000254
Guido van Rossum0263c802001-08-09 18:18:08 +0000255 f = mh.openfolder('dummy1')
256 def create(n):
257 msg = "From: foo\nSubject: %s\n\nDummy Message %s\n" % (n,n)
258 f.createmessage(n, StringIO.StringIO(msg))
259
260 create(7)
261 create(8)
262 create(9)
Tim Petersab9ba272001-08-09 21:40:30 +0000263
Guido van Rossum0263c802001-08-09 18:18:08 +0000264 eq(readFile(f.getmessagefilename(9)),
265 "From: foo\nSubject: 9\n\nDummy Message 9\n")
266
267 eq(f.listmessages(), [7, 8, 9])
268 files = os.listdir(path)
269 files.sort()
Tim Petersab9ba272001-08-09 21:40:30 +0000270 eq(files, ['7', '8', '9'])
Guido van Rossum0263c802001-08-09 18:18:08 +0000271
272 f.removemessages(['7', '8'])
273 files = os.listdir(path)
274 files.sort()
275 eq(files, [',7', ',8', '9'])
276 eq(f.listmessages(), [9])
277 create(10)
278 create(11)
279 create(12)
Tim Petersab9ba272001-08-09 21:40:30 +0000280
Guido van Rossum0263c802001-08-09 18:18:08 +0000281 mh.makefolder("dummy2")
282 f2 = mh.openfolder("dummy2")
283 eq(f2.listmessages(), [])
284 f.movemessage(10, f2, 3)
285 f.movemessage(11, f2, 5)
286 eq(f.listmessages(), [9, 12])
287 eq(f2.listmessages(), [3, 5])
288 eq(readFile(f2.getmessagefilename(3)),
289 "From: foo\nSubject: 10\n\nDummy Message 10\n")
Tim Petersab9ba272001-08-09 21:40:30 +0000290
Guido van Rossum0263c802001-08-09 18:18:08 +0000291 f.copymessage(9, f2, 4)
292 eq(f.listmessages(), [9, 12])
293 eq(readFile(f2.getmessagefilename(4)),
294 "From: foo\nSubject: 9\n\nDummy Message 9\n")
Tim Petersab9ba272001-08-09 21:40:30 +0000295
Guido van Rossum0263c802001-08-09 18:18:08 +0000296 f.refilemessages([9, 12], f2)
297 eq(f.listmessages(), [])
298 eq(f2.listmessages(), [3, 4, 5, 6, 7])
299 eq(readFile(f2.getmessagefilename(7)),
300 "From: foo\nSubject: 12\n\nDummy Message 12\n")
301 # XXX This should check that _copysequences does the right thing.
302
303 mh.deletefolder('dummy1')
304 mh.deletefolder('dummy2')
305 self.assert_('dummy1' not in mh.listfolders())
306 self.assert_(not os.path.exists(path))
307
308 def test_read(self):
309 mh = getMH()
310 eq = self.assertEquals
Tim Petersab9ba272001-08-09 21:40:30 +0000311
Guido van Rossum0263c802001-08-09 18:18:08 +0000312 f = mh.openfolder('inbox')
313 msg = f.openmessage(1)
314 # Check some basic stuff from rfc822
315 eq(msg.getheader('From'), "Mrs. Premise")
316 eq(msg.getheader('To'), "Mrs. Conclusion")
317
318 # Okay, we have the right message. Let's check the stuff from
319 # mhlib.
320 lines = sortLines(msg.getheadertext())
Tim Petersab9ba272001-08-09 21:40:30 +0000321 eq(lines, ["Date: 18 July 2001",
Guido van Rossum0263c802001-08-09 18:18:08 +0000322 "From: Mrs. Premise",
323 "To: Mrs. Conclusion"])
324 lines = sortLines(msg.getheadertext(lambda h: len(h)==4))
Tim Petersab9ba272001-08-09 21:40:30 +0000325 eq(lines, ["Date: 18 July 2001",
Guido van Rossum0263c802001-08-09 18:18:08 +0000326 "From: Mrs. Premise"])
327 eq(msg.getbodytext(), "Hullo, Mrs. Conclusion!\n\n")
328 eq(msg.getbodytext(0), "Hullo, Mrs. Conclusion!\n\n")
Tim Petersab9ba272001-08-09 21:40:30 +0000329
Guido van Rossum0263c802001-08-09 18:18:08 +0000330 # XXXX there should be a better way to reclaim the file handle
331 msg.fp.close()
332 del msg
333
334run_unittest(MhlibTests)