Skip to content

Commit b23646a

Browse files
gh-93417: Improve test_mimetypes (GH-150725)
* Separate tests for module-level API and for the MimeTypes class. * Add tests for mimetypes.init() and MimeTypes() with knownfiles and with explicitly passed files.
1 parent 9ba2a89 commit b23646a

2 files changed

Lines changed: 206 additions & 156 deletions

File tree

Lib/test/mime.types2

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# MIME type Extensions
2+
testing/test2 test test2
3+
testing/test3 test test3

Lib/test/test_mimetypes.py

Lines changed: 203 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -31,50 +31,11 @@ def tearDownModule():
3131
mimetypes.knownfiles = knownfiles
3232

3333

34-
class MimeTypesTestCase(unittest.TestCase):
34+
class MimeTypesModuleTestCase(unittest.TestCase):
3535
def setUp(self):
36-
self.db = mimetypes.MimeTypes()
37-
38-
def test_case_sensitivity(self):
39-
eq = self.assertEqual
40-
eq(self.db.guess_file_type("foobar.html"), ("text/html", None))
41-
eq(self.db.guess_type("scheme:foobar.html"), ("text/html", None))
42-
eq(self.db.guess_file_type("foobar.HTML"), ("text/html", None))
43-
eq(self.db.guess_type("scheme:foobar.HTML"), ("text/html", None))
44-
eq(self.db.guess_file_type("foobar.tgz"), ("application/x-tar", "gzip"))
45-
eq(self.db.guess_type("scheme:foobar.tgz"), ("application/x-tar", "gzip"))
46-
eq(self.db.guess_file_type("foobar.TGZ"), ("application/x-tar", "gzip"))
47-
eq(self.db.guess_type("scheme:foobar.TGZ"), ("application/x-tar", "gzip"))
48-
eq(self.db.guess_file_type("foobar.tar.Z"), ("application/x-tar", "compress"))
49-
eq(self.db.guess_type("scheme:foobar.tar.Z"), ("application/x-tar", "compress"))
50-
eq(self.db.guess_file_type("foobar.tar.z"), (None, None))
51-
eq(self.db.guess_type("scheme:foobar.tar.z"), (None, None))
52-
53-
def test_default_data(self):
54-
eq = self.assertEqual
55-
eq(self.db.guess_file_type("foo.html"), ("text/html", None))
56-
eq(self.db.guess_file_type("foo.HTML"), ("text/html", None))
57-
eq(self.db.guess_file_type("foo.tgz"), ("application/x-tar", "gzip"))
58-
eq(self.db.guess_file_type("foo.tar.gz"), ("application/x-tar", "gzip"))
59-
eq(self.db.guess_file_type("foo.tar.Z"), ("application/x-tar", "compress"))
60-
eq(self.db.guess_file_type("foo.tar.bz2"), ("application/x-tar", "bzip2"))
61-
eq(self.db.guess_file_type("foo.tar.xz"), ("application/x-tar", "xz"))
62-
63-
def test_data_urls(self):
64-
eq = self.assertEqual
65-
guess_type = self.db.guess_type
66-
eq(guess_type("data:invalidDataWithoutComma"), (None, None))
67-
eq(guess_type("data:,thisIsTextPlain"), ("text/plain", None))
68-
eq(guess_type("data:;base64,thisIsTextPlain"), ("text/plain", None))
69-
eq(guess_type("data:text/x-foo,thisIsTextXFoo"), ("text/x-foo", None))
70-
71-
def test_file_parsing(self):
72-
eq = self.assertEqual
73-
sio = io.StringIO("x-application/x-unittest pyunit\n")
74-
self.db.readfp(sio)
75-
eq(self.db.guess_file_type("foo.pyunit"),
76-
("x-application/x-unittest", None))
77-
eq(self.db.guess_extension("x-application/x-unittest"), ".pyunit")
36+
mimetypes.inited = False
37+
mimetypes._default_mime_types()
38+
mimetypes._db = None
7839

7940
def test_read_mime_types(self):
8041
eq = self.assertEqual
@@ -109,100 +70,6 @@ def test_read_mime_types(self):
10970
mock_open.assert_called_with(filename, encoding='utf-8')
11071
eq(mime_dict[".Français"], "application/no-mans-land")
11172

