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