Home | History | Annotate | Download | only in test
      1 import mailcap
      2 import os
      3 import copy
      4 import test.support
      5 import unittest
      6 
      7 # Location of mailcap file
      8 MAILCAPFILE = test.support.findfile("mailcap.txt")
      9 
     10 # Dict to act as mock mailcap entry for this test
     11 # The keys and values should match the contents of MAILCAPFILE
     12 MAILCAPDICT = {
     13     'application/x-movie':
     14         [{'compose': 'moviemaker %s',
     15           'x11-bitmap': '"/usr/lib/Zmail/bitmaps/movie.xbm"',
     16           'description': '"Movie"',
     17           'view': 'movieplayer %s',
     18           'lineno': 4}],
     19     'application/*':
     20         [{'copiousoutput': '',
     21           'view': 'echo "This is \\"%t\\" but        is 50 \\% Greek to me" \\; cat %s',
     22           'lineno': 5}],
     23     'audio/basic':
     24         [{'edit': 'audiocompose %s',
     25           'compose': 'audiocompose %s',
     26           'description': '"An audio fragment"',
     27           'view': 'showaudio %s',
     28           'lineno': 6}],
     29     'video/mpeg':
     30         [{'view': 'mpeg_play %s', 'lineno': 13}],
     31     'application/postscript':
     32         [{'needsterminal': '', 'view': 'ps-to-terminal %s', 'lineno': 1},
     33          {'compose': 'idraw %s', 'view': 'ps-to-terminal %s', 'lineno': 2}],
     34     'application/x-dvi':
     35         [{'view': 'xdvi %s', 'lineno': 3}],
     36     'message/external-body':
     37         [{'composetyped': 'extcompose %s',
     38           'description': '"A reference to data stored in an external location"',
     39           'needsterminal': '',
     40           'view': 'showexternal %s %{access-type} %{name} %{site}     %{directory} %{mode} %{server}',
     41           'lineno': 10}],
     42     'text/richtext':
     43         [{'test': 'test "`echo     %{charset} | tr \'[A-Z]\' \'[a-z]\'`"  = iso-8859-8',
     44           'copiousoutput': '',
     45           'view': 'shownonascii iso-8859-8 -e richtext -p %s',
     46           'lineno': 11}],
     47     'image/x-xwindowdump':
     48         [{'view': 'display %s', 'lineno': 9}],
     49     'audio/*':
     50         [{'view': '/usr/local/bin/showaudio %t', 'lineno': 7}],
     51     'video/*':
     52         [{'view': 'animate %s', 'lineno': 12}],
     53     'application/frame':
     54         [{'print': '"cat %s | lp"', 'view': 'showframe %s', 'lineno': 0}],
     55     'image/rgb':
     56         [{'view': 'display %s', 'lineno': 8}]
     57 }
     58 
     59 # For backwards compatibility, readmailcapfile() and lookup() still support
     60 # the old version of mailcapdict without line numbers.
     61 MAILCAPDICT_DEPRECATED = copy.deepcopy(MAILCAPDICT)
     62 for entry_list in MAILCAPDICT_DEPRECATED.values():
     63     for entry in entry_list:
     64         entry.pop('lineno')
     65 
     66 
     67 class HelperFunctionTest(unittest.TestCase):
     68 
     69     def test_listmailcapfiles(self):
     70         # The return value for listmailcapfiles() will vary by system.
     71         # So verify that listmailcapfiles() returns a list of strings that is of
     72         # non-zero length.
     73         mcfiles = mailcap.listmailcapfiles()
     74         self.assertIsInstance(mcfiles, list)
     75         for m in mcfiles:
     76             self.assertIsInstance(m, str)
     77         with test.support.EnvironmentVarGuard() as env:
     78             # According to RFC 1524, if MAILCAPS env variable exists, use that
     79             # and only that.
     80             if "MAILCAPS" in env:
     81                 env_mailcaps = env["MAILCAPS"].split(os.pathsep)
     82             else:
     83                 env_mailcaps = ["/testdir1/.mailcap", "/testdir2/mailcap"]
     84                 env["MAILCAPS"] = os.pathsep.join(env_mailcaps)
     85                 mcfiles = mailcap.listmailcapfiles()
     86         self.assertEqual(env_mailcaps, mcfiles)
     87 
     88     def test_readmailcapfile(self):
     89         # Test readmailcapfile() using test file. It should match MAILCAPDICT.
     90         with open(MAILCAPFILE, 'r') as mcf:
     91             with self.assertWarns(DeprecationWarning):
     92                 d = mailcap.readmailcapfile(mcf)
     93         self.assertDictEqual(d, MAILCAPDICT_DEPRECATED)
     94 
     95     def test_lookup(self):
     96         # Test without key
     97         expected = [{'view': 'animate %s', 'lineno': 12},
     98                     {'view': 'mpeg_play %s', 'lineno': 13}]
     99         actual = mailcap.lookup(MAILCAPDICT, 'video/mpeg')
    100         self.assertListEqual(expected, actual)
    101 
    102         # Test with key
    103         key = 'compose'
    104         expected = [{'edit': 'audiocompose %s',
    105                      'compose': 'audiocompose %s',
    106                      'description': '"An audio fragment"',
    107                      'view': 'showaudio %s',
    108                      'lineno': 6}]
    109         actual = mailcap.lookup(MAILCAPDICT, 'audio/basic', key)
    110         self.assertListEqual(expected, actual)
    111 
    112         # Test on user-defined dicts without line numbers
    113         expected = [{'view': 'mpeg_play %s'}, {'view': 'animate %s'}]
    114         actual = mailcap.lookup(MAILCAPDICT_DEPRECATED, 'video/mpeg')
    115         self.assertListEqual(expected, actual)
    116 
    117     def test_subst(self):
    118         plist = ['id=1', 'number=2', 'total=3']
    119         # test case: ([field, MIMEtype, filename, plist=[]], <expected string>)
    120         test_cases = [
    121             (["", "audio/*", "foo.txt"], ""),
    122             (["echo foo", "audio/*", "foo.txt"], "echo foo"),
    123             (["echo %s", "audio/*", "foo.txt"], "echo foo.txt"),
    124             (["echo %t", "audio/*", "foo.txt"], "echo audio/*"),
    125             (["echo \\%t", "audio/*", "foo.txt"], "echo %t"),
    126             (["echo foo", "audio/*", "foo.txt", plist], "echo foo"),
    127             (["echo %{total}", "audio/*", "foo.txt", plist], "echo 3")
    128         ]
    129         for tc in test_cases:
    130             self.assertEqual(mailcap.subst(*tc[0]), tc[1])
    131 
    132 
    133 class GetcapsTest(unittest.TestCase):
    134 
    135     def test_mock_getcaps(self):
    136         # Test mailcap.getcaps() using mock mailcap file in this dir.
    137         # Temporarily override any existing system mailcap file by pointing the
    138         # MAILCAPS environment variable to our mock file.
    139         with test.support.EnvironmentVarGuard() as env:
    140             env["MAILCAPS"] = MAILCAPFILE
    141             caps = mailcap.getcaps()
    142             self.assertDictEqual(caps, MAILCAPDICT)
    143 
    144     def test_system_mailcap(self):
    145         # Test mailcap.getcaps() with mailcap file(s) on system, if any.
    146         caps = mailcap.getcaps()
    147         self.assertIsInstance(caps, dict)
    148         mailcapfiles = mailcap.listmailcapfiles()
    149         existingmcfiles = [mcf for mcf in mailcapfiles if os.path.exists(mcf)]
    150         if existingmcfiles:
    151             # At least 1 mailcap file exists, so test that.
    152             for (k, v) in caps.items():
    153                 self.assertIsInstance(k, str)
    154                 self.assertIsInstance(v, list)
    155                 for e in v:
    156                     self.assertIsInstance(e, dict)
    157         else:
    158             # No mailcap files on system. getcaps() should return empty dict.
    159             self.assertEqual({}, caps)
    160 
    161 
    162 class FindmatchTest(unittest.TestCase):
    163 
    164     def test_findmatch(self):
    165 
    166         # default findmatch arguments
    167         c = MAILCAPDICT
    168         fname = "foo.txt"
    169         plist = ["access-type=default", "name=john", "site=python.org",
    170                  "directory=/tmp", "mode=foo", "server=bar"]
    171         audio_basic_entry = {
    172             'edit': 'audiocompose %s',
    173             'compose': 'audiocompose %s',
    174             'description': '"An audio fragment"',
    175             'view': 'showaudio %s',
    176             'lineno': 6
    177         }
    178         audio_entry = {"view": "/usr/local/bin/showaudio %t", 'lineno': 7}
    179         video_entry = {'view': 'animate %s', 'lineno': 12}
    180         message_entry = {
    181             'composetyped': 'extcompose %s',
    182             'description': '"A reference to data stored in an external location"', 'needsterminal': '',
    183             'view': 'showexternal %s %{access-type} %{name} %{site}     %{directory} %{mode} %{server}',
    184             'lineno': 10,
    185         }
    186 
    187         # test case: (findmatch args, findmatch keyword args, expected output)
    188         #   positional args: caps, MIMEtype
    189         #   keyword args: key="view", filename="/dev/null", plist=[]
    190         #   output: (command line, mailcap entry)
    191         cases = [
    192             ([{}, "video/mpeg"], {}, (None, None)),
    193             ([c, "foo/bar"], {}, (None, None)),
    194             ([c, "video/mpeg"], {}, ('animate /dev/null', video_entry)),
    195             ([c, "audio/basic", "edit"], {}, ("audiocompose /dev/null", audio_basic_entry)),
    196             ([c, "audio/basic", "compose"], {}, ("audiocompose /dev/null", audio_basic_entry)),
    197             ([c, "audio/basic", "description"], {}, ('"An audio fragment"', audio_basic_entry)),
    198             ([c, "audio/basic", "foobar"], {}, (None, None)),
    199             ([c, "video/*"], {"filename": fname}, ("animate %s" % fname, video_entry)),
    200             ([c, "audio/basic", "compose"],
    201              {"filename": fname},
    202              ("audiocompose %s" % fname, audio_basic_entry)),
    203             ([c, "audio/basic"],
    204              {"key": "description", "filename": fname},
    205              ('"An audio fragment"', audio_basic_entry)),
    206             ([c, "audio/*"],
    207              {"filename": fname},
    208              ("/usr/local/bin/showaudio audio/*", audio_entry)),
    209             ([c, "message/external-body"],
    210              {"plist": plist},
    211              ("showexternal /dev/null default john python.org     /tmp foo bar", message_entry))
    212         ]
    213         self._run_cases(cases)
    214 
    215     @unittest.skipUnless(os.name == "posix", "Requires 'test' command on system")
    216     def test_test(self):
    217         # findmatch() will automatically check any "test" conditions and skip
    218         # the entry if the check fails.
    219         caps = {"test/pass": [{"test": "test 1 -eq 1"}],
    220                 "test/fail": [{"test": "test 1 -eq 0"}]}
    221         # test case: (findmatch args, findmatch keyword args, expected output)
    222         #   positional args: caps, MIMEtype, key ("test")
    223         #   keyword args: N/A
    224         #   output: (command line, mailcap entry)
    225         cases = [
    226             # findmatch will return the mailcap entry for test/pass because it evaluates to true
    227             ([caps, "test/pass", "test"], {}, ("test 1 -eq 1", {"test": "test 1 -eq 1"})),
    228             # findmatch will return None because test/fail evaluates to false
    229             ([caps, "test/fail", "test"], {}, (None, None))
    230         ]
    231         self._run_cases(cases)
    232 
    233     def _run_cases(self, cases):
    234         for c in cases:
    235             self.assertEqual(mailcap.findmatch(*c[0], **c[1]), c[2])
    236 
    237 
    238 if __name__ == '__main__':
    239     unittest.main()
    240