cpython/Lib/test/test_mailbox.py
Thomas Wouters 9fe394c1be Merged revisions 53538-53622 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r53545 | andrew.kuchling | 2007-01-24 21:06:41 +0100 (Wed, 24 Jan 2007) | 1 line

  Strengthen warning about using lock()
........
  r53556 | thomas.heller | 2007-01-25 19:34:14 +0100 (Thu, 25 Jan 2007) | 3 lines

  Fix for #1643874: When calling SysAllocString, create a PyCObject
  which will eventually call SysFreeString to free the BSTR resource.
........
  r53563 | andrew.kuchling | 2007-01-25 21:02:13 +0100 (Thu, 25 Jan 2007) | 1 line

  Add item
........
  r53564 | brett.cannon | 2007-01-25 21:22:02 +0100 (Thu, 25 Jan 2007) | 8 lines

  Fix time.strptime's %U support.  Basically rewrote the algorithm to be more
  generic so that one only has to shift certain values based on whether the week
  was specified to start on Monday or Sunday.  Cut out a lot of edge case code
  compared to the previous version.  Also broke algorithm out into its own
  function (that is private to the module).

  Fixes bug #1643943 (thanks Biran Nahas for the report).
........
  r53570 | brett.cannon | 2007-01-26 00:30:39 +0100 (Fri, 26 Jan 2007) | 4 lines

  Remove specific mention of my name and email address from modules.  Not really
  needed and all bug reports should go to the bug tracker, not directly to me.
  Plus I am not the only person to have edited these files at this point.
........
  r53573 | fred.drake | 2007-01-26 17:28:44 +0100 (Fri, 26 Jan 2007) | 1 line

  fix typo (extraneous ")")
........
  r53575 | georg.brandl | 2007-01-27 18:43:02 +0100 (Sat, 27 Jan 2007) | 4 lines

  Patch #1638243: the compiler package is now able to correctly compile
  a with statement; previously, executing code containing a with statement
  compiled by the compiler package crashed the interpreter.
........
  r53578 | georg.brandl | 2007-01-27 18:59:42 +0100 (Sat, 27 Jan 2007) | 3 lines

  Patch #1634778: add missing encoding aliases for iso8859_15 and
  iso8859_16.
........
  r53579 | georg.brandl | 2007-01-27 20:38:50 +0100 (Sat, 27 Jan 2007) | 2 lines

  Bug #1645944: os.access now returns bool but docstring is not updated
........
  r53590 | brett.cannon | 2007-01-28 21:58:00 +0100 (Sun, 28 Jan 2007) | 2 lines

  Use the thread lock's context manager instead of a try/finally statement.
........
  r53591 | brett.cannon | 2007-01-29 05:41:44 +0100 (Mon, 29 Jan 2007) | 2 lines

  Add a test for slicing an exception.
........
  r53594 | andrew.kuchling | 2007-01-29 21:21:43 +0100 (Mon, 29 Jan 2007) | 1 line

  Minor edits to the curses HOWTO
........
  r53596 | andrew.kuchling | 2007-01-29 21:55:40 +0100 (Mon, 29 Jan 2007) | 1 line

  Various minor edits
........
  r53597 | andrew.kuchling | 2007-01-29 22:28:48 +0100 (Mon, 29 Jan 2007) | 1 line

  More edits
........
  r53601 | tim.peters | 2007-01-30 04:03:46 +0100 (Tue, 30 Jan 2007) | 2 lines

  Whitespace normalization.
........
  r53603 | georg.brandl | 2007-01-30 21:21:30 +0100 (Tue, 30 Jan 2007) | 2 lines

  Bug #1648191: typo in docs.
........
  r53605 | brett.cannon | 2007-01-30 22:34:36 +0100 (Tue, 30 Jan 2007) | 8 lines

  No more raising of string exceptions!

  The next step of PEP 352 (for 2.6) causes raising a string exception to trigger
  a TypeError.  Trying to catch a string exception raises a DeprecationWarning.
  References to string exceptions has been removed from the docs since they are
  now just an error.
........
  r53618 | raymond.hettinger | 2007-02-01 22:02:59 +0100 (Thu, 01 Feb 2007) | 1 line

  Bug #1648179:  set.update() not recognizing __iter__ overrides in dict subclasses.
........
2007-02-05 01:24:16 +00:00

1842 lines
73 KiB
Python

