""" | |
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.test_support import run_unittest, TESTFN, import_module | |
import os, StringIO | |
import sys | |
mhlib = import_module('mhlib', deprecated=True) | |
if (sys.platform.startswith("win") or sys.platform=="riscos" or | |
sys.platform.startswith("atheos")): | |
# mhlib.updateline() renames a file to the name of a file that already | |
# exists. That causes a reasonable OS <wink> to complain in test_sequence | |
# here, like the "OSError: [Errno 17] File exists" raised on Windows. | |
# mhlib's listsubfolders() and listallfolders() do something with | |
# link counts, and that causes test_listfolders() here to get back | |
# an empty list from its call of listallfolders(). | |
# The other tests here pass on Windows. | |
raise unittest.SkipTest("skipped on %s -- " % sys.platform + | |
"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.assertEqual | |
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.assertEqual | |
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.assertEqual | |
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.assertEqual | |
mh.makefolder("dummy1") | |
self.assertIn("dummy1", mh.listfolders()) | |
path = os.path.join(_mhpath, "dummy1") | |
self.assertTrue(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.assertNotIn('dummy1', mh.listfolders()) | |
self.assertTrue(not os.path.exists(path)) | |
def test_read(self): | |
mh = getMH() | |
eq = self.assertEqual | |
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() |