112-
def test_non_standard_types(self):
113-
eq = self.assertEqual
114-
# First try strict
115-
eq(self.db.guess_file_type('foo.xul', strict=True), (None, None))
116-
# And then non-strict
117-
eq(self.db.guess_file_type('foo.xul', strict=False), ('text/xul', None))
118-
eq(self.db.guess_file_type('foo.XUL', strict=False), ('text/xul', None))
119-
eq(self.db.guess_file_type('foo.invalid', strict=False), (None, None))
120-
eq(self.db.guess_extension('image/jpeg', strict=False), '.jpg')
121-
eq(self.db.guess_extension('image/JPEG', strict=False), '.jpg')
122-
123-
def test_filename_with_url_delimiters(self):
124-
# bpo-38449: URL delimiters cases should be handled also.
125-
# They would have different mime types if interpreted as URL as
126-
# compared to when interpreted as filename because of the semicolon.
127-
eq = self.assertEqual
128-
gzip_expected = ('application/x-tar', 'gzip')
129-
for name in (
130-
';1.tar.gz',
131-
'?1.tar.gz',
132-
'#1.tar.gz',
133-
'#1#.tar.gz',
134-
';1#.tar.gz',
135-
';&1=123;?.tar.gz',
136-
'?k1=v1&k2=v2.tar.gz',
137-
):
138-
for prefix in ('', '/', '\\',
139-
'c:', 'c:/', 'c:\\', 'c:/d/', 'c:\\d\\',
140-
'//share/server/', '\\\\share\\server\\'):
141-
path = prefix + name
142-
with self.subTest(path=path):
143-
eq(self.db.guess_file_type(path), gzip_expected)
144-
eq(self.db.guess_type(path), gzip_expected)
145-
expected = (None, None) if os.name == 'nt' else gzip_expected
146-
for prefix in ('//', '\\\\', '//share/', '\\\\share\\'):
147-
path = prefix + name
148-
with self.subTest(path=path):
149-
eq(self.db.guess_file_type(path), expected)
150-
eq(self.db.guess_type(path), expected)
151-
eq(self.db.guess_file_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected)
152-
eq(self.db.guess_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected)
153-
154-
eq(self.db.guess_file_type(r'foo/.tar.gz'), (None, 'gzip'))
155-
eq(self.db.guess_type(r'foo/.tar.gz'), (None, 'gzip'))
156-
expected = (None, 'gzip') if os.name == 'nt' else gzip_expected
157-
eq(self.db.guess_file_type(r'foo\.tar.gz'), expected)
158-
eq(self.db.guess_type(r'foo\.tar.gz'), expected)
159-
eq(self.db.guess_type(r'scheme:foo\.tar.gz'), gzip_expected)
160-
161-
def test_url(self):
162-
result = self.db.guess_type('http://example.com/host.html')
163-
result = self.db.guess_type('http://host.html')
164-
msg = 'URL only has a host name, not a file'
165-
self.assertSequenceEqual(result, (None, None), msg)
166-
result = self.db.guess_type('http://example.com/host.html')
167-
msg = 'Should be text/html'
168-
self.assertSequenceEqual(result, ('text/html', None), msg)
169-
result = self.db.guess_type('http://example.com/host.html#x.tar')
170-
self.assertSequenceEqual(result, ('text/html', None))
171-
result = self.db.guess_type('http://example.com/host.html?q=x.tar')
172-
self.assertSequenceEqual(result, ('text/html', None))
173-
174-
def test_guess_all_types(self):
175-
# First try strict. Use a set here for testing the results because if
176-
# test_urllib2 is run before test_mimetypes, global state is modified
177-
# such that the 'all' set will have more items in it.
178-
all = self.db.guess_all_extensions('text/plain', strict=True)
179-
self.assertTrue(set(all) >= {'.bat', '.c', '.h', '.ksh', '.pl', '.txt'})
180-
self.assertEqual(len(set(all)), len(all)) # no duplicates
181-
# And now non-strict
182-
all = self.db.guess_all_extensions('image/jpeg', strict=False)
183-
self.assertEqual(all, ['.jpg', '.jpe', '.jpeg'])
184-
# And now for no hits
185-
all = self.db.guess_all_extensions('image/jpg', strict=True)
186-
self.assertEqual(all, [])
187-
# And now for type existing in both strict and non-strict mappings.
188-
self.db.add_type('test-type', '.strict-ext')
189-
self.db.add_type('test-type', '.non-strict-ext', strict=False)
190-
all = self.db.guess_all_extensions('test-type', strict=False)
191-
self.assertEqual(all, ['.strict-ext', '.non-strict-ext'])
192-
all = self.db.guess_all_extensions('test-type')
193-
self.assertEqual(all, ['.strict-ext'])
194-
# Test that changing the result list does not affect the global state
195-
all.append('.no-such-ext')
196-
all = self.db.guess_all_extensions('test-type')
197-
self.assertNotIn('.no-such-ext', all)
198-
199-
def test_encoding(self):
200-
filename = support.findfile("mime.types")
201-
mimes = mimetypes.MimeTypes([filename])
202-
exts = mimes.guess_all_extensions('application/vnd.geocube+xml',
203-
strict=True)
204-
self.assertEqual(exts, ['.g3', '.g\xb3'])
205-
20673
def test_init_reinitializes(self):
20774
# Issue 4936: make sure an init starts clean
20875
# First, put some poison into the types table
@@ -341,6 +208,205 @@ def test_init_stability(self):
341208
self.assertEqual(types_map, mimetypes.types_map)
342209
self.assertEqual(common_types, mimetypes.common_types)
343210