import os
import sys
import time
import stat
import socket
import email
import email.message
import rfc822
import re
import StringIO
from test import test_support
import unittest
import mailbox
import glob
try:
import fcntl
except ImportError:
pass
class TestBase(unittest.TestCase):
def _check_sample(self, msg):
# Inspect a mailbox.Message representation of the sample message
self.assert_(isinstance(msg, email.message.Message))
self.assert_(isinstance(msg, mailbox.Message))
for key, value in _sample_headers.iteritems():
self.assert_(value in msg.get_all(key))
self.assert_(msg.is_multipart())
self.assert_(len(msg.get_payload()) == len(_sample_payloads))
for i, payload in enumerate(_sample_payloads):
part = msg.get_payload(i)
self.assert_(isinstance(part, email.message.Message))
self.assert_(not isinstance(part, mailbox.Message))
self.assert_(part.get_payload() == payload)
def _delete_recursively(self, target):
# Delete a file or delete a directory recursively
if os.path.isdir(target):
for path, dirs, files in os.walk(target, topdown=False):
for name in files:
os.remove(os.path.join(path, name))
for name in dirs:
os.rmdir(os.path.join(path, name))
os.rmdir(target)
elif os.path.exists(target):
os.remove(target)
class TestMailbox(TestBase):
_factory = None # Overridden by subclasses to reuse tests
_template = 'From: foo\n\n%s'
def setUp(self):
self._path = test_support.TESTFN
self._box = self._factory(self._path)
def tearDown(self):
self._box.close()
self._delete_recursively(self._path)
def test_add(self):
# Add copies of a sample message
keys = []
keys.append(self._box.add(self._template % 0))
self.assert_(len(self._box) == 1)
keys.append(self._box.add(mailbox.Message(_sample_message)))
self.assert_(len(self._box) == 2)
keys.append(self._box.add(email.message_from_string(_sample_message)))
self.assert_(len(self._box) == 3)
keys.append(self._box.add(StringIO.StringIO(_sample_message)))
self.assert_(len(self._box) == 4)
keys.append(self._box.add(_sample_message))
self.assert_(len(self._box) == 5)
self.assert_(self._box.get_string(keys[0]) == self._template % 0)
for i in (1, 2, 3, 4):
self._check_sample(self._box[keys[i]])
def test_remove(self):
# Remove messages using remove()
self._test_remove_or_delitem(self._box.remove)
def test_delitem(self):
# Remove messages using __delitem__()
self._test_remove_or_delitem(self._box.__delitem__)
def _test_remove_or_delitem(self, method):
# (Used by test_remove() and test_delitem().)
key0 = self._box.add(self._template % 0)
key1 = self._box.add(self._template % 1)
self.assert_(len(self._box) == 2)
method(key0)
l = len(self._box)
self.assert_(l == 1, "actual l: %s" % l)
self.assertRaises(KeyError, lambda: self._box[key0])
self.assertRaises(KeyError, lambda: method(key0))
self.assert_(self._box.get_string(key1) == self._template % 1)
key2 = self._box.add(self._template % 2)
self.assert_(len(self._box) == 2)
method(key2)
l = len(self._box)
self.assert_(l == 1, "actual l: %s" % l)
self.assertRaises(KeyError, lambda: self._box[key2])
self.assertRaises(KeyError, lambda: method(key2))
self.assert_(self._box.get_string(key1) == self._template % 1)
method(key1)
self.assert_(len(self._box) == 0)
self.assertRaises(KeyError, lambda: self._box[key1])
self.assertRaises(KeyError, lambda: method(key1))
def test_discard(self, repetitions=10):
# Discard messages
key0 = self._box.add(self._template % 0)
key1 = self._box.add(self._template % 1)
self.assert_(len(self._box) == 2)
self._box.discard(key0)
self.assert_(len(self._box) == 1)
self.assertRaises(KeyError, lambda: self._box[key0])
self._box.discard(key0)
self.assert_(len(self._box) == 1)
self.assertRaises(KeyError, lambda: self._box[key0])
def test_get(self):
# Retrieve messages using get()
key0 = self._box.add(self._template % 0)
msg = self._box.get(key0)
self.assert_(msg['from'] == 'foo')
self.assert_(msg.get_payload() == '0')
self.assert_(self._box.get('foo') is None)
self.assert_(self._box.get('foo', False) is False)
self._box.close()
self._box = self._factory(self._path, factory=rfc822.Message)
key1 = self._box.add(self._template % 1)
msg = self._box.get(key1)
self.assert_(msg['from'] == 'foo')
self.assert_(msg.fp.read() == '1')
def test_getitem(self):
# Retrieve message using __getitem__()
key0 = self._box.add(self._template % 0)
msg = self._box[key0]
self.assert_(msg['from'] == 'foo')
self.assert_(msg.get_payload() == '0')
self.assertRaises(KeyError, lambda: self._box['foo'])
self._box.discard(key0)
self.assertRaises(KeyError, lambda: self._box[key0])
def test_get_message(self):
# Get Message representations of messages
key0 = self._box.add(self._template % 0)
key1 = self._box.add(_sample_message)
msg0 = self._box.get_message(key0)
self.assert_(isinstance(msg0, mailbox.Message))
self.assert_(msg0['from'] == 'foo')
self.assert_(msg0.get_payload() == '0')
self._check_sample(self._box.get_message(key1))
def test_get_string(self):
# Get string representations of messages
key0 = self._box.add(self._template % 0)
key1 = self._box.add(_sample_message)
self.assert_(self._box.get_string(key0) == self._template % 0)
self.assert_(self._box.get_string(key1) == _sample_message)
def test_get_file(self):
# Get file representations of messages
key0 = self._box.add(self._template % 0)
key1 = self._box.add(_sample_message)
self.assert_(self._box.get_file(key0).read().replace(os.linesep, '\n')
== self._template % 0)
self.assert_(self._box.get_file(key1).read().replace(os.linesep, '\n')
== _sample_message)
def test_iterkeys(self):
# Get keys using iterkeys()
self._check_iteration(self._box.iterkeys, do_keys=True, do_values=False)
def test_keys(self):
# Get keys using keys()
self._check_iteration(self._box.keys, do_keys=True, do_values=False)
def test_itervalues(self):
# Get values using itervalues()
self._check_iteration(self._box.itervalues, do_keys=False,
do_values=True)
def test_iter(self):
# Get values using __iter__()
self._check_iteration(self._box.__iter__, do_keys=False,
do_values=True)
def test_values(self):
# Get values using values()
self._check_iteration(self._box.values, do_keys=False, do_values=True)
def test_iteritems(self):
# Get keys and values using iteritems()
self._check_iteration(self._box.iteritems, do_keys=True,
do_values=True)
def test_items(self):
# Get keys and values using items()
self._check_iteration(self._box.items, do_keys=True, do_values=True)
def _check_iteration(self, method, do_keys, do_values, repetitions=10):
for value in method():
self.fail("Not empty")
keys, values = [], []
for i in xrange(repetitions):
keys.append(self._box.add(self._template % i))
values.append(self._template % i)
if do_keys and not do_values:
returned_keys = list(method())
elif do_values and not do_keys:
returned_values = list(method())
else:
returned_keys, returned_values = [], []
for key, value in method():
returned_keys.append(key)
returned_values.append(value)
if do_keys:
self.assert_(len(keys) == len(returned_keys))
self.assert_(set(keys) == set(returned_keys))
if do_values:
count = 0
for value in returned_values:
self.assert_(value['from'] == 'foo')
self.assert_(int(value.get_payload()) < repetitions)
count += 1
self.assert_(len(values) == count)
def test_contains(self):
# Check existence of keys using __contains__()
method = self._box.__contains__
self.assert_(not method('foo'))
key0 = self._box.add(self._template % 0)
self.assert_(method(key0))
self.assert_(not method('foo'))
key1 = self._box.add(self._template % 1)
self.assert_(method(key1))
self.assert_(method(key0))
self.assert_(not method('foo'))
self._box.remove(key0)
self.assert_(not method(key0))
self.assert_(method(key1))
self.assert_(not method('foo'))
self._box.remove(key1)
self.assert_(not method(key1))
self.assert_(not method(key0))
self.assert_(not method('foo'))
def test_len(self, repetitions=10):
# Get message count
keys = []
for i in xrange(repetitions):
self.assert_(len(self._box) == i)
keys.append(self._box.add(self._template % i))
self.assert_(len(self._box) == i + 1)
for i in xrange(repetitions):
self.assert_(len(self._box) == repetitions - i)
self._box.remove(keys[i])
self.assert_(len(self._box) == repetitions - i - 1)
def test_set_item(self):
# Modify messages using __setitem__()
key0 = self._box.add(self._template % 'original 0')
self.assert_(self._box.get_string(key0) == \
self._template % 'original 0')
key1 = self._box.add(self._template % 'original 1')
self.assert_(self._box.get_string(key1) == \
self._template % 'original 1')
self._box[key0] = self._template % 'changed 0'
self.assert_(self._box.get_string(key0) == \
self._template % 'changed 0')
self._box[key1] = self._template % 'changed 1'
self.assert_(self._box.get_string(key1) == \
self._template % 'changed 1')
self._box[key0] = _sample_message
self._check_sample(self._box[key0])
self._box[key1] = self._box[key0]
self._check_sample(self._box[key1])
self._box[key0] = self._template % 'original 0'
self.assert_(self._box.get_string(key0) ==
self._template % 'original 0')
self._check_sample(self._box[key1])
self.assertRaises(KeyError,
lambda: self._box.__setitem__('foo', 'bar'))
self.assertRaises(KeyError, lambda: self._box['foo'])
self.assert_(len(self._box) == 2)
def test_clear(self, iterations=10):
# Remove all messages using clear()
keys = []
for i in xrange(iterations):
self._box.add(self._template % i)
for i, key in enumerate(keys):
self.assert_(self._box.get_string(key) == self._template % i)
self._box.clear()
self.assert_(len(self._box) == 0)
for i, key in enumerate(keys):
self.assertRaises(KeyError, lambda: self._box.get_string(key))
def test_pop(self):
# Get and remove a message using pop()
key0 = self._box.add(self._template % 0)
self.assert_(key0 in self._box)
key1 = self._box.add(self._template % 1)
self.assert_(key1 in self._box)
self.assert_(self._box.pop(key0).get_payload() == '0')
self.assert_(key0 not in self._box)
self.assert_(key1 in self._box)
key2 = self._box.add(self._template % 2)
self.assert_(key2 in self._box)
self.assert_(self._box.pop(key2).get_payload() == '2')
self.assert_(key2 not in self._box)
self.assert_(key1 in self._box)
self.assert_(self._box.pop(key1).get_payload() == '1')
self.assert_(key1 not in self._box)
self.assert_(len(self._box) == 0)
def test_popitem(self, iterations=10):
# Get and remove an arbitrary (key, message) using popitem()
keys = []
for i in xrange(10):
keys.append(self._box.add(self._template % i))
seen = []
for i in xrange(10):
key, msg = self._box.popitem()
self.assert_(key in keys)
self.assert_(key not in seen)
seen.append(key)
self.assert_(int(msg.get_payload()) == keys.index(key))
self.assert_(len(self._box) == 0)
for key in keys:
self.assertRaises(KeyError, lambda: self._box[key])
def test_update(self):
# Modify multiple messages using update()
key0 = self._box.add(self._template % 'original 0')
key1 = self._box.add(self._template % 'original 1')
key2 = self._box.add(self._template % 'original 2')
self._box.update({key0: self._template % 'changed 0',
key2: _sample_message})
self.assert_(len(self._box) == 3)
self.assert_(self._box.get_string(key0) ==
self._template % 'changed 0')
self.assert_(self._box.get_string(key1) ==
self._template % 'original 1')
self._check_sample(self._box[key2])
self._box.update([(key2, self._template % 'changed 2'),
(key1, self._template % 'changed 1'),
(key0, self._template % 'original 0')])
self.assert_(len(self._box) == 3)
self.assert_(self._box.get_string(key0) ==
self._template % 'original 0')
self.assert_(self._box.get_string(key1) ==
self._template % 'changed 1')
self.assert_(self._box.get_string(key2) ==
self._template % 'changed 2')
self.assertRaises(KeyError,
lambda: self._box.update({'foo': 'bar',
key0: self._template % "changed 0"}))
self.assert_(len(self._box) == 3)
self.assert_(self._box.get_string(key0) ==
self._template % "changed 0")
self.assert_(self._box.get_string(key1) ==
self._template % "changed 1")
self.assert_(self._box.get_string(key2) ==
self._template % "changed 2")
def test_flush(self):
# Write changes to disk
self._test_flush_or_close(self._box.flush)
def test_lock_unlock(self):
# Lock and unlock the mailbox
self.assert_(not os.path.exists(self._get_lock_path()))
self._box.lock()
self.assert_(os.path.exists(self._get_lock_path()))
self._box.unlock()
self.assert_(not os.path.exists(self._get_lock_path()))
def test_close(self):
# Close mailbox and flush changes to disk
self._test_flush_or_close(self._box.close)
def _test_flush_or_close(self, method):
contents = [self._template % i for i in xrange(3)]
self._box.add(contents[0])
self._box.add(contents[1])
self._box.add(contents[2])
method()
self._box = self._factory(self._path)
keys = self._box.keys()
self.assert_(len(keys) == 3)
for key in keys:
self.assert_(self._box.get_string(key) in contents)
def test_dump_message(self):
# Write message representations to disk
for input in (email.message_from_string(_sample_message),
_sample_message, StringIO.StringIO(_sample_message)):
output = StringIO.StringIO()
self._box._dump_message(input, output)
self.assert_(output.getvalue() ==
_sample_message.replace('\n', os.linesep))
output = StringIO.StringIO()
self.assertRaises(TypeError,
lambda: self._box._dump_message(None, output))
def _get_lock_path(self):
# Return the path of the dot lock file. May be overridden.
return self._path + '.lock'
class TestMailboxSuperclass(TestBase):
def test_notimplemented(self):
# Test that all Mailbox methods raise NotImplementedException.
box = mailbox.Mailbox('path')
self.assertRaises(NotImplementedError, lambda: box.add(''))
self.assertRaises(NotImplementedError, lambda: box.remove(''))
self.assertRaises(NotImplementedError, lambda: box.__delitem__(''))
self.assertRaises(NotImplementedError, lambda: box.discard(''))
self.assertRaises(NotImplementedError, lambda: box.__setitem__('', ''))
self.assertRaises(NotImplementedError, lambda: box.iterkeys())
self.assertRaises(NotImplementedError, lambda: box.keys())
self.assertRaises(NotImplementedError, lambda: box.itervalues().next())
self.assertRaises(NotImplementedError, lambda: box.__iter__().next())
self.assertRaises(NotImplementedError, lambda: box.values())
self.assertRaises(NotImplementedError, lambda: box.iteritems().next())
self.assertRaises(NotImplementedError, lambda: box.items())
self.assertRaises(NotImplementedError, lambda: box.get(''))
self.assertRaises(NotImplementedError, lambda: box.__getitem__(''))
self.assertRaises(NotImplementedError, lambda: box.get_message(''))
self.assertRaises(NotImplementedError, lambda: box.get_string(''))
self.assertRaises(NotImplementedError, lambda: box.get_file(''))
self.assertRaises(NotImplementedError, lambda: '' in box)
self.assertRaises(NotImplementedError, lambda: box.__contains__(''))
self.assertRaises(NotImplementedError, lambda: box.__len__())
self.assertRaises(NotImplementedError, lambda: box.clear())
self.assertRaises(NotImplementedError, lambda: box.pop(''))
self.assertRaises(NotImplementedError, lambda: box.popitem())
self.assertRaises(NotImplementedError, lambda: box.update((('', ''),)))
self.assertRaises(NotImplementedError, lambda: box.flush())
self.assertRaises(NotImplementedError, lambda: box.lock())
self.assertRaises(NotImplementedError, lambda: box.unlock())
self.assertRaises(NotImplementedError, lambda: box.close())
class TestMaildir(TestMailbox):
_factory = lambda self, path, factory=None: mailbox.Maildir(path, factory)
def setUp(self):
TestMailbox.setUp(self)
if os.name in ('nt', 'os2') or sys.platform == 'cygwin':
self._box.colon = '!'
def test_add_MM(self):
# Add a MaildirMessage instance
msg = mailbox.MaildirMessage(self._template % 0)
msg.set_subdir('cur')
msg.set_info('foo')
key = self._box.add(msg)
self.assert_(os.path.exists(os.path.join(self._path, 'cur', '%s%sfoo' %
(key, self._box.colon))))
def test_get_MM(self):
# Get a MaildirMessage instance
msg = mailbox.MaildirMessage(self._template % 0)
msg.set_subdir('cur')
msg.set_flags('RF')
key = self._box.add(msg)
msg_returned = self._box.get_message(key)
self.assert_(isinstance(msg_returned, mailbox.MaildirMessage))
self.assert_(msg_returned.get_subdir() == 'cur')
self.assert_(msg_returned.get_flags() == 'FR')
def test_set_MM(self):
# Set with a MaildirMessage instance
msg0 = mailbox.MaildirMessage(self._template % 0)
msg0.set_flags('TP')
key = self._box.add(msg0)
msg_returned = self._box.get_message(key)
self.assert_(msg_returned.get_subdir() == 'new')
self.assert_(msg_returned.get_flags() == 'PT')
msg1 = mailbox.MaildirMessage(self._template % 1)
self._box[key] = msg1
msg_returned = self._box.get_message(key)
self.assert_(msg_returned.get_subdir() == 'new')
self.assert_(msg_returned.get_flags() == '')
self.assert_(msg_returned.get_payload() == '1')
msg2 = mailbox.MaildirMessage(self._template % 2)
msg2.set_info('2,S')
self._box[key] = msg2
self._box[key] = self._template % 3
msg_returned = self._box.get_message(key)
self.assert_(msg_returned.get_subdir() == 'new')
self.assert_(msg_returned.get_flags() == 'S')
self.assert_(msg_returned.get_payload() == '3')
def test_initialize_new(self):
# Initialize a non-existent mailbox
self.tearDown()
self._box = mailbox.Maildir(self._path)
self._check_basics(factory=rfc822.Message)
self._delete_recursively(self._path)
self._box = self._factory(self._path, factory=None)
self._check_basics()
def test_initialize_existing(self):
# Initialize an existing mailbox
self.tearDown()
for subdir in '', 'tmp', 'new', 'cur':
os.mkdir(os.path.normpath(os.path.join(self._path, subdir)))
self._box = mailbox.Maildir(self._path)
self._check_basics(factory=rfc822.Message)
self._box = mailbox.Maildir(self._path, factory=None)
self._check_basics()
def _check_basics(self, factory=None):
# (Used by test_open_new() and test_open_existing().)
self.assertEqual(self._box._path, os.path.abspath(self._path))
self.assertEqual(self._box._factory, factory)
for subdir in '', 'tmp', 'new', 'cur':
path = os.path.join(self._path, subdir)
mode = os.stat(path)[stat.ST_MODE]
self.assert_(stat.S_ISDIR(mode), "Not a directory: '%s'" % path)
def test_list_folders(self):
# List folders
self._box.add_folder('one')
self._box.add_folder('two')
self._box.add_folder('three')
self.assert_(len(self._box.list_folders()) == 3)
self.assert_(set(self._box.list_folders()) ==
set(('one', 'two', 'three')))
def test_get_folder(self):
# Open folders
self._box.add_folder('foo.bar')
folder0 = self._box.get_folder('foo.bar')
folder0.add(self._template % 'bar')
self.assert_(os.path.isdir(os.path.join(self._path, '.foo.bar')))
folder1 = self._box.get_folder('foo.bar')
self.assert_(folder1.get_string(folder1.keys()[0]) == \
self._template % 'bar')
def test_add_and_remove_folders(self):
# Delete folders
self._box.add_folder('one')
self._box.add_folder('two')
self.assert_(len(self._box.list_folders()) == 2)
self.assert_(set(self._box.list_folders()) == set(('one', 'two')))
self._box.remove_folder('one')
self.assert_(len(self._box.list_folders()) == 1)
self.assert_(set(self._box.list_folders()) == set(('two',)))
self._box.add_folder('three')
self.assert_(len(self._box.list_folders()) == 2)
self.assert_(set(self._box.list_folders()) == set(('two', 'three')))
self._box.remove_folder('three')
self.assert_(len(self._box.list_folders()) == 1)
self.assert_(set(self._box.list_folders()) == set(('two',)))
self._box.remove_folder('two')
self.assert_(len(self._box.list_folders()) == 0)
self.assert_(self._box.list_folders() == [])
def test_clean(self):
# Remove old files from 'tmp'
foo_path = os.path.join(self._path, 'tmp', 'foo')
bar_path = os.path.join(self._path, 'tmp', 'bar')
f = open(foo_path, 'w')
f.write("@")
f.close()
f = open(bar_path, 'w')
f.write("@")
f.close()
self._box.clean()
self.assert_(os.path.exists(foo_path))
self.assert_(os.path.exists(bar_path))
foo_stat = os.stat(foo_path)
os.utime(foo_path, (time.time() - 129600 - 2,
foo_stat.st_mtime))
self._box.clean()
self.assert_(not os.path.exists(foo_path))
self.assert_(os.path.exists(bar_path))
def test_create_tmp(self, repetitions=10):
# Create files in tmp directory
hostname = socket.gethostname()
if '/' in hostname:
hostname = hostname.replace('/', r'\057')
if ':' in hostname:
hostname = hostname.replace(':', r'\072')
pid = os.getpid()
pattern = re.compile(r"(?P<time>\d+)\.M(?P<M>\d{1,6})P(?P<P>\d+)"
r"Q(?P<Q>\d+)\.(?P<host>[^:/]+)")
previous_groups = None
for x in xrange(repetitions):
tmp_file = self._box._create_tmp()
head, tail = os.path.split(tmp_file.name)
self.assertEqual(head, os.path.abspath(os.path.join(self._path,
"tmp")),
"File in wrong location: '%s'" % head)
match = pattern.match(tail)
self.assert_(match != None, "Invalid file name: '%s'" % tail)
groups = match.groups()
if previous_groups != None:
self.assert_(int(groups[0] >= previous_groups[0]),
"Non-monotonic seconds: '%s' before '%s'" %
(previous_groups[0], groups[0]))
self.assert_(int(groups[1] >= previous_groups[1]) or
groups[0] != groups[1],
"Non-monotonic milliseconds: '%s' before '%s'" %
(previous_groups[1], groups[1]))
self.assert_(int(groups[2]) == pid,
"Process ID mismatch: '%s' should be '%s'" %
(groups[2], pid))
self.assert_(int(groups[3]) == int(previous_groups[3]) + 1,
"Non-sequential counter: '%s' before '%s'" %
(previous_groups[3], groups[3]))
self.assert_(groups[4] == hostname,
"Host name mismatch: '%s' should be '%s'" %
(groups[4], hostname))
previous_groups = groups
tmp_file.write(_sample_message)
tmp_file.seek(0)
self.assert_(tmp_file.read() == _sample_message)
tmp_file.close()
file_count = len(os.listdir(os.path.join(self._path, "tmp")))
self.assert_(file_count == repetitions,
"Wrong file count: '%s' should be '%s'" %
(file_count, repetitions))
def test_refresh(self):
# Update the table of contents
self.assert_(self._box._toc == {})
key0 = self._box.add(self._template % 0)
key1 = self._box.add(self._template % 1)
self.assert_(self._box._toc == {})
self._box._refresh()
self.assert_(self._box._toc == {key0: os.path.join('new', key0),
key1: os.path.join('new', key1)})
key2 = self._box.add(self._template % 2)
self.assert_(self._box._toc == {key0: os.path.join('new', key0),
key1: os.path.join('new', key1)})
self._box._refresh()
self.assert_(self._box._toc == {key0: os.path.join('new', key0),
key1: os.path.join('new', key1),
key2: os.path.join('new', key2)})
def test_lookup(self):
# Look up message subpaths in the TOC
self.assertRaises(KeyError, lambda: self._box._lookup('foo'))
key0 = self._box.add(self._template % 0)
self.assert_(self._box._lookup(key0) == os.path.join('new', key0))
os.remove(os.path.join(self._path, 'new', key0))
self.assert_(self._box._toc == {key0: os.path.join('new', key0)})
self.assertRaises(KeyError, lambda: self._box._lookup(key0))
self.assert_(self._box._toc == {})
def test_lock_unlock(self):
# Lock and unlock the mailbox. For Maildir, this does nothing.
self._box.lock()
self._box.unlock()
def test_folder (self):
# Test for bug #1569790: verify that folders returned by .get_folder()
# use the same factory function.
def dummy_factory (s):
return None
box = self._factory(self._path, factory=dummy_factory)
folder = box.add_folder('folder1')
self.assert_(folder._factory is dummy_factory)
folder1_alias = box.get_folder('folder1')
self.assert_(folder1_alias._factory is dummy_factory)
class _TestMboxMMDF(TestMailbox):
def tearDown(self):
self._box.close()
self._delete_recursively(self._path)
for lock_remnant in glob.glob(self._path + '.*'):
os.remove(lock_remnant)
def test_add_from_string(self):
# Add a string starting with 'From ' to the mailbox
key = self._box.add('From foo@bar blah\nFrom: foo\n\n0')
self.assert_(self._box[key].get_from() == 'foo@bar blah')
self.assert_(self._box[key].get_payload() == '0')
def test_add_mbox_or_mmdf_message(self):
# Add an mboxMessage or MMDFMessage
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
msg = class_('From foo@bar blah\nFrom: foo\n\n0')
key = self._box.add(msg)
def test_open_close_open(self):
# Open and inspect previously-created mailbox
values = [self._template % i for i in xrange(3)]
for value in values:
self._box.add(value)
self._box.close()
mtime = os.path.getmtime(self._path)
self._box = self._factory(self._path)
self.assert_(len(self._box) == 3)
for key in self._box.iterkeys():
self.assert_(self._box.get_string(key) in values)
self._box.close()
self.assert_(mtime == os.path.getmtime(self._path))
def test_add_and_close(self):
# Verifying that closing a mailbox doesn't change added items
self._box.add(_sample_message)
for i in xrange(3):
self._box.add(self._template % i)
self._box.add(_sample_message)
self._box._file.flush()
self._box._file.seek(0)
contents = self._box._file.read()
self._box.close()
self.assert_(contents == open(self._path, 'rb').read())
self._box = self._factory(self._path)
def test_lock_conflict(self):
# Fork off a subprocess that will lock the file for 2 seconds,
# unlock it, and then exit.
if not hasattr(os, 'fork'):
return
pid = os.fork()
if pid == 0:
# In the child, lock the mailbox.
self._box.lock()
time.sleep(2)
self._box.unlock()
os._exit(0)
# In the parent, sleep a bit to give the child time to acquire
# the lock.
time.sleep(0.5)
try:
self.assertRaises(mailbox.ExternalClashError,
self._box.lock)
finally:
# Wait for child to exit. Locking should now succeed.
exited_pid, status = os.waitpid(pid, 0)
self._box.lock()
self._box.unlock()
def test_relock(self):
# Test case for bug #1575506: the mailbox class was locking the
# wrong file object in its flush() method.
msg = "Subject: sub\n\nbody\n"
key1 = self._box.add(msg)
self._box.flush()
self._box.close()
self._box = self._factory(self._path)
self._box.lock()
key2 = self._box.add(msg)
self._box.flush()
self.assert_(self._box._locked)
self._box.close()
class TestMbox(_TestMboxMMDF):
_factory = lambda self, path, factory=None: mailbox.mbox(path, factory)
class TestMMDF(_TestMboxMMDF):
_factory = lambda self, path, factory=None: mailbox.MMDF(path, factory)
class TestMH(TestMailbox):
_factory = lambda self, path, factory=None: mailbox.MH(path, factory)
def test_list_folders(self):
# List folders
self._box.add_folder('one')
self._box.add_folder('two')
self._box.add_folder('three')
self.assert_(len(self._box.list_folders()) == 3)
self.assert_(set(self._box.list_folders()) ==
set(('one', 'two', 'three')))
def test_get_folder(self):
# Open folders
def dummy_factory (s):
return None
self._box = self._factory(self._path, dummy_factory)
new_folder = self._box.add_folder('foo.bar')
folder0 = self._box.get_folder('foo.bar')
folder0.add(self._template % 'bar')
self.assert_(os.path.isdir(os.path.join(self._path, 'foo.bar')))
folder1 = self._box.get_folder('foo.bar')
self.assert_(folder1.get_string(folder1.keys()[0]) == \
self._template % 'bar')
# Test for bug #1569790: verify that folders returned by .get_folder()
# use the same factory function.
self.assert_(new_folder._factory is self._box._factory)
self.assert_(folder0._factory is self._box._factory)
def test_add_and_remove_folders(self):
# Delete folders
self._box.add_folder('one')
self._box.add_folder('two')
self.assert_(len(self._box.list_folders()) == 2)
self.assert_(set(self._box.list_folders()) == set(('one', 'two')))
self._box.remove_folder('one')
self.assert_(len(self._box.list_folders()) == 1)
self.assert_(set(self._box.list_folders()) == set(('two',)))
self._box.add_folder('three')
self.assert_(len(self._box.list_folders()) == 2)
self.assert_(set(self._box.list_folders()) == set(('two', 'three')))
self._box.remove_folder('three')
self.assert_(len(self._box.list_folders()) == 1)
self.assert_(set(self._box.list_folders()) == set(('two',)))
self._box.remove_folder('two')
self.assert_(len(self._box.list_folders()) == 0)
self.assert_(self._box.list_folders() == [])
def test_sequences(self):
# Get and set sequences
self.assert_(self._box.get_sequences() == {})
msg0 = mailbox.MHMessage(self._template % 0)
msg0.add_sequence('foo')
key0 = self._box.add(msg0)
self.assert_(self._box.get_sequences() == {'foo':[key0]})
msg1 = mailbox.MHMessage(self._template % 1)
msg1.set_sequences(['bar', 'replied', 'foo'])
key1 = self._box.add(msg1)
self.assert_(self._box.get_sequences() ==
{'foo':[key0, key1], 'bar':[key1], 'replied':[key1]})
msg0.set_sequences(['flagged'])
self._box[key0] = msg0
self.assert_(self._box.get_sequences() ==
{'foo':[key1], 'bar':[key1], 'replied':[key1],
'flagged':[key0]})
self._box.remove(key1)
self.assert_(self._box.get_sequences() == {'flagged':[key0]})
def test_pack(self):
# Pack the contents of the mailbox
msg0 = mailbox.MHMessage(self._template % 0)
msg1 = mailbox.MHMessage(self._template % 1)
msg2 = mailbox.MHMessage(self._template % 2)
msg3 = mailbox.MHMessage(self._template % 3)
msg0.set_sequences(['foo', 'unseen'])
msg1.set_sequences(['foo'])
msg2.set_sequences(['foo', 'flagged'])
msg3.set_sequences(['foo', 'bar', 'replied'])
key0 = self._box.add(msg0)
key1 = self._box.add(msg1)
key2 = self._box.add(msg2)
key3 = self._box.add(msg3)
self.assert_(self._box.get_sequences() ==
{'foo':[key0,key1,key2,key3], 'unseen':[key0],
'flagged':[key2], 'bar':[key3], 'replied':[key3]})
self._box.remove(key2)
self.assert_(self._box.get_sequences() ==
{'foo':[key0,key1,key3], 'unseen':[key0], 'bar':[key3],
'replied':[key3]})
self._box.pack()
self.assert_(self._box.keys() == [1, 2, 3])
key0 = key0
key1 = key0 + 1
key2 = key1 + 1
self.assert_(self._box.get_sequences() ==
{'foo':[1, 2, 3], 'unseen':[1], 'bar':[3], 'replied':[3]})
# Test case for packing while holding the mailbox locked.
key0 = self._box.add(msg1)
key1 = self._box.add(msg1)
key2 = self._box.add(msg1)
key3 = self._box.add(msg1)
self._box.remove(key0)
self._box.remove(key2)
self._box.lock()
self._box.pack()
self._box.unlock()
self.assert_(self._box.get_sequences() ==
{'foo':[1, 2, 3, 4, 5],
'unseen':[1], 'bar':[3], 'replied':[3]})
def _get_lock_path(self):
return os.path.join(self._path, '.mh_sequences.lock')
class TestBabyl(TestMailbox):
_factory = lambda self, path, factory=None: mailbox.Babyl(path, factory)
def tearDown(self):
self._box.close()
self._delete_recursively(self._path)
for lock_remnant in glob.glob(self._path + '.*'):
os.remove(lock_remnant)
def test_labels(self):
# Get labels from the mailbox
self.assert_(self._box.get_labels() == [])
msg0 = mailbox.BabylMessage(self._template % 0)
msg0.add_label('foo')
key0 = self._box.add(msg0)
self.assert_(self._box.get_labels() == ['foo'])
msg1 = mailbox.BabylMessage(self._template % 1)
msg1.set_labels(['bar', 'answered', 'foo'])
key1 = self._box.add(msg1)
self.assert_(set(self._box.get_labels()) == set(['foo', 'bar']))
msg0.set_labels(['blah', 'filed'])
self._box[key0] = msg0
self.assert_(set(self._box.get_labels()) ==
set(['foo', 'bar', 'blah']))
self._box.remove(key1)
self.assert_(set(self._box.get_labels()) == set(['blah']))
class TestMessage(TestBase):
_factory = mailbox.Message # Overridden by subclasses to reuse tests
def setUp(self):
self._path = test_support.TESTFN
def tearDown(self):
self._delete_recursively(self._path)
def test_initialize_with_eMM(self):
# Initialize based on email.message.Message instance
eMM = email.message_from_string(_sample_message)
msg = self._factory(eMM)
self._post_initialize_hook(msg)
self._check_sample(msg)
def test_initialize_with_string(self):
# Initialize based on string
msg = self._factory(_sample_message)
self._post_initialize_hook(msg)
self._check_sample(msg)
def test_initialize_with_file(self):
# Initialize based on contents of file
f = open(self._path, 'w+')
f.write(_sample_message)
f.seek(0)
msg = self._factory(f)
self._post_initialize_hook(msg)
self._check_sample(msg)
f.close()
def test_initialize_with_nothing(self):
# Initialize without arguments
msg = self._factory()
self._post_initialize_hook(msg)
self.assert_(isinstance(msg, email.message.Message))
self.assert_(isinstance(msg, mailbox.Message))
self.assert_(isinstance(msg, self._factory))
self.assert_(msg.keys() == [])
self.assert_(not msg.is_multipart())
self.assert_(msg.get_payload() == None)
def test_initialize_incorrectly(self):
# Initialize with invalid argument
self.assertRaises(TypeError, lambda: self._factory(object()))
def test_become_message(self):
# Take on the state of another message
eMM = email.message_from_string(_sample_message)
msg = self._factory()
msg._become_message(eMM)
self._check_sample(msg)
def test_explain_to(self):
# Copy self's format-specific data to other message formats.
# This test is superficial; better ones are in TestMessageConversion.
msg = self._factory()
for class_ in (mailbox.Message, mailbox.MaildirMessage,
mailbox.mboxMessage, mailbox.MHMessage,
mailbox.BabylMessage, mailbox.MMDFMessage):
other_msg = class_()
msg._explain_to(other_msg)
other_msg = email.message.Message()
self.assertRaises(TypeError, lambda: msg._explain_to(other_msg))
def _post_initialize_hook(self, msg):
# Overridden by subclasses to check extra things after initialization
pass
class TestMaildirMessage(TestMessage):
_factory = mailbox.MaildirMessage
def _post_initialize_hook(self, msg):
self.assert_(msg._subdir == 'new')
self.assert_(msg._info == '')
def test_subdir(self):
# Use get_subdir() and set_subdir()
msg = mailbox.MaildirMessage(_sample_message)
self.assert_(msg.get_subdir() == 'new')
msg.set_subdir('cur')
self.assert_(msg.get_subdir() == 'cur')
msg.set_subdir('new')
self.assert_(msg.get_subdir() == 'new')
self.assertRaises(ValueError, lambda: msg.set_subdir('tmp'))
self.assert_(msg.get_subdir() == 'new')
msg.set_subdir('new')
self.assert_(msg.get_subdir() == 'new')
self._check_sample(msg)
def test_flags(self):
# Use get_flags(), set_flags(), add_flag(), remove_flag()
msg = mailbox.MaildirMessage(_sample_message)
self.assert_(msg.get_flags() == '')
self.assert_(msg.get_subdir() == 'new')
msg.set_flags('F')
self.assert_(msg.get_subdir() == 'new')
self.assert_(msg.get_flags() == 'F')
msg.set_flags('SDTP')
self.assert_(msg.get_flags() == 'DPST')
msg.add_flag('FT')
self.assert_(msg.get_flags() == 'DFPST')
msg.remove_flag('TDRP')
self.assert_(msg.get_flags() == 'FS')
self.assert_(msg.get_subdir() == 'new')
self._check_sample(msg)
def test_date(self):
# Use get_date() and set_date()
msg = mailbox.MaildirMessage(_sample_message)
self.assert_(abs(msg.get_date() - time.time()) < 60)
msg.set_date(0.0)
self.assert_(msg.get_date() == 0.0)
def test_info(self):
# Use get_info() and set_info()
msg = mailbox.MaildirMessage(_sample_message)
self.assert_(msg.get_info() == '')
msg.set_info('1,foo=bar')
self.assert_(msg.get_info() == '1,foo=bar')
self.assertRaises(TypeError, lambda: msg.set_info(None))
self._check_sample(msg)
def test_info_and_flags(self):
# Test interaction of info and flag methods
msg = mailbox.MaildirMessage(_sample_message)
self.assert_(msg.get_info() == '')
msg.set_flags('SF')
self.assert_(msg.get_flags() == 'FS')
self.assert_(msg.get_info() == '2,FS')
msg.set_info('1,')
self.assert_(msg.get_flags() == '')
self.assert_(msg.get_info() == '1,')
msg.remove_flag('RPT')
self.assert_(msg.get_flags() == '')
self.assert_(msg.get_info() == '1,')
msg.add_flag('D')
self.assert_(msg.get_flags() == 'D')
self.assert_(msg.get_info() == '2,D')
self._check_sample(msg)
class _TestMboxMMDFMessage(TestMessage):
_factory = mailbox._mboxMMDFMessage
def _post_initialize_hook(self, msg):
self._check_from(msg)
def test_initialize_with_unixfrom(self):
# Initialize with a message that already has a _unixfrom attribute
msg = mailbox.Message(_sample_message)
msg.set_unixfrom('From foo@bar blah')
msg = mailbox.mboxMessage(msg)
self.assert_(msg.get_from() == 'foo@bar blah', msg.get_from())
def test_from(self):
# Get and set "From " line
msg = mailbox.mboxMessage(_sample_message)
self._check_from(msg)
msg.set_from('foo bar')
self.assert_(msg.get_from() == 'foo bar')
msg.set_from('foo@bar', True)
self._check_from(msg, 'foo@bar')
msg.set_from('blah@temp', time.localtime())
self._check_from(msg, 'blah@temp')
def test_flags(self):
# Use get_flags(), set_flags(), add_flag(), remove_flag()
msg = mailbox.mboxMessage(_sample_message)
self.assert_(msg.get_flags() == '')
msg.set_flags('F')
self.assert_(msg.get_flags() == 'F')
msg.set_flags('XODR')
self.assert_(msg.get_flags() == 'RODX')
msg.add_flag('FA')
self.assert_(msg.get_flags() == 'RODFAX')
msg.remove_flag('FDXA')
self.assert_(msg.get_flags() == 'RO')
self._check_sample(msg)
def _check_from(self, msg, sender=None):
# Check contents of "From " line
if sender is None:
sender = "MAILER-DAEMON"
self.assert_(re.match(sender + r" \w{3} \w{3} [\d ]\d [\d ]\d:\d{2}:"
r"\d{2} \d{4}", msg.get_from()) is not None)
class TestMboxMessage(_TestMboxMMDFMessage):
_factory = mailbox.mboxMessage
class TestMHMessage(TestMessage):
_factory = mailbox.MHMessage
def _post_initialize_hook(self, msg):
self.assert_(msg._sequences == [])
def test_sequences(self):
# Get, set, join, and leave sequences
msg = mailbox.MHMessage(_sample_message)
self.assert_(msg.get_sequences() == [])
msg.set_sequences(['foobar'])
self.assert_(msg.get_sequences() == ['foobar'])
msg.set_sequences([])
self.assert_(msg.get_sequences() == [])
msg.add_sequence('unseen')
self.assert_(msg.get_sequences() == ['unseen'])
msg.add_sequence('flagged')
self.assert_(msg.get_sequences() == ['unseen', 'flagged'])
msg.add_sequence('flagged')
self.assert_(msg.get_sequences() == ['unseen', 'flagged'])
msg.remove_sequence('unseen')
self.assert_(msg.get_sequences() == ['flagged'])
msg.add_sequence('foobar')
self.assert_(msg.get_sequences() == ['flagged', 'foobar'])
msg.remove_sequence('replied')
self.assert_(msg.get_sequences() == ['flagged', 'foobar'])
msg.set_sequences(['foobar', 'replied'])
self.assert_(msg.get_sequences() == ['foobar', 'replied'])
class TestBabylMessage(TestMessage):
_factory = mailbox.BabylMessage
def _post_initialize_hook(self, msg):
self.assert_(msg._labels == [])
def test_labels(self):
# Get, set, join, and leave labels
msg = mailbox.BabylMessage(_sample_message)
self.assert_(msg.get_labels() == [])
msg.set_labels(['foobar'])
self.assert_(msg.get_labels() == ['foobar'])
msg.set_labels([])
self.assert_(msg.get_labels() == [])
msg.add_label('filed')
self.assert_(msg.get_labels() == ['filed'])
msg.add_label('resent')
self.assert_(msg.get_labels() == ['filed', 'resent'])
msg.add_label('resent')
self.assert_(msg.get_labels() == ['filed', 'resent'])
msg.remove_label('filed')
self.assert_(msg.get_labels() == ['resent'])
msg.add_label('foobar')
self.assert_(msg.get_labels() == ['resent', 'foobar'])
msg.remove_label('unseen')
self.assert_(msg.get_labels() == ['resent', 'foobar'])
msg.set_labels(['foobar', 'answered'])
self.assert_(msg.get_labels() == ['foobar', 'answered'])
def test_visible(self):
# Get, set, and update visible headers
msg = mailbox.BabylMessage(_sample_message)
visible = msg.get_visible()
self.assert_(visible.keys() == [])
self.assert_(visible.get_payload() is None)
visible['User-Agent'] = 'FooBar 1.0'
visible['X-Whatever'] = 'Blah'
self.assert_(msg.get_visible().keys() == [])
msg.set_visible(visible)
visible = msg.get_visible()
self.assert_(visible.keys() == ['User-Agent', 'X-Whatever'])
self.assert_(visible['User-Agent'] == 'FooBar 1.0')
self.assert_(visible['X-Whatever'] == 'Blah')
self.assert_(visible.get_payload() is None)
msg.update_visible()
self.assert_(visible.keys() == ['User-Agent', 'X-Whatever'])
self.assert_(visible.get_payload() is None)
visible = msg.get_visible()
self.assert_(visible.keys() == ['User-Agent', 'Date', 'From', 'To',
'Subject'])
for header in ('User-Agent', 'Date', 'From', 'To', 'Subject'):
self.assert_(visible[header] == msg[header])
class TestMMDFMessage(_TestMboxMMDFMessage):
_factory = mailbox.MMDFMessage
class TestMessageConversion(TestBase):
def test_plain_to_x(self):
# Convert Message to all formats
for class_ in (mailbox.Message, mailbox.MaildirMessage,
mailbox.mboxMessage, mailbox.MHMessage,
mailbox.BabylMessage, mailbox.MMDFMessage):
msg_plain = mailbox.Message(_sample_message)
msg = class_(msg_plain)
self._check_sample(msg)
def test_x_to_plain(self):
# Convert all formats to Message
for class_ in (mailbox.Message, mailbox.MaildirMessage,
mailbox.mboxMessage, mailbox.MHMessage,
mailbox.BabylMessage, mailbox.MMDFMessage):
msg = class_(_sample_message)
msg_plain = mailbox.Message(msg)
self._check_sample(msg_plain)
def test_x_to_invalid(self):
# Convert all formats to an invalid format
for class_ in (mailbox.Message, mailbox.MaildirMessage,
mailbox.mboxMessage, mailbox.MHMessage,
mailbox.BabylMessage, mailbox.MMDFMessage):
self.assertRaises(TypeError, lambda: class_(False))
def test_maildir_to_maildir(self):
# Convert MaildirMessage to MaildirMessage
msg_maildir = mailbox.MaildirMessage(_sample_message)
msg_maildir.set_flags('DFPRST')
msg_maildir.set_subdir('cur')
date = msg_maildir.get_date()
msg = mailbox.MaildirMessage(msg_maildir)
self._check_sample(msg)
self.assert_(msg.get_flags() == 'DFPRST')
self.assert_(msg.get_subdir() == 'cur')
self.assert_(msg.get_date() == date)
def test_maildir_to_mboxmmdf(self):
# Convert MaildirMessage to mboxmessage and MMDFMessage
pairs = (('D', ''), ('F', 'F'), ('P', ''), ('R', 'A'), ('S', 'R'),
('T', 'D'), ('DFPRST', 'RDFA'))
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
msg_maildir = mailbox.MaildirMessage(_sample_message)
msg_maildir.set_date(0.0)
for setting, result in pairs:
msg_maildir.set_flags(setting)
msg = class_(msg_maildir)
self.assert_(msg.get_flags() == result)
self.assert_(msg.get_from() == 'MAILER-DAEMON %s' %
time.asctime(time.gmtime(0.0)))
msg_maildir.set_subdir('cur')
self.assert_(class_(msg_maildir).get_flags() == 'RODFA')
def test_maildir_to_mh(self):
# Convert MaildirMessage to MHMessage
msg_maildir = mailbox.MaildirMessage(_sample_message)
pairs = (('D', ['unseen']), ('F', ['unseen', 'flagged']),
('P', ['unseen']), ('R', ['unseen', 'replied']), ('S', []),
('T', ['unseen']), ('DFPRST', ['replied', 'flagged']))
for setting, result in pairs:
msg_maildir.set_flags(setting)
self.assert_(mailbox.MHMessage(msg_maildir).get_sequences() == \
result)
def test_maildir_to_babyl(self):
# Convert MaildirMessage to Babyl
msg_maildir = mailbox.MaildirMessage(_sample_message)
pairs = (('D', ['unseen']), ('F', ['unseen']),
('P', ['unseen', 'forwarded']), ('R', ['unseen', 'answered']),
('S', []), ('T', ['unseen', 'deleted']),
('DFPRST', ['deleted', 'answered', 'forwarded']))
for setting, result in pairs:
msg_maildir.set_flags(setting)
self.assert_(mailbox.BabylMessage(msg_maildir).get_labels() == \
result)
def test_mboxmmdf_to_maildir(self):
# Convert mboxMessage and MMDFMessage to MaildirMessage
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
msg_mboxMMDF = class_(_sample_message)
msg_mboxMMDF.set_from('foo@bar', time.gmtime(0.0))
pairs = (('R', 'S'), ('O', ''), ('D', 'T'), ('F', 'F'), ('A', 'R'),
('RODFA', 'FRST'))
for setting, result in pairs:
msg_mboxMMDF.set_flags(setting)
msg = mailbox.MaildirMessage(msg_mboxMMDF)
self.assert_(msg.get_flags() == result)
self.assert_(msg.get_date() == 0.0, msg.get_date())
msg_mboxMMDF.set_flags('O')
self.assert_(mailbox.MaildirMessage(msg_mboxMMDF).get_subdir() == \
'cur')
def test_mboxmmdf_to_mboxmmdf(self):
# Convert mboxMessage and MMDFMessage to mboxMessage and MMDFMessage
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
msg_mboxMMDF = class_(_sample_message)
msg_mboxMMDF.set_flags('RODFA')
msg_mboxMMDF.set_from('foo@bar')
for class2_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
msg2 = class2_(msg_mboxMMDF)
self.assert_(msg2.get_flags() == 'RODFA')
self.assert_(msg2.get_from() == 'foo@bar')
def test_mboxmmdf_to_mh(self):
# Convert mboxMessage and MMDFMessage to MHMessage
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
msg_mboxMMDF = class_(_sample_message)
pairs = (('R', []), ('O', ['unseen']), ('D', ['unseen']),
('F', ['unseen', 'flagged']),
('A', ['unseen', 'replied']),
('RODFA', ['replied', 'flagged']))
for setting, result in pairs:
msg_mboxMMDF.set_flags(setting)
self.assert_(mailbox.MHMessage(msg_mboxMMDF).get_sequences() \
== result)
def test_mboxmmdf_to_babyl(self):
# Convert mboxMessage and MMDFMessage to BabylMessage
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
msg = class_(_sample_message)
pairs = (('R', []), ('O', ['unseen']),
('D', ['unseen', 'deleted']), ('F', ['unseen']),
('A', ['unseen', 'answered']),
('RODFA', ['deleted', 'answered']))
for setting, result in pairs:
msg.set_flags(setting)
self.assert_(mailbox.BabylMessage(msg).get_labels() == result)
def test_mh_to_maildir(self):
# Convert MHMessage to MaildirMessage
pairs = (('unseen', ''), ('replied', 'RS'), ('flagged', 'FS'))
for setting, result in pairs:
msg = mailbox.MHMessage(_sample_message)
msg.add_sequence(setting)
self.assert_(mailbox.MaildirMessage(msg).get_flags() == result)
self.assert_(mailbox.MaildirMessage(msg).get_subdir() == 'cur')
msg = mailbox.MHMessage(_sample_message)
msg.add_sequence('unseen')
msg.add_sequence('replied')
msg.add_sequence('flagged')
self.assert_(mailbox.MaildirMessage(msg).get_flags() == 'FR')
self.assert_(mailbox.MaildirMessage(msg).get_subdir() == 'cur')
def test_mh_to_mboxmmdf(self):
# Convert MHMessage to mboxMessage and MMDFMessage
pairs = (('unseen', 'O'), ('replied', 'ROA'), ('flagged', 'ROF'))
for setting, result in pairs:
msg = mailbox.MHMessage(_sample_message)
msg.add_sequence(setting)
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
self.assert_(class_(msg).get_flags() == result)
msg = mailbox.MHMessage(_sample_message)
msg.add_sequence('unseen')
msg.add_sequence('replied')
msg.add_sequence('flagged')
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
self.assert_(class_(msg).get_flags() == 'OFA')
def test_mh_to_mh(self):
# Convert MHMessage to MHMessage
msg = mailbox.MHMessage(_sample_message)
msg.add_sequence('unseen')
msg.add_sequence('replied')
msg.add_sequence('flagged')
self.assert_(mailbox.MHMessage(msg).get_sequences() == \
['unseen', 'replied', 'flagged'])
def test_mh_to_babyl(self):
# Convert MHMessage to BabylMessage
pairs = (('unseen', ['unseen']), ('replied', ['answered']),
('flagged', []))
for setting, result in pairs:
msg = mailbox.MHMessage(_sample_message)
msg.add_sequence(setting)
self.assert_(mailbox.BabylMessage(msg).get_labels() == result)
msg = mailbox.MHMessage(_sample_message)
msg.add_sequence('unseen')
msg.add_sequence('replied')
msg.add_sequence('flagged')
self.assert_(mailbox.BabylMessage(msg).get_labels() == \
['unseen', 'answered'])
def test_babyl_to_maildir(self):
# Convert BabylMessage to MaildirMessage
pairs = (('unseen', ''), ('deleted', 'ST'), ('filed', 'S'),
('answered', 'RS'), ('forwarded', 'PS'), ('edited', 'S'),
('resent', 'PS'))
for setting, result in pairs:
msg = mailbox.BabylMessage(_sample_message)
msg.add_label(setting)
self.assert_(mailbox.MaildirMessage(msg).get_flags() == result)
self.assert_(mailbox.MaildirMessage(msg).get_subdir() == 'cur')
msg = mailbox.BabylMessage(_sample_message)
for label in ('unseen', 'deleted', 'filed', 'answered', 'forwarded',
'edited', 'resent'):
msg.add_label(label)
self.assert_(mailbox.MaildirMessage(msg).get_flags() == 'PRT')
self.assert_(mailbox.MaildirMessage(msg).get_subdir() == 'cur')
def test_babyl_to_mboxmmdf(self):
# Convert BabylMessage to mboxMessage and MMDFMessage
pairs = (('unseen', 'O'), ('deleted', 'ROD'), ('filed', 'RO'),
('answered', 'ROA'), ('forwarded', 'RO'), ('edited', 'RO'),
('resent', 'RO'))
for setting, result in pairs:
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
msg = mailbox.BabylMessage(_sample_message)
msg.add_label(setting)
self.assert_(class_(msg).get_flags() == result)
msg = mailbox.BabylMessage(_sample_message)
for label in ('unseen', 'deleted', 'filed', 'answered', 'forwarded',
'edited', 'resent'):
msg.add_label(label)
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
self.assert_(class_(msg).get_flags() == 'ODA')
def test_babyl_to_mh(self):
# Convert BabylMessage to MHMessage
pairs = (('unseen', ['unseen']), ('deleted', []), ('filed', []),
('answered', ['replied']), ('forwarded', []), ('edited', []),
('resent', []))
for setting, result in pairs:
msg = mailbox.BabylMessage(_sample_message)
msg.add_label(setting)
self.assert_(mailbox.MHMessage(msg).get_sequences() == result)
msg = mailbox.BabylMessage(_sample_message)
for label in ('unseen', 'deleted', 'filed', 'answered', 'forwarded',
'edited', 'resent'):
msg.add_label(label)
self.assert_(mailbox.MHMessage(msg).get_sequences() == \
['unseen', 'replied'])
def test_babyl_to_babyl(self):
# Convert BabylMessage to BabylMessage
msg = mailbox.BabylMessage(_sample_message)
msg.update_visible()
for label in ('unseen', 'deleted', 'filed', 'answered', 'forwarded',
'edited', 'resent'):
msg.add_label(label)
msg2 = mailbox.BabylMessage(msg)
self.assert_(msg2.get_labels() == ['unseen', 'deleted', 'filed',
'answered', 'forwarded', 'edited',
'resent'])
self.assert_(msg.get_visible().keys() == msg2.get_visible().keys())
for key in msg.get_visible().keys():
self.assert_(msg.get_visible()[key] == msg2.get_visible()[key])
class TestProxyFileBase(TestBase):
def _test_read(self, proxy):
# Read by byte
proxy.seek(0)
self.assert_(proxy.read() == 'bar')
proxy.seek(1)
self.assert_(proxy.read() == 'ar')
proxy.seek(0)
self.assert_(proxy.read(2) == 'ba')
proxy.seek(1)
self.assert_(proxy.read(-1) == 'ar')
proxy.seek(2)
self.assert_(proxy.read(1000) == 'r')
def _test_readline(self, proxy):
# Read by line
proxy.seek(0)
self.assert_(proxy.readline() == 'foo' + os.linesep)
self.assert_(proxy.readline() == 'bar' + os.linesep)
self.assert_(proxy.readline() == 'fred' + os.linesep)
self.assert_(proxy.readline() == 'bob')
proxy.seek(2)
self.assert_(proxy.readline() == 'o' + os.linesep)
proxy.seek(6 + 2 * len(os.linesep))
self.assert_(proxy.readline() == 'fred' + os.linesep)
proxy.seek(6 + 2 * len(os.linesep))
self.assert_(proxy.readline(2) == 'fr')
self.assert_(proxy.readline(-10) == 'ed' + os.linesep)
def _test_readlines(self, proxy):
# Read multiple lines
proxy.seek(0)
self.assert_(proxy.readlines() == ['foo' + os.linesep,
'bar' + os.linesep,
'fred' + os.linesep, 'bob'])
proxy.seek(0)
self.assert_(proxy.readlines(2) == ['foo' + os.linesep])
proxy.seek(3 + len(os.linesep))
self.assert_(proxy.readlines(4 + len(os.linesep)) ==
['bar' + os.linesep, 'fred' + os.linesep])
proxy.seek(3)
self.assert_(proxy.readlines(1000) == [os.linesep, 'bar' + os.linesep,
'fred' + os.linesep, 'bob'])
def _test_iteration(self, proxy):
# Iterate by line
proxy.seek(0)
iterator = iter(proxy)
self.assert_(iterator.next() == 'foo' + os.linesep)
self.assert_(iterator.next() == 'bar' + os.linesep)
self.assert_(iterator.next() == 'fred' + os.linesep)
self.assert_(iterator.next() == 'bob')
self.assertRaises(StopIteration, lambda: iterator.next())
def _test_seek_and_tell(self, proxy):
# Seek and use tell to check position
proxy.seek(3)
self.assert_(proxy.tell() == 3)
self.assert_(proxy.read(len(os.linesep)) == os.linesep)
proxy.seek(2, 1)
self.assert_(proxy.read(1 + len(os.linesep)) == 'r' + os.linesep)
proxy.seek(-3 - len(os.linesep), 2)
self.assert_(proxy.read(3) == 'bar')
proxy.seek(2, 0)
self.assert_(proxy.read() == 'o' + os.linesep + 'bar' + os.linesep)
proxy.seek(100)
self.assert_(proxy.read() == '')
def _test_close(self, proxy):
# Close a file
proxy.close()
self.assertRaises(AttributeError, lambda: proxy.close())
class TestProxyFile(TestProxyFileBase):
def setUp(self):
self._path = test_support.TESTFN
self._file = open(self._path, 'wb+')
def tearDown(self):
self._file.close()
self._delete_recursively(self._path)
def test_initialize(self):
# Initialize and check position
self._file.write('foo')
pos = self._file.tell()
proxy0 = mailbox._ProxyFile(self._file)
self.assert_(proxy0.tell() == pos)
self.assert_(self._file.tell() == pos)
proxy1 = mailbox._ProxyFile(self._file, 0)
self.assert_(proxy1.tell() == 0)
self.assert_(self._file.tell() == pos)
def test_read(self):
self._file.write('bar')
self._test_read(mailbox._ProxyFile(self._file))
def test_readline(self):
self._file.write('foo%sbar%sfred%sbob' % (os.linesep, os.linesep,
os.linesep))
self._test_readline(mailbox._ProxyFile(self._file))
def test_readlines(self):
self._file.write('foo%sbar%sfred%sbob' % (os.linesep, os.linesep,
os.linesep))
self._test_readlines(mailbox._ProxyFile(self._file))
def test_iteration(self):
self._file.write('foo%sbar%sfred%sbob' % (os.linesep, os.linesep,
os.linesep))
self._test_iteration(mailbox._ProxyFile(self._file))
def test_seek_and_tell(self):
self._file.write('foo%sbar%s' % (os.linesep, os.linesep))
self._test_seek_and_tell(mailbox._ProxyFile(self._file))
def test_close(self):
self._file.write('foo%sbar%s' % (os.linesep, os.linesep))
self._test_close(mailbox._ProxyFile(self._file))
class TestPartialFile(TestProxyFileBase):
def setUp(self):
self._path = test_support.TESTFN
self._file = open(self._path, 'wb+')
def tearDown(self):
self._file.close()
self._delete_recursively(self._path)
def test_initialize(self):
# Initialize and check position
self._file.write('foo' + os.linesep + 'bar')
pos = self._file.tell()
proxy = mailbox._PartialFile(self._file, 2, 5)
self.assert_(proxy.tell() == 0)
self.assert_(self._file.tell() == pos)
def test_read(self):
self._file.write('***bar***')
self._test_read(mailbox._PartialFile(self._file, 3, 6))
def test_readline(self):
self._file.write('!!!!!foo%sbar%sfred%sbob!!!!!' %
(os.linesep, os.linesep, os.linesep))
self._test_readline(mailbox._PartialFile(self._file, 5,
18 + 3 * len(os.linesep)))
def test_readlines(self):
self._file.write('foo%sbar%sfred%sbob?????' %
(os.linesep, os.linesep, os.linesep))
self._test_readlines(mailbox._PartialFile(self._file, 0,
13 + 3 * len(os.linesep)))
def test_iteration(self):
self._file.write('____foo%sbar%sfred%sbob####' %
(os.linesep, os.linesep, os.linesep))
self._test_iteration(mailbox._PartialFile(self._file, 4,
17 + 3 * len(os.linesep)))
def test_seek_and_tell(self):
self._file.write('(((foo%sbar%s$$$' % (os.linesep, os.linesep))
self._test_seek_and_tell(mailbox._PartialFile(self._file, 3,
9 + 2 * len(os.linesep)))
def test_close(self):
self._file.write('&foo%sbar%s^' % (os.linesep, os.linesep))
self._test_close(mailbox._PartialFile(self._file, 1,
6 + 3 * len(os.linesep)))
## Start: tests from the original module (for backward compatibility).
FROM_ = "From some.body@dummy.domain Sat Jul 24 13:43:35 2004\n"
DUMMY_MESSAGE = """\
From: some.body@dummy.domain
To: me@my.domain
Subject: Simple Test
This is a dummy message.
"""
class MaildirTestCase(unittest.TestCase):
def setUp(self):
# create a new maildir mailbox to work with:
self._dir = test_support.TESTFN
os.mkdir(self._dir)
os.mkdir(os.path.join(self._dir, "cur"))
os.mkdir(os.path.join(self._dir, "tmp"))
os.mkdir(os.path.join(self._dir, "new"))
self._counter = 1
self._msgfiles = []
def tearDown(self):
map(os.unlink, self._msgfiles)
os.rmdir(os.path.join(self._dir, "cur"))
os.rmdir(os.path.join(self._dir, "tmp"))
os.rmdir(os.path.join(self._dir, "new"))
os.rmdir(self._dir)
def createMessage(self, dir, mbox=False):
t = int(time.time() % 1000000)
pid = self._counter
self._counter += 1
filename = os.extsep.join((str(t), str(pid), "myhostname", "mydomain"))
tmpname = os.path.join(self._dir, "tmp", filename)
newname = os.path.join(self._dir, dir, filename)
fp = open(tmpname, "w")
self._msgfiles.append(tmpname)
if mbox:
fp.write(FROM_)
fp.write(DUMMY_MESSAGE)
fp.close()
if hasattr(os, "link"):
os.link(tmpname, newname)
else:
fp = open(newname, "w")
fp.write(DUMMY_MESSAGE)
fp.close()
self._msgfiles.append(newname)
return tmpname
def test_empty_maildir(self):
"""Test an empty maildir mailbox"""
# Test for regression on bug #117490:
# Make sure the boxes attribute actually gets set.
self.mbox = mailbox.Maildir(test_support.TESTFN)
#self.assert_(hasattr(self.mbox, "boxes"))
#self.assert_(len(self.mbox.boxes) == 0)
self.assert_(self.mbox.next() is None)
self.assert_(self.mbox.next() is None)
def test_nonempty_maildir_cur(self):
self.createMessage("cur")
self.mbox = mailbox.Maildir(test_support.TESTFN)
#self.assert_(len(self.mbox.boxes) == 1)
self.assert_(self.mbox.next() is not None)
self.assert_(self.mbox.next() is None)
self.assert_(self.mbox.next() is None)
def test_nonempty_maildir_new(self):
self.createMessage("new")
self.mbox = mailbox.Maildir(test_support.TESTFN)
#self.assert_(len(self.mbox.boxes) == 1)
self.assert_(self.mbox.next() is not None)
self.assert_(self.mbox.next() is None)
self.assert_(self.mbox.next() is None)
def test_nonempty_maildir_both(self):
self.createMessage("cur")
self.createMessage("new")
self.mbox = mailbox.Maildir(test_support.TESTFN)
#self.assert_(len(self.mbox.boxes) == 2)
self.assert_(self.mbox.next() is not None)
self.assert_(self.mbox.next() is not None)
self.assert_(self.mbox.next() is None)
self.assert_(self.mbox.next() is None)
def test_unix_mbox(self):
### should be better!
import email.parser
fname = self.createMessage("cur", True)
n = 0
for msg in mailbox.PortableUnixMailbox(open(fname),
email.parser.Parser().parse):
n += 1
self.assertEqual(msg["subject"], "Simple Test")
self.assertEqual(len(str(msg)), len(FROM_)+len(DUMMY_MESSAGE))
self.assertEqual(n, 1)
## End: classes from the original module (for backward compatibility).
_sample_message = """\
Return-Path: <gkj@gregorykjohnson.com>
X-Original-To: gkj+person@localhost
Delivered-To: gkj+person@localhost
Received: from localhost (localhost [127.0.0.1])
by andy.gregorykjohnson.com (Postfix) with ESMTP id 356ED9DD17
for <gkj+person@localhost>; Wed, 13 Jul 2005 17:23:16 -0400 (EDT)
Delivered-To: gkj@sundance.gregorykjohnson.com
Received: from localhost [127.0.0.1]
by localhost with POP3 (fetchmail-6.2.5)
for gkj+person@localhost (single-drop); Wed, 13 Jul 2005 17:23:16 -0400 (EDT)
Received: from andy.gregorykjohnson.com (andy.gregorykjohnson.com [64.32.235.228])
by sundance.gregorykjohnson.com (Postfix) with ESMTP id 5B056316746
for <gkj@gregorykjohnson.com>; Wed, 13 Jul 2005 17:23:11 -0400 (EDT)
Received: by andy.gregorykjohnson.com (Postfix, from userid 1000)
id 490CD9DD17; Wed, 13 Jul 2005 17:23:11 -0400 (EDT)
Date: Wed, 13 Jul 2005 17:23:11 -0400
From: "Gregory K. Johnson" <gkj@gregorykjohnson.com>
To: gkj@gregorykjohnson.com
Subject: Sample message
Message-ID: <20050713212311.GC4701@andy.gregorykjohnson.com>
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="NMuMz9nt05w80d4+"
Content-Disposition: inline
User-Agent: Mutt/1.5.9i
--NMuMz9nt05w80d4+
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
This is a sample message.
--
Gregory K. Johnson
--NMuMz9nt05w80d4+
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="text.gz"
Content-Transfer-Encoding: base64
H4sICM2D1UIAA3RleHQAC8nILFYAokSFktSKEoW0zJxUPa7wzJIMhZLyfIWczLzUYj0uAHTs
3FYlAAAA
--NMuMz9nt05w80d4+--
"""
_sample_headers = {
"Return-Path":"<gkj@gregorykjohnson.com>",
"X-Original-To":"gkj+person@localhost",
"Delivered-To":"gkj+person@localhost",
"Received":"""from localhost (localhost [127.0.0.1])
by andy.gregorykjohnson.com (Postfix) with ESMTP id 356ED9DD17
for <gkj+person@localhost>; Wed, 13 Jul 2005 17:23:16 -0400 (EDT)""",
"Delivered-To":"gkj@sundance.gregorykjohnson.com",
"Received":"""from localhost [127.0.0.1]
by localhost with POP3 (fetchmail-6.2.5)
for gkj+person@localhost (single-drop); Wed, 13 Jul 2005 17:23:16 -0400 (EDT)""",
"Received":"""from andy.gregorykjohnson.com (andy.gregorykjohnson.com [64.32.235.228])
by sundance.gregorykjohnson.com (Postfix) with ESMTP id 5B056316746
for <gkj@gregorykjohnson.com>; Wed, 13 Jul 2005 17:23:11 -0400 (EDT)""",
"Received":"""by andy.gregorykjohnson.com (Postfix, from userid 1000)
id 490CD9DD17; Wed, 13 Jul 2005 17:23:11 -0400 (EDT)""",
"Date":"Wed, 13 Jul 2005 17:23:11 -0400",
"From":""""Gregory K. Johnson" <gkj@gregorykjohnson.com>""",
"To":"gkj@gregorykjohnson.com",
"Subject":"Sample message",
"Mime-Version":"1.0",
"Content-Type":"""multipart/mixed; boundary="NMuMz9nt05w80d4+\"""",
"Content-Disposition":"inline",
"User-Agent": "Mutt/1.5.9i" }
_sample_payloads = ("""This is a sample message.
--
Gregory K. Johnson
""",
"""H4sICM2D1UIAA3RleHQAC8nILFYAokSFktSKEoW0zJxUPa7wzJIMhZLyfIWczLzUYj0uAHTs
3FYlAAAA
""")
def test_main():
tests = (TestMailboxSuperclass, TestMaildir, TestMbox, TestMMDF, TestMH,
TestBabyl, TestMessage, TestMaildirMessage, TestMboxMessage,
TestMHMessage, TestBabylMessage, TestMMDFMessage,
TestMessageConversion, TestProxyFile, TestPartialFile,
MaildirTestCase)
test_support.run_unittest(*tests)
test_support.reap_children()
if __name__ == '__main__':
test_main()