| """ |
| Tests for the mhlib module |
| Nick Mathewson |
| """ |
| |
| ### BUG: This suite doesn't currently test the mime functionality of |
| ### mhlib. It should. |
| |
| import unittest |
| from test_support import run_unittest, TESTFN, TestSkipped |
| import os, StringIO |
| import sys |
| import mhlib |
| |
| if sys.platform.startswith("win"): |
| raise TestSkipped("test_mhlib skipped on Windows -- " |
| "too many Unix assumptions") |
| |
| _mhroot = TESTFN+"_MH" |
| _mhpath = os.path.join(_mhroot, "MH") |
| _mhprofile = os.path.join(_mhroot, ".mh_profile") |
| |
| def normF(f): |
| return os.path.join(*f.split('/')) |
| |
| def writeFile(fname, contents): |
| dir = os.path.split(fname)[0] |
| if dir and not os.path.exists(dir): |
| mkdirs(dir) |
| f = open(fname, 'w') |
| f.write(contents) |
| f.close() |
| |
| def readFile(fname): |
| f = open(fname) |
| r = f.read() |
| f.close() |
| return r |
| |
| def writeProfile(dict): |
| contents = [ "%s: %s\n" % (k, v) for k, v in dict.iteritems() ] |
| writeFile(_mhprofile, "".join(contents)) |
| |
| def writeContext(folder): |
| folder = normF(folder) |
| writeFile(os.path.join(_mhpath, "context"), |
| "Current-Folder: %s\n" % folder) |
| |
| def writeCurMessage(folder, cur): |
| folder = normF(folder) |
| writeFile(os.path.join(_mhpath, folder, ".mh_sequences"), |
| "cur: %s\n"%cur) |
| |
| def writeMessage(folder, n, headers, body): |
| folder = normF(folder) |
| headers = "".join([ "%s: %s\n" % (k, v) for k, v in headers.iteritems() ]) |
| contents = "%s\n%s\n" % (headers,body) |
| mkdirs(os.path.join(_mhpath, folder)) |
| writeFile(os.path.join(_mhpath, folder, str(n)), contents) |
| |
| def getMH(): |
| return mhlib.MH(os.path.abspath(_mhpath), _mhprofile) |
| |
| def sortLines(s): |
| lines = s.split("\n") |
| lines = [ line.strip() for line in lines if len(line) >= 2 ] |
| lines.sort() |
| return lines |
| |
| # These next 2 functions are copied from test_glob.py. |
| def mkdirs(fname): |
| if os.path.exists(fname) or fname == '': |
| return |
| base, file = os.path.split(fname) |
| mkdirs(base) |
| os.mkdir(fname) |
| |
| def deltree(fname): |
| if not os.path.exists(fname): |
| return |
| for f in os.listdir(fname): |
| fullname = os.path.join(fname, f) |
| if os.path.isdir(fullname): |
| deltree(fullname) |
| else: |
| try: |
| os.unlink(fullname) |
| except: |
| pass |
| try: |
| os.rmdir(fname) |
| except: |
| pass |
| |
| class MhlibTests(unittest.TestCase): |
| def setUp(self): |
| deltree(_mhroot) |
| mkdirs(_mhpath) |
| writeProfile({'Path' : os.path.abspath(_mhpath), |
| 'Editor': 'emacs', |
| 'ignored-attribute': 'camping holiday'}) |
| # Note: These headers aren't really conformant to RFC822, but |
| # mhlib shouldn't care about that. |
| |
| # An inbox with a couple of messages. |
| writeMessage('inbox', 1, |
| {'From': 'Mrs. Premise', |
| 'To': 'Mrs. Conclusion', |
| 'Date': '18 July 2001'}, "Hullo, Mrs. Conclusion!\n") |
| writeMessage('inbox', 2, |
| {'From': 'Mrs. Conclusion', |
| 'To': 'Mrs. Premise', |
| 'Date': '29 July 2001'}, "Hullo, Mrs. Premise!\n") |
| |
| # A folder with many messages |
| for i in range(5, 101)+range(101, 201, 2): |
| writeMessage('wide', i, |
| {'From': 'nowhere', 'Subject': 'message #%s' % i}, |
| "This is message number %s\n" % i) |
| |
| # A deeply nested folder |
| def deep(folder, n): |
| writeMessage(folder, n, |
| {'Subject': 'Message %s/%s' % (folder, n) }, |
| "This is message number %s in %s\n" % (n, folder) ) |
| deep('deep/f1', 1) |
| deep('deep/f1', 2) |
| deep('deep/f1', 3) |
| deep('deep/f2', 4) |
| deep('deep/f2', 6) |
| deep('deep', 3) |
| deep('deep/f2/f3', 1) |
| deep('deep/f2/f3', 2) |
| |
| def tearDown(self): |
| deltree(_mhroot) |
| |
| def test_basic(self): |
| writeContext('inbox') |
| writeCurMessage('inbox', 2) |
| mh = getMH() |
| |
| eq = self.assertEquals |
| eq(mh.getprofile('Editor'), 'emacs') |
| eq(mh.getprofile('not-set'), None) |
| eq(mh.getpath(), os.path.abspath(_mhpath)) |
| eq(mh.getcontext(), 'inbox') |
| |
| mh.setcontext('wide') |
| eq(mh.getcontext(), 'wide') |
| eq(readFile(os.path.join(_mhpath, 'context')), |
| "Current-Folder: wide\n") |
| |
| mh.setcontext('inbox') |
| |
| inbox = mh.openfolder('inbox') |
| eq(inbox.getfullname(), |
| os.path.join(os.path.abspath(_mhpath), 'inbox')) |
| eq(inbox.getsequencesfilename(), |
| os.path.join(os.path.abspath(_mhpath), 'inbox', '.mh_sequences')) |
| eq(inbox.getmessagefilename(1), |
| os.path.join(os.path.abspath(_mhpath), 'inbox', '1')) |
| |
| def test_listfolders(self): |
| mh = getMH() |
| eq = self.assertEquals |
| |
| folders = mh.listfolders() |
| folders.sort() |
| eq(folders, ['deep', 'inbox', 'wide']) |
| |
| folders = mh.listallfolders() |
| folders.sort() |
| tfolders = map(normF, ['deep', 'deep/f1', 'deep/f2', 'deep/f2/f3', |
| 'inbox', 'wide']) |
| tfolders.sort() |
| eq(folders, tfolders) |
| |
| folders = mh.listsubfolders('deep') |
| folders.sort() |
| eq(folders, map(normF, ['deep/f1', 'deep/f2'])) |
| |
| folders = mh.listallsubfolders('deep') |
| folders.sort() |
| eq(folders, map(normF, ['deep/f1', 'deep/f2', 'deep/f2/f3'])) |
| eq(mh.listsubfolders(normF('deep/f2')), [normF('deep/f2/f3')]) |
| |
| eq(mh.listsubfolders('inbox'), []) |
| eq(mh.listallsubfolders('inbox'), []) |
| |
| def test_sequence(self): |
| mh = getMH() |
| eq = self.assertEquals |
| writeCurMessage('wide', 55) |
| |
| f = mh.openfolder('wide') |
| all = f.listmessages() |
| eq(all, range(5, 101)+range(101, 201, 2)) |
| eq(f.getcurrent(), 55) |
| f.setcurrent(99) |
| eq(readFile(os.path.join(_mhpath, 'wide', '.mh_sequences')), |
| 'cur: 99\n') |
| |
| def seqeq(seq, val): |
| eq(f.parsesequence(seq), val) |
| |
| seqeq('5-55', range(5, 56)) |
| seqeq('90-108', range(90, 101)+range(101, 109, 2)) |
| seqeq('90-108', range(90, 101)+range(101, 109, 2)) |
| |
| seqeq('10:10', range(10, 20)) |
| seqeq('10:+10', range(10, 20)) |
| seqeq('101:10', range(101, 121, 2)) |
| |
| seqeq('cur', [99]) |
| seqeq('.', [99]) |
| seqeq('prev', [98]) |
| seqeq('next', [100]) |
| seqeq('cur:-3', [97, 98, 99]) |
| seqeq('first-cur', range(5, 100)) |
| seqeq('150-last', range(151, 201, 2)) |
| seqeq('prev-next', [98, 99, 100]) |
| |
| lowprimes = [5, 7, 11, 13, 17, 19, 23, 29] |
| lowcompos = [x for x in range(5, 31) if not x in lowprimes ] |
| f.putsequences({'cur': [5], |
| 'lowprime': lowprimes, |
| 'lowcompos': lowcompos}) |
| seqs = readFile(os.path.join(_mhpath, 'wide', '.mh_sequences')) |
| seqs = sortLines(seqs) |
| eq(seqs, ["cur: 5", |
| "lowcompos: 6 8-10 12 14-16 18 20-22 24-28 30", |
| "lowprime: 5 7 11 13 17 19 23 29"]) |
| |
| seqeq('lowprime', lowprimes) |
| seqeq('lowprime:1', [5]) |
| seqeq('lowprime:2', [5, 7]) |
| seqeq('lowprime:-2', [23, 29]) |
| |
| ## Not supported |
| #seqeq('lowprime:first', [5]) |
| #seqeq('lowprime:last', [29]) |
| #seqeq('lowprime:prev', [29]) |
| #seqeq('lowprime:next', [29]) |
| |
| def test_modify(self): |
| mh = getMH() |
| eq = self.assertEquals |
| |
| mh.makefolder("dummy1") |
| self.assert_("dummy1" in mh.listfolders()) |
| path = os.path.join(_mhpath, "dummy1") |
| self.assert_(os.path.exists(path)) |
| |
| f = mh.openfolder('dummy1') |
| def create(n): |
| msg = "From: foo\nSubject: %s\n\nDummy Message %s\n" % (n,n) |
| f.createmessage(n, StringIO.StringIO(msg)) |
| |
| create(7) |
| create(8) |
| create(9) |
| |
| eq(readFile(f.getmessagefilename(9)), |
| "From: foo\nSubject: 9\n\nDummy Message 9\n") |
| |
| eq(f.listmessages(), [7, 8, 9]) |
| files = os.listdir(path) |
| files.sort() |
| eq(files, ['7', '8', '9']) |
| |
| f.removemessages(['7', '8']) |
| files = os.listdir(path) |
| files.sort() |
| eq(files, [',7', ',8', '9']) |
| eq(f.listmessages(), [9]) |
| create(10) |
| create(11) |
| create(12) |
| |
| mh.makefolder("dummy2") |
| f2 = mh.openfolder("dummy2") |
| eq(f2.listmessages(), []) |
| f.movemessage(10, f2, 3) |
| f.movemessage(11, f2, 5) |
| eq(f.listmessages(), [9, 12]) |
| eq(f2.listmessages(), [3, 5]) |
| eq(readFile(f2.getmessagefilename(3)), |
| "From: foo\nSubject: 10\n\nDummy Message 10\n") |
| |
| f.copymessage(9, f2, 4) |
| eq(f.listmessages(), [9, 12]) |
| eq(readFile(f2.getmessagefilename(4)), |
| "From: foo\nSubject: 9\n\nDummy Message 9\n") |
| |
| f.refilemessages([9, 12], f2) |
| eq(f.listmessages(), []) |
| eq(f2.listmessages(), [3, 4, 5, 6, 7]) |
| eq(readFile(f2.getmessagefilename(7)), |
| "From: foo\nSubject: 12\n\nDummy Message 12\n") |
| # XXX This should check that _copysequences does the right thing. |
| |
| mh.deletefolder('dummy1') |
| mh.deletefolder('dummy2') |
| self.assert_('dummy1' not in mh.listfolders()) |
| self.assert_(not os.path.exists(path)) |
| |
| def test_read(self): |
| mh = getMH() |
| eq = self.assertEquals |
| |
| f = mh.openfolder('inbox') |
| msg = f.openmessage(1) |
| # Check some basic stuff from rfc822 |
| eq(msg.getheader('From'), "Mrs. Premise") |
| eq(msg.getheader('To'), "Mrs. Conclusion") |
| |
| # Okay, we have the right message. Let's check the stuff from |
| # mhlib. |
| lines = sortLines(msg.getheadertext()) |
| eq(lines, ["Date: 18 July 2001", |
| "From: Mrs. Premise", |
| "To: Mrs. Conclusion"]) |
| lines = sortLines(msg.getheadertext(lambda h: len(h)==4)) |
| eq(lines, ["Date: 18 July 2001", |
| "From: Mrs. Premise"]) |
| eq(msg.getbodytext(), "Hullo, Mrs. Conclusion!\n\n") |
| eq(msg.getbodytext(0), "Hullo, Mrs. Conclusion!\n\n") |
| |
| # XXXX there should be a better way to reclaim the file handle |
| msg.fp.close() |
| del msg |
| |
| |
| def test_main(): |
| run_unittest(MhlibTests) |
| |
| |
| if __name__ == "__main__": |
| test_main() |