blob: a4cd09c70615ff7bde511adef8df51c9dad6f09f [file] [log] [blame]
Nick Coghlan029ba2b2011-08-22 16:05:44 +10001import mailcap
2import os
3import shutil
4import test.support
5import unittest
6
7# Location of mailcap file
8MAILCAPFILE = 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
Ezio Melotti83feff52011-08-23 01:39:22 +030012MAILCAPDICT = {
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 'application/*':
19 [{'copiousoutput': '',
20 'view': 'echo "This is \\"%t\\" but is 50 \\% Greek to me" \\; cat %s'}],
21 'audio/basic':
22 [{'edit': 'audiocompose %s',
23 'compose': 'audiocompose %s',
24 'description': '"An audio fragment"',
25 'view': 'showaudio %s'}],
26 'video/mpeg':
27 [{'view': 'mpeg_play %s'}],
28 'application/postscript':
29 [{'needsterminal': '', 'view': 'ps-to-terminal %s'},
30 {'compose': 'idraw %s', 'view': 'ps-to-terminal %s'}],
31 'application/x-dvi':
32 [{'view': 'xdvi %s'}],
33 'message/external-body':
34 [{'composetyped': 'extcompose %s',
35 'description': '"A reference to data stored in an external location"',
36 'needsterminal': '',
37 'view': 'showexternal %s %{access-type} %{name} %{site} %{directory} %{mode} %{server}'}],
38 'text/richtext':
39 [{'test': 'test "`echo %{charset} | tr \'[A-Z]\' \'[a-z]\'`" = iso-8859-8',
40 'copiousoutput': '',
41 'view': 'shownonascii iso-8859-8 -e richtext -p %s'}],
42 'image/x-xwindowdump':
43 [{'view': 'display %s'}],
44 'audio/*':
45 [{'view': '/usr/local/bin/showaudio %t'}],
46 'video/*':
47 [{'view': 'animate %s'}],
48 'application/frame':
49 [{'print': '"cat %s | lp"', 'view': 'showframe %s'}],
50 'image/rgb':
51 [{'view': 'display %s'}]
52}
Nick Coghlan029ba2b2011-08-22 16:05:44 +100053
54
55class HelperFunctionTest(unittest.TestCase):
56
57 def test_listmailcapfiles(self):
58 # The return value for listmailcapfiles() will vary by system.
59 # So verify that listmailcapfiles() returns a list of strings that is of
60 # non-zero length.
61 mcfiles = mailcap.listmailcapfiles()
Ezio Melotti83feff52011-08-23 01:39:22 +030062 self.assertIsInstance(mcfiles, list)
63 for m in mcfiles:
64 self.assertIsInstance(m, str)
Nick Coghlan029ba2b2011-08-22 16:05:44 +100065 with test.support.EnvironmentVarGuard() as env:
66 # According to RFC 1524, if MAILCAPS env variable exists, use that
67 # and only that.
68 if "MAILCAPS" in env:
69 env_mailcaps = env["MAILCAPS"].split(os.pathsep)
70 else:
71 env_mailcaps = ["/testdir1/.mailcap", "/testdir2/mailcap"]
72 env["MAILCAPS"] = os.pathsep.join(env_mailcaps)
73 mcfiles = mailcap.listmailcapfiles()
74 self.assertEqual(env_mailcaps, mcfiles)
75
76 def test_readmailcapfile(self):
77 # Test readmailcapfile() using test file. It should match MAILCAPDICT.
78 with open(MAILCAPFILE, 'r') as mcf:
79 d = mailcap.readmailcapfile(mcf)
80 self.assertDictEqual(d, MAILCAPDICT)
81
82 def test_lookup(self):
83 # Test without key
84 expected = [{'view': 'mpeg_play %s'}, {'view': 'animate %s'}]
85 actual = mailcap.lookup(MAILCAPDICT, 'video/mpeg')
86 self.assertListEqual(expected, actual)
87
88 # Test with key
89 key = 'compose'
90 expected = [{'edit': 'audiocompose %s',
91 'compose': 'audiocompose %s',
92 'description': '"An audio fragment"',
93 'view': 'showaudio %s'}]
94 actual = mailcap.lookup(MAILCAPDICT, 'audio/basic', key)
95 self.assertListEqual(expected, actual)
96
97 def test_subst(self):
98 plist = ['id=1', 'number=2', 'total=3']
99 # test case: ([field, MIMEtype, filename, plist=[]], <expected string>)
100 test_cases = [
Ezio Melotti83feff52011-08-23 01:39:22 +0300101 (["", "audio/*", "foo.txt"], ""),
102 (["echo foo", "audio/*", "foo.txt"], "echo foo"),
103 (["echo %s", "audio/*", "foo.txt"], "echo foo.txt"),
104 (["echo %t", "audio/*", "foo.txt"], "echo audio/*"),
105 (["echo \%t", "audio/*", "foo.txt"], "echo %t"),
106 (["echo foo", "audio/*", "foo.txt", plist], "echo foo"),
107 (["echo %{total}", "audio/*", "foo.txt", plist], "echo 3")
108 ]
Nick Coghlan029ba2b2011-08-22 16:05:44 +1000109 for tc in test_cases:
110 self.assertEqual(mailcap.subst(*tc[0]), tc[1])
111
112
113class GetcapsTest(unittest.TestCase):
114
115 def test_mock_getcaps(self):
116 # Test mailcap.getcaps() using mock mailcap file in this dir.
117 # Temporarily override any existing system mailcap file by pointing the
118 # MAILCAPS environment variable to our mock file.
119 with test.support.EnvironmentVarGuard() as env:
120 env["MAILCAPS"] = MAILCAPFILE
121 caps = mailcap.getcaps()
122 self.assertDictEqual(caps, MAILCAPDICT)
123
124 def test_system_mailcap(self):
125 # Test mailcap.getcaps() with mailcap file(s) on system, if any.
126 caps = mailcap.getcaps()
Ezio Melotti83feff52011-08-23 01:39:22 +0300127 self.assertIsInstance(caps, dict)
Nick Coghlan029ba2b2011-08-22 16:05:44 +1000128 mailcapfiles = mailcap.listmailcapfiles()
129 existingmcfiles = [mcf for mcf in mailcapfiles if os.path.exists(mcf)]
130 if existingmcfiles:
131 # At least 1 mailcap file exists, so test that.
132 for (k, v) in caps.items():
Ezio Melotti83feff52011-08-23 01:39:22 +0300133 self.assertIsInstance(k, str)
134 self.assertIsInstance(v, list)
135 for e in v:
136 self.assertIsInstance(e, dict)
Nick Coghlan029ba2b2011-08-22 16:05:44 +1000137 else:
138 # No mailcap files on system. getcaps() should return empty dict.
139 self.assertEqual({}, caps)
140
141
142class FindmatchTest(unittest.TestCase):
143
144 def test_findmatch(self):
145
146 # default findmatch arguments
147 c = MAILCAPDICT
148 fname = "foo.txt"
149 plist = ["access-type=default", "name=john", "site=python.org",
150 "directory=/tmp", "mode=foo", "server=bar"]
Ezio Melotti83feff52011-08-23 01:39:22 +0300151 audio_basic_entry = {
152 'edit': 'audiocompose %s',
153 'compose': 'audiocompose %s',
154 'description': '"An audio fragment"',
155 'view': 'showaudio %s'
156 }
Nick Coghlan029ba2b2011-08-22 16:05:44 +1000157 audio_entry = {"view": "/usr/local/bin/showaudio %t"}
158 video_entry = {'view': 'animate %s'}
Ezio Melotti83feff52011-08-23 01:39:22 +0300159 message_entry = {
160 'composetyped': 'extcompose %s',
161 'description': '"A reference to data stored in an external location"', 'needsterminal': '',
162 'view': 'showexternal %s %{access-type} %{name} %{site} %{directory} %{mode} %{server}'
163 }
Nick Coghlan029ba2b2011-08-22 16:05:44 +1000164
165 # test case: (findmatch args, findmatch keyword args, expected output)
166 # positional args: caps, MIMEtype
167 # keyword args: key="view", filename="/dev/null", plist=[]
168 # output: (command line, mailcap entry)
169 cases = [
170 ([{}, "video/mpeg"], {}, (None, None)),
171 ([c, "foo/bar"], {}, (None, None)),
172 ([c, "video/mpeg"], {}, ('mpeg_play /dev/null', {'view': 'mpeg_play %s'})),
173 ([c, "audio/basic", "edit"], {}, ("audiocompose /dev/null", audio_basic_entry)),
174 ([c, "audio/basic", "compose"], {}, ("audiocompose /dev/null", audio_basic_entry)),
175 ([c, "audio/basic", "description"], {}, ('"An audio fragment"', audio_basic_entry)),
176 ([c, "audio/basic", "foobar"], {}, (None, None)),
177 ([c, "video/*"], {"filename": fname}, ("animate %s" % fname, video_entry)),
178 ([c, "audio/basic", "compose"],
179 {"filename": fname},
180 ("audiocompose %s" % fname, audio_basic_entry)),
181 ([c, "audio/basic"],
182 {"key": "description", "filename": fname},
183 ('"An audio fragment"', audio_basic_entry)),
184 ([c, "audio/*"],
185 {"filename": fname},
186 ("/usr/local/bin/showaudio audio/*", audio_entry)),
187 ([c, "message/external-body"],
188 {"plist": plist},
189 ("showexternal /dev/null default john python.org /tmp foo bar", message_entry))
Ezio Melotti83feff52011-08-23 01:39:22 +0300190 ]
Nick Coghlan029ba2b2011-08-22 16:05:44 +1000191 self._run_cases(cases)
192
193 @unittest.skipUnless(os.name == "posix", "Requires 'test' command on system")
194 def test_test(self):
195 # findmatch() will automatically check any "test" conditions and skip
196 # the entry if the check fails.
197 caps = {"test/pass": [{"test": "test 1 -eq 1"}],
198 "test/fail": [{"test": "test 1 -eq 0"}]}
199 # test case: (findmatch args, findmatch keyword args, expected output)
200 # positional args: caps, MIMEtype, key ("test")
201 # keyword args: N/A
202 # output: (command line, mailcap entry)
203 cases = [
204 # findmatch will return the mailcap entry for test/pass because it evaluates to true
205 ([caps, "test/pass", "test"], {}, ("test 1 -eq 1", {"test": "test 1 -eq 1"})),
206 # findmatch will return None because test/fail evaluates to false
207 ([caps, "test/fail", "test"], {}, (None, None))
Ezio Melotti83feff52011-08-23 01:39:22 +0300208 ]
Nick Coghlan029ba2b2011-08-22 16:05:44 +1000209 self._run_cases(cases)
210
211 def _run_cases(self, cases):
212 for c in cases:
213 self.assertEqual(mailcap.findmatch(*c[0], **c[1]), c[2])
214
215
216def test_main():
217 test.support.run_unittest(HelperFunctionTest, GetcapsTest, FindmatchTest)
218
219
220if __name__ == '__main__':
221 test_main()