211+
def test_init_files(self):
212+
guess_file_type = mimetypes.guess_file_type
213+
self.assertEqual(guess_file_type("file.test2")[0], None)
214+
215+
filename = support.findfile("mime.types2")
216+
mimetypes.init([filename])
217+
self.assertEqual(guess_file_type("file.test2")[0], "testing/test2")
218+
219+
mimetypes.init()
220+
self.assertEqual(guess_file_type("file.test2")[0], None)
221+
222+
def test_init_knownfiles(self):
223+
guess_file_type = mimetypes.guess_file_type
224+
self.assertEqual(guess_file_type("file.test2")[0], None)
225+
226+
filename = support.findfile("mime.types2")
227+
mimetypes.knownfiles = [filename, "non-existent"]
228+
self.addCleanup(mimetypes.knownfiles.clear)
229+
230+
mimetypes.init()
231+
self.assertEqual(guess_file_type("file.test2")[0], "testing/test2")
232+
233+
def test_added_types_are_used(self):
234+
mimetypes.add_type('testing/default-type', '')
235+
mime_type, _ = mimetypes.guess_type('')
236+
self.assertEqual(mime_type, 'testing/default-type')
237+
238+
mime_type, _ = mimetypes.guess_type('test.myext')
239+
self.assertEqual(mime_type, None)
240+
241+
mimetypes.add_type('testing/type', '.myext')
242+
mime_type, _ = mimetypes.guess_type('test.myext')
243+
self.assertEqual(mime_type, 'testing/type')
244+
245+
def test_add_type_with_undotted_extension_not_supported(self):
246+
msg = "Extension 'undotted' must start with '.'"
247+
with self.assertRaisesRegex(ValueError, msg):
248+
mimetypes.add_type("testing/type", "undotted")
249+
with self.assertRaisesRegex(ValueError, msg):
250+
mimetypes.add_type("", "undotted")
251+
252+
253+
class MimeTypesClassTestCase(unittest.TestCase):
254+
def setUp(self):
255+
self.db = mimetypes.MimeTypes()
256+
257+
def test_init_files(self):
258+
guess_file_type = self.db.guess_file_type
259+
self.assertEqual(guess_file_type("file.test2")[0], None)
260+
261+
filename = support.findfile("mime.types2")
262+
db = mimetypes.MimeTypes([filename])
263+
guess_file_type = db.guess_file_type
264+
self.assertEqual(guess_file_type("file.test2")[0], "testing/test2")
265+
266+
def test_init_knownfiles(self):
267+
filename = support.findfile("mime.types2")
268+
mimetypes.knownfiles = [filename, "non-existent"]
269+
self.addCleanup(mimetypes.knownfiles.clear)
270+
271+
db = mimetypes.MimeTypes()
272+
guess_file_type = db.guess_file_type
273+
self.assertEqual(guess_file_type("file.test2")[0], None)
274+
275+
def test_case_sensitivity(self):
276+
eq = self.assertEqual
277+
eq(self.db.guess_file_type("foobar.html"), ("text/html", None))
278+
eq(self.db.guess_type("scheme:foobar.html"), ("text/html", None))
279+
eq(self.db.guess_file_type("foobar.HTML"), ("text/html", None))
280+
eq(self.db.guess_type("scheme:foobar.HTML"), ("text/html", None))
281+
eq(self.db.guess_file_type("foobar.tgz"), ("application/x-tar", "gzip"))
282+
eq(self.db.guess_type("scheme:foobar.tgz"), ("application/x-tar", "gzip"))
283+
eq(self.db.guess_file_type("foobar.TGZ"), ("application/x-tar", "gzip"))
284+
eq(self.db.guess_type("scheme:foobar.TGZ"), ("application/x-tar", "gzip"))
285+
eq(self.db.guess_file_type("foobar.tar.Z"), ("application/x-tar", "compress"))
286+
eq(self.db.guess_type("scheme:foobar.tar.Z"), ("application/x-tar", "compress"))
287+
eq(self.db.guess_file_type("foobar.tar.z"), (None, None))
288+
eq(self.db.guess_type("scheme:foobar.tar.z"), (None, None))
289+
290+
def test_default_data(self):
291+
eq = self.assertEqual
292+
eq(self.db.guess_file_type("foo.html"), ("text/html", None))
293+
eq(self.db.guess_file_type("foo.HTML"), ("text/html", None))
294+
eq(self.db.guess_file_type("foo.tgz"), ("application/x-tar", "gzip"))
295+
eq(self.db.guess_file_type("foo.tar.gz"), ("application/x-tar", "gzip"))
296+
eq(self.db.guess_file_type("foo.tar.Z"), ("application/x-tar", "compress"))
297+
eq(self.db.guess_file_type("foo.tar.bz2"), ("application/x-tar", "bzip2"))
298+
eq(self.db.guess_file_type("foo.tar.xz"), ("application/x-tar", "xz"))
299+
300+
def test_data_urls(self):
301+
eq = self.assertEqual
302+
guess_type = self.db.guess_type
303+
eq(guess_type("data:invalidDataWithoutComma"), (None, None))
304+
eq(guess_type("data:,thisIsTextPlain"), ("text/plain", None))
305+
eq(guess_type("data:;base64,thisIsTextPlain"), ("text/plain", None))
306+
eq(guess_type("data:text/x-foo,thisIsTextXFoo"), ("text/x-foo", None))
307+
308+
def test_file_parsing(self):
309+
eq = self.assertEqual
310+
sio = io.StringIO("x-application/x-unittest pyunit\n")
311+
self.db.readfp(sio)
312+
eq(self.db.guess_file_type("foo.pyunit"),
313+
("x-application/x-unittest", None))
314+
eq(self.db.guess_extension("x-application/x-unittest"), ".pyunit")
315+
316+
def test_non_standard_types(self):
317+
eq = self.assertEqual
318+
# First try strict
319+
eq(self.db.guess_file_type('foo.xul', strict=True), (None, None))
320+
# And then non-strict
321+
eq(self.db.guess_file_type('foo.xul', strict=False), ('text/xul', None))
322+
eq(self.db.guess_file_type('foo.XUL', strict=False), ('text/xul', None))
323+
eq(self.db.guess_file_type('foo.invalid', strict=False), (None, None))
324+
eq(self.db.guess_extension('image/jpeg', strict=False), '.jpg')
325+
eq(self.db.guess_extension('image/JPEG', strict=False), '.jpg')
326+
327+
def test_filename_with_url_delimiters(self):
328+
# bpo-38449: URL delimiters cases should be handled also.
329+
# They would have different mime types if interpreted as URL as
330+
# compared to when interpreted as filename because of the semicolon.
331+
eq = self.assertEqual
332+
gzip_expected = ('application/x-tar', 'gzip')
333+
for name in (
334+
';1.tar.gz',
335+
'?1.tar.gz',
336+
'#1.tar.gz',
337+
'#1#.tar.gz',
338+
';1#.tar.gz',
339+
';&1=123;?.tar.gz',
340+
'?k1=v1&k2=v2.tar.gz',
341+
):
342+
for prefix in ('', '/', '\\',
343+
'c:', 'c:/', 'c:\\', 'c:/d/', 'c:\\d\\',
344+
'//share/server/', '\\\\share\\server\\'):
345+
path = prefix + name
346+
with self.subTest(path=path):
347+
eq(self.db.guess_file_type(path), gzip_expected)
348+
eq(self.db.guess_type(path), gzip_expected)
349+
expected = (None, None) if os.name == 'nt' else gzip_expected
350+
for prefix in ('//', '\\\\', '//share/', '\\\\share\\'):
351+
path = prefix + name
352+
with self.subTest(path=path):
353+
eq(self.db.guess_file_type(path), expected)
354+
eq(self.db.guess_type(path), expected)
355+
eq(self.db.guess_file_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected)
356+
eq(self.db.guess_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected)
357+
358+
eq(self.db.guess_file_type(r'foo/.tar.gz'), (None, 'gzip'))
359+
eq(self.db.guess_type(r'foo/.tar.gz'), (None, 'gzip'))
360+
expected = (None, 'gzip') if os.name == 'nt' else gzip_expected
361+
eq(self.db.guess_file_type(r'foo\.tar.gz'), expected)
362+
eq(self.db.guess_type(r'foo\.tar.gz'), expected)
363+
eq(self.db.guess_type(r'scheme:foo\.tar.gz'), gzip_expected)
364+
365+
def test_url(self):
366+
result = self.db.guess_type('http://example.com/host.html')
367+
result = self.db.guess_type('http://host.html')
368+
msg = 'URL only has a host name, not a file'
369+
self.assertSequenceEqual(result, (None, None), msg)
370+
result = self.db.guess_type('http://example.com/host.html')
371+
msg = 'Should be text/html'
372+
self.assertSequenceEqual(result, ('text/html', None), msg)
373+
result = self.db.guess_type('http://example.com/host.html#x.tar')
374+
self.assertSequenceEqual(result, ('text/html', None))
375+
result = self.db.guess_type('http://example.com/host.html?q=x.tar')
376+
self.assertSequenceEqual(result, ('text/html', None))
377+
378+
def test_guess_all_types(self):
379+
# First try strict. Use a set here for testing the results because if
380+
# test_urllib2 is run before test_mimetypes, global state is modified
381+
# such that the 'all' set will have more items in it.
382+
all = self.db.guess_all_extensions('text/plain', strict=True)
383+
self.assertTrue(set(all) >= {'.bat', '.c', '.h', '.ksh', '.pl', '.txt'})
384+
self.assertEqual(len(set(all)), len(all)) # no duplicates
385+
# And now non-strict
386+
all = self.db.guess_all_extensions('image/jpeg', strict=False)
387+
self.assertEqual(all, ['.jpg', '.jpe', '.jpeg'])
388+
# And now for no hits
389+
all = self.db.guess_all_extensions('image/jpg', strict=True)
390+
self.assertEqual(all, [])
391+
# And now for type existing in both strict and non-strict mappings.
392+
self.db.add_type('test-type', '.strict-ext')
393+
self.db.add_type('test-type', '.non-strict-ext', strict=False)
394+
all = self.db.guess_all_extensions('test-type', strict=False)
395+
self.assertEqual(all, ['.strict-ext', '.non-strict-ext'])
396+
all = self.db.guess_all_extensions('test-type')
397+
self.assertEqual(all, ['.strict-ext'])
398+
# Test that changing the result list does not affect the global state
399+
all.append('.no-such-ext')
400+
all = self.db.guess_all_extensions('test-type')
401+
self.assertNotIn('.no-such-ext', all)
402+
403+
def test_encoding(self):
404+
filename = support.findfile("mime.types")
405+
mimes = mimetypes.MimeTypes([filename])
406+
exts = mimes.guess_all_extensions('application/vnd.geocube+xml',
407+
strict=True)
408+
self.assertEqual(exts, ['.g3', '.g\xb3'])
409+
344410
def test_path_like_ob(self):
345411
filename = "LICENSE.txt"
346412
filepath = os_helper.FakePath(filename)
@@ -378,25 +444,6 @@ def test_keywords_args_api(self):
378444
self.assertEqual(self.db.guess_all_extensions(
379445
type='image/jpeg', strict=True), ['.jpg', '.jpe', '.jpeg'])
380446

381-
def test_added_types_are_used(self):
382-
mimetypes.add_type('testing/default-type', '')
383-
mime_type, _ = mimetypes.guess_type('')
384-
self.assertEqual(mime_type, 'testing/default-type')
385-
386-
mime_type, _ = mimetypes.guess_type('test.myext')
387-
self.assertEqual(mime_type, None)
388-
389-
mimetypes.add_type('testing/type', '.myext')
390-
mime_type, _ = mimetypes.guess_type('test.myext')
391-
self.assertEqual(mime_type, 'testing/type')
392-
393-
def test_add_type_with_undotted_extension_not_supported(self):
394-
msg = "Extension 'undotted' must start with '.'"
395-
with self.assertRaisesRegex(ValueError, msg):
396-
mimetypes.add_type("testing/type", "undotted")
397-
with self.assertRaisesRegex(ValueError, msg):
398-
mimetypes.add_type("", "undotted")
399-
400447

401448
@unittest.skipUnless(sys.platform.startswith("win"), "Windows only")
402449
class Win32MimeTypesTestCase(unittest.TestCase):

0 commit comments

Comments
 (0)