From 09abe3f6dccc2910b326df668a5215448eb55b78 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 5 Jun 2022 12:25:40 +0100 Subject: Rename test files to run with pytest --- README | 2 +- test/test-basedirectory.py | 117 ------------- test/test-desktop.py | 122 -------------- test/test-icon.py | 49 ------ test/test-inifile.py | 81 --------- test/test-locale.py | 7 - test/test-menu-rules.py | 183 -------------------- test/test-menu.py | 116 ------------- test/test-mime.py | 404 --------------------------------------------- test/test-recentfiles.py | 44 ----- test/test_basedirectory.py | 117 +++++++++++++ test/test_desktop.py | 122 ++++++++++++++ test/test_icon.py | 49 ++++++ test/test_inifile.py | 81 +++++++++ test/test_locale.py | 7 + test/test_menu.py | 116 +++++++++++++ test/test_menu_rules.py | 183 ++++++++++++++++++++ test/test_mime.py | 404 +++++++++++++++++++++++++++++++++++++++++++++ test/test_recentfiles.py | 44 +++++ 19 files changed, 1124 insertions(+), 1124 deletions(-) delete mode 100644 test/test-basedirectory.py delete mode 100644 test/test-desktop.py delete mode 100644 test/test-icon.py delete mode 100644 test/test-inifile.py delete mode 100644 test/test-locale.py delete mode 100644 test/test-menu-rules.py delete mode 100644 test/test-menu.py delete mode 100644 test/test-mime.py delete mode 100644 test/test-recentfiles.py create mode 100644 test/test_basedirectory.py create mode 100644 test/test_desktop.py create mode 100644 test/test_icon.py create mode 100644 test/test_inifile.py create mode 100644 test/test_locale.py create mode 100644 test/test_menu.py create mode 100644 test/test_menu_rules.py create mode 100644 test/test_mime.py create mode 100644 test/test_recentfiles.py diff --git a/README b/README index c09f489..36d47f5 100644 --- a/README +++ b/README @@ -18,4 +18,4 @@ The XDG Package contains: - Implementation of the XDG-Recent File Storage Specification http://standards.freedesktop.org/recent-file-spec/ -To run the tests, run nosetests in the top level directory. +To run the tests, run pytest in the top level directory. diff --git a/test/test-basedirectory.py b/test/test-basedirectory.py deleted file mode 100644 index 954f573..0000000 --- a/test/test-basedirectory.py +++ /dev/null @@ -1,117 +0,0 @@ -from xdg import BaseDirectory - -import os -from os import environ -import unittest -import tempfile, shutil -import stat - -try: - reload -except NameError: - from imp import reload - -class BaseDirectoryTest(unittest.TestCase): - def setUp(self): - self.environ_save = environ.copy() - - def tearDown(self): - # Restore environment variables - environ.clear() - for k, v in self.environ_save.items(): - environ[k] = v - - def test_save_config_path(self): - tmpdir = tempfile.mkdtemp() - try: - environ['XDG_CONFIG_HOME'] = tmpdir - reload(BaseDirectory) - configpath = BaseDirectory.save_config_path("foo") - self.assertEqual(configpath, os.path.join(tmpdir, "foo")) - finally: - shutil.rmtree(tmpdir) - - def test_save_data_path(self): - tmpdir = tempfile.mkdtemp() - try: - environ['XDG_DATA_HOME'] = tmpdir - reload(BaseDirectory) - datapath = BaseDirectory.save_data_path("foo") - self.assertEqual(datapath, os.path.join(tmpdir, "foo")) - finally: - shutil.rmtree(tmpdir) - - def test_save_cache_path(self): - tmpdir = tempfile.mkdtemp() - try: - environ['XDG_CACHE_HOME'] = tmpdir - reload(BaseDirectory) - datapath = BaseDirectory.save_cache_path("foo") - self.assertEqual(datapath, os.path.join(tmpdir, "foo")) - finally: - shutil.rmtree(tmpdir) - - def test_save_state_path(self): - tmpdir = tempfile.mkdtemp() - try: - environ['XDG_STATE_HOME'] = tmpdir - reload(BaseDirectory) - statepath = BaseDirectory.save_state_path("foo") - self.assertEqual(statepath, os.path.join(tmpdir, "foo")) - finally: - shutil.rmtree(tmpdir) - - def test_load_first_config(self): - tmpdir = tempfile.mkdtemp() - tmpdir2 = tempfile.mkdtemp() - tmpdir3 = tempfile.mkdtemp() - path = os.path.join(tmpdir3, "wpokewefketnrhruit") - os.mkdir(path) - try: - environ['XDG_CONFIG_HOME'] = tmpdir - environ['XDG_CONFIG_DIRS'] = ":".join([tmpdir2, tmpdir3]) - reload(BaseDirectory) - configdir = BaseDirectory.load_first_config("wpokewefketnrhruit") - self.assertEqual(configdir, path) - finally: - shutil.rmtree(tmpdir) - shutil.rmtree(tmpdir2) - shutil.rmtree(tmpdir3) - - def test_load_config_paths(self): - tmpdir = tempfile.mkdtemp() - path = os.path.join(tmpdir, "wpokewefketnrhruit") - os.mkdir(path) - tmpdir2 = tempfile.mkdtemp() - path2 = os.path.join(tmpdir2, "wpokewefketnrhruit") - os.mkdir(path2) - try: - environ['XDG_CONFIG_HOME'] = tmpdir - environ['XDG_CONFIG_DIRS'] = tmpdir2 + ":/etc/xdg" - reload(BaseDirectory) - configdirs = BaseDirectory.load_config_paths("wpokewefketnrhruit") - self.assertEqual(list(configdirs), [path, path2]) - finally: - shutil.rmtree(tmpdir) - shutil.rmtree(tmpdir2) - - def test_runtime_dir(self): - rd = '/pyxdg-example/run/user/fred' - environ['XDG_RUNTIME_DIR'] = rd - self.assertEqual(BaseDirectory.get_runtime_dir(strict=True), rd) - self.assertEqual(BaseDirectory.get_runtime_dir(strict=False), rd) - - def test_runtime_dir_notset(self): - environ.pop('XDG_RUNTIME_DIR', None) - self.assertRaises(KeyError, BaseDirectory.get_runtime_dir, strict=True) - fallback = BaseDirectory.get_runtime_dir(strict=False) - assert fallback.startswith('/tmp/'), fallback - assert os.path.isdir(fallback), fallback - mode = stat.S_IMODE(os.stat(fallback).st_mode) - self.assertEqual(mode, stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR) - - # Calling it again should return the same directory. - fallback2 = BaseDirectory.get_runtime_dir(strict=False) - self.assertEqual(fallback, fallback2) - mode = stat.S_IMODE(os.stat(fallback2).st_mode) - self.assertEqual(mode, stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR) diff --git a/test/test-desktop.py b/test/test-desktop.py deleted file mode 100644 index 9f88af6..0000000 --- a/test/test-desktop.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3 -# coding: utf-8 -from xdg.DesktopEntry import DesktopEntry -from xdg.Exceptions import ValidationError, ParsingError, NoKeyError -from xdg.util import u - -import resources - -import io -import os -import shutil -import re -import tempfile -import unittest - -class DesktopEntryTest(unittest.TestCase): - def setUp(self): - self.tmpdir = tempfile.mkdtemp() - self.test_file = os.path.join(self.tmpdir, "gedit.desktop") - with io.open(self.test_file, "w", encoding='utf-8') as f: - f.write(resources.gedit_desktop) - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def test_write_file(self): - de = DesktopEntry() - de.parse(self.test_file) - de.removeKey("Name") - de.addGroup("Hallo") - de.set("key", "value", "Hallo") - - new_file = os.path.join(self.tmpdir, "test.desktop") - de.write(new_file, trusted=True) - - with io.open(new_file, encoding='utf-8') as f: - contents = f.read() - - assert "[Hallo]" in contents, contents - assert re.search(r"key\s*=\s*value", contents), contents - - # This is missing the Name key, and has an unknown Hallo group, so it - # shouldn't validate. - new_entry = DesktopEntry(new_file) - self.assertRaises(ValidationError, new_entry.validate) - - def test_validate(self): - entry = DesktopEntry(self.test_file) - entry.validate() - - def test_values(self): - entry = DesktopEntry(self.test_file) - self.assertEqual(entry.getName(), 'gedit') - self.assertEqual(entry.getGenericName(), 'Text Editor') - self.assertEqual(entry.getNoDisplay(), False) - self.assertEqual(entry.getComment(), 'Edit text files') - self.assertEqual(entry.getIcon(), 'accessories-text-editor') - self.assertEqual(entry.getHidden(), False) - self.assertEqual(entry.getOnlyShowIn(), []) - self.assertEqual(entry.getExec(), 'gedit %U') - self.assertEqual(entry.getTerminal(), False) - self.assertEqual(entry.getMimeTypes(), ['text/plain']) - self.assertEqual(entry.getCategories(), ['GNOME', 'GTK', 'Utility', 'TextEditor']) - self.assertEqual(entry.getTerminal(), False) - - def test_basic(self): - entry = DesktopEntry(self.test_file) - assert entry.hasKey("Categories") - assert not entry.hasKey("TryExec") - - assert entry.hasGroup("Desktop Action Window") - assert not entry.hasGroup("Desktop Action Door") - - def test_unicode_name(self): - with io.open(self.test_file, "w", encoding='utf-8') as f: - f.write(resources.unicode_desktop) - - entry = DesktopEntry(self.test_file) - self.assertEqual(entry.getName(), u('Abc€þ')) - - def test_invalid(self): - test_file = os.path.join(self.tmpdir, "spout.desktop") - with io.open(test_file, "w", encoding='utf-8') as f: - f.write(resources.spout_desktop) - - self.assertRaises(ParsingError, DesktopEntry, test_file) - - def test_invalid_unicode(self): - test_file = os.path.join(self.tmpdir, "gnome-alsamixer.desktop") - with io.open(test_file, "w", encoding='latin-1') as f: - f.write(resources.gnome_alsamixer_desktop) - - # Just check this doesn't throw a UnicodeError. - DesktopEntry(test_file) - -class TestTryExec(unittest.TestCase): - def setUp(self): - self.tmpdir = tempfile.mkdtemp() - self.test_file = os.path.join(self.tmpdir, "foo.desktop") - - def test_present(self): - with io.open(self.test_file, "w", encoding='utf-8') as f: - f.write(resources.python_desktop) - - entry = DesktopEntry(self.test_file) - res = entry.findTryExec() - assert res, repr(res) - - def test_absent(self): - with io.open(self.test_file, "w", encoding='utf-8') as f: - f.write(resources.unicode_desktop) - - entry = DesktopEntry(self.test_file) - res = entry.findTryExec() - assert res is None, repr(res) - - def test_no_TryExec(self): - with io.open(self.test_file, "w", encoding='utf-8') as f: - f.write(resources.gedit_desktop) - - entry = DesktopEntry(self.test_file) - self.assertRaises(NoKeyError, entry.findTryExec) diff --git a/test/test-icon.py b/test/test-icon.py deleted file mode 100644 index 5a2731b..0000000 --- a/test/test-icon.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 -from xdg.IconTheme import IconTheme, getIconPath, getIconData -import tempfile, shutil, os -import unittest - -import resources - -example_dir = os.path.join(os.path.dirname(__file__), 'example') -def example_file(filename): - return os.path.join(example_dir, filename) - -class IconThemeTest(unittest.TestCase): - def test_find_icon_exists(self): - print("Finding an icon that probably exists:") - print (getIconPath("firefox")) - - def test_find_icon_nonexistant(self): - icon = getIconPath("oijeorjewrjkngjhbqefew") - assert icon is None, "%r is not None" % icon - - def test_validate_icon_theme(self): - theme = IconTheme() - theme.parse(example_file("index.theme")) - theme.validate() - -class IconDataTest(unittest.TestCase): - def test_read_icon_data(self): - tmpdir = tempfile.mkdtemp() - try: - png_file = os.path.join(tmpdir, "test.png") - with open(png_file, "wb") as f: - f.write(resources.png_data) - - icon_file = os.path.join(tmpdir, "test.icon") - with open(icon_file, "w") as f: - f.write(resources.icon_data) - - icondata = getIconData(png_file) - icondata.validate() - - self.assertEqual(icondata.getDisplayName(), 'Mime text/plain') - self.assertEqual(icondata.getAttachPoints(), [(200,200), (800,200), (500,500), (200,800), (800,800)]) - self.assertEqual(icondata.getEmbeddedTextRectangle(), [100,100,900,900]) - - assert " - - Accessibility - - Settings - - - screenreader.desktop - - """, - 'data': [ - ('app1.desktop', ['Accessibility'], True), - ('app2.desktop', ['Accessibility', 'Settings'], False), - ('app3.desktop', ['Accessibility', 'Preferences'], True), - ('app4.desktop', ['Graphics', 'Settings'], False), - ('screenreader.desktop', ['Utility', 'Other'], True) - ] - }, - { - 'doc': """ - - - Settings - - - System - X-GNOME-Settings-Panel - foobar.desktop - - - - - """, - 'data': [ - ('app0.desktop', [], False), - ('app1.desktop', ['Settings'], True), - ('app2.desktop', ['System', 'Settings'], False), - ('app3.desktop', ['Games', 'Preferences'], False), - ('app4.desktop', ['Graphics', 'Settings'], True), - ('app5.desktop', ['X-GNOME-Settings-Panel', 'Settings'], False), - ('foobar.desktop', ['Settings', 'Other'], False) - ] - }, - # Empty conditions - { - 'doc': "", - 'data': [ - ('app0.desktop', ['Graphics', 'Settings'], False), - ('screenreader.desktop', [], False) - ] - }, - { - 'doc': "", - 'data': [ - ('app0.desktop', ['Graphics', 'Settings'], False), - ('screenreader.desktop', [], False) - ] - }, - { - 'doc': "", - 'data': [ - ('app0.desktop', ['Graphics', 'Settings'], False), - ('screenreader.desktop', [], False) - ] - }, - { - 'doc': "", - 'data': [ - ('app0.desktop', ['Graphics', 'Settings'], False), - ('screenreader.desktop', [], False) - ] - }, - { - 'doc': """ - - screenreader.desktop - - - """, - 'data': [ - ('app0.desktop', ['Graphics', 'Settings'], False), - ('screenreader.desktop', [], True) - ] - }, - { - 'doc': """ - - - screenreader.desktop - - - - """, - 'data': [ - ('app0.desktop', ['Graphics', 'Settings'], False), - ('screenreader.desktop', [], True) - ] - }, - # Single condition - { - 'doc': "foobar.desktop", - 'data': [ - ('app0.desktop', ['Graphics', 'Settings'], False), - ('foobar.desktop', [], True) - ] - }, - # All - { - 'doc': "", - 'data': [ - ('app0.desktop', ['Graphics', 'Settings'], True), - ('foobar.desktop', [], True) - ] - }, - { - 'doc': "foobar.desktop", - 'data': [ - ('app0.desktop', ['Graphics', 'Settings'], True), - ('foobar.desktop', [], True) - ] - }, - { - 'doc': """ - - foobar.desktop - Graphics - - - """, - 'data': [ - ('app0.desktop', ['Graphics', 'Settings'], True), - ('app1.desktop', ['Accessibility'], False), - ('app2.desktop', ['Accessibility', 'Settings'], False), - ('foobar.desktop', [], True), - ] - } -] - - -class MockMenuEntry(object): - - def __init__(self, id, categories): - self.DesktopFileID = id - self.Categories = categories - - def __str__(self): - return "<%s: %s>" % (self.DesktopFileID, self.Categories) - - -class RulesTest(unittest.TestCase): - """Basic rule matching tests""" - - def test_rule_from_node(self): - parser = XMLMenuBuilder(debug=True) - for i, test in enumerate(_tests): - root = etree.fromstring(test['doc']) - rule = parser.parse_rule(root) - for j, data in enumerate(test['data']): - menuentry = MockMenuEntry(data[0], data[1]) - result = eval(rule.code) - message = "Error in test %s with result set %s: got %s, expected %s" - assert result == data[2], message % (i, j, result, data[2]) - - def test_rule_from_filename(self): - tests = [ - ('foobar.desktop', 'foobar.desktop', True), - ('barfoo.desktop', 'foobar.desktop', False) - ] - for i, test in enumerate(tests): - rule = Rule.fromFilename(Rule.TYPE_INCLUDE, test[0]) - menuentry = MockMenuEntry(test[1], []) - result = eval(rule.code) - message = "Error with result set %s: got %s, expected %s" - assert result == test[2], message % (i, result, test[2]) diff --git a/test/test-menu.py b/test/test-menu.py deleted file mode 100644 index 0139534..0000000 --- a/test/test-menu.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env python3 -from __future__ import print_function - -import io -import os -import os.path -import shutil -import tempfile -import unittest - -import xdg.Menu -import xdg.DesktopEntry -import resources - -def show_menu(menu, depth = 0): - print(depth*"-" + "\x1b[01m" + menu.getName() + "\x1b[0m") - depth += 1 - for entry in menu.getEntries(): - if isinstance(entry, xdg.Menu.Menu): - show_menu(entry, depth) - elif isinstance(entry, xdg.Menu.MenuEntry): - print(depth*"-" + entry.DesktopEntry.getName()) - print(depth*" " + menu.getPath(), entry.DesktopFileID, entry.DesktopEntry.getFileName()) - elif isinstance(entry, xdg.Menu.Separator): - print(depth*"-" + "|||") - elif isinstance(entry, xdg.Menu.Header): - print(depth*"-" + "\x1b[01m" + entry.Name + "\x1b[0m") - depth -= 1 - -def entry_names(entries): - names = [] - for entry in entries: - if isinstance(entry, xdg.Menu.Menu): - names.append(entry.getName()) - elif isinstance(entry, xdg.Menu.MenuEntry): - names.append(entry.DesktopEntry.getName()) - elif isinstance(entry, xdg.Menu.Separator): - names.append("---") - elif isinstance(entry, xdg.Menu.Header): - names.append(entry.Name) - return names - -class MenuTest(unittest.TestCase): - def setUp(self): - self.tmpdir = tempfile.mkdtemp() - self.test_file = os.path.join(self.tmpdir, "applications.menu") - with open(self.test_file, "w") as f: - f.write(resources.applications_menu) - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def test_parse_menu(self): - menu = xdg.Menu.parse(self.test_file) - show_menu(menu) - - # Check these don't throw an error - menu.getName() - menu.getGenericName() - menu.getComment() - menu.getIcon() - - def test_parse_layout(self): - test_file = os.path.join(self.tmpdir, "layout.menu") - with io.open(test_file, "w") as f: - f.write(resources.layout_menu) - menu = xdg.Menu.parse(test_file) - show_menu(menu) - - assert len(menu.Entries) == 4 - assert entry_names(menu.Entries) == ["Accessories", "Games", "---", "More"] - - games_menu = menu.getMenu("Games") - assert len(games_menu.Entries) == 4 - assert entry_names(games_menu.Entries) == ["Steam", "---", "Action", "Arcade"] - - def test_unicode_menuentry(self): - test_file = os.path.join(self.tmpdir, "unicode.desktop") - with io.open(test_file, 'w', encoding='utf-8') as f: - f.write(resources.unicode_desktop) - - entry = xdg.Menu.MenuEntry(test_file) - assert entry == entry - assert not entry < entry - - def test_empty_legacy_dirs(self): - legacy_dir = os.path.join(self.tmpdir, "applnk") - os.mkdir(legacy_dir) - os.mkdir(os.path.join(legacy_dir, "Toys")) - os.mkdir(os.path.join(legacy_dir, "Utilities")) - test_file = os.path.join(self.tmpdir, "legacy.menu") - with open(test_file, "w") as f: - f.write(resources.legacy_menu.replace("legacy_dir", legacy_dir)) - - menu = xdg.Menu.parse(test_file) - - # The menu should be empty besides the root named "Legacy" - show_menu(menu) - - assert len(menu.Entries) == 0 - - def test_kde_legacy_dirs(self): - """This was failing on systems which didn't have kde-config installed. - We just check that parsing doesn't throw an error. - - See fd.o bug #56426. - """ - test_file = os.path.join(self.tmpdir, "kde_legacy.menu") - with open(test_file, "w") as f: - f.write(resources.kde_legacy_menu) - - menu = xdg.Menu.parse(test_file) - - -if __name__ == '__main__': - unittest.main() diff --git a/test/test-mime.py b/test/test-mime.py deleted file mode 100644 index cc10a3c..0000000 --- a/test/test-mime.py +++ /dev/null @@ -1,404 +0,0 @@ -from xdg import Mime -import unittest -import os.path -import tempfile, shutil - -import resources - -example_dir = os.path.join(os.path.dirname(__file__), 'example') -def example_file(filename): - return os.path.join(example_dir, filename) - -class MimeTestBase(unittest.TestCase): - def check_mimetype(self, mimetype, media, subtype): - self.assertEqual(mimetype.media, media) - self.assertEqual(mimetype.subtype, subtype) - -class MimeTest(MimeTestBase): - def test_create_mimetype(self): - mt1 = Mime.MIMEtype('application', 'pdf') - mt2 = Mime.MIMEtype('application', 'pdf') - self.assertEqual(id(mt1), id(mt2)) # Check caching - - amr = Mime.MIMEtype('audio', 'AMR') - self.check_mimetype(amr, 'audio', 'amr') # Check lowercase - - ogg = Mime.MIMEtype('audio/ogg') - self.check_mimetype(ogg, 'audio', 'ogg') # Check split on / - - self.assertRaises(Exception, Mime.MIMEtype, 'audio/foo/bar') - - def test_get_type_by_name(self): - appzip = Mime.get_type_by_name("foo.zip") - self.check_mimetype(appzip, 'application', 'zip') - - def test_get_type_by_data(self): - imgpng = Mime.get_type_by_data(resources.png_data) - self.check_mimetype(imgpng, 'image', 'png') - - def test_mimetype_repr(self): - mt = Mime.lookup('application', 'zip') - repr(mt) # Just check that this doesn't throw an error. - - def test_get_type_by_contents(self): - tmpdir = tempfile.mkdtemp() - try: - test_file = os.path.join(tmpdir, "test") - with open(test_file, "wb") as f: - f.write(resources.png_data) - - imgpng = Mime.get_type_by_contents(test_file) - self.check_mimetype(imgpng, 'image', 'png') - - finally: - shutil.rmtree(tmpdir) - - def test_get_type(self): - # File that doesn't exist - get type by name - imgpng = Mime.get_type(example_file("test.gif")) - self.check_mimetype(imgpng, 'image', 'gif') - - # File that does exist - get type by contents - imgpng = Mime.get_type(example_file("png_file")) - self.check_mimetype(imgpng, 'image', 'png') - - # Directory - special case - inodedir = Mime.get_type(example_file("subdir")) - self.check_mimetype(inodedir, 'inode', 'directory') - - # Mystery files - mystery_text = Mime.get_type(example_file('mystery_text')) - self.check_mimetype(mystery_text, 'text', 'plain') - mystery_exe = Mime.get_type(example_file('mystery_exe')) - self.check_mimetype(mystery_exe, 'application', 'executable') - - # Symlink - self.check_mimetype(Mime.get_type(example_file("png_symlink")), - 'image', 'png') - self.check_mimetype(Mime.get_type(example_file("png_symlink"), follow=False), - 'inode', 'symlink') - - def test_get_type2(self): - # File that doesn't exist - use the name - self.check_mimetype(Mime.get_type2(example_file('test.gif')), 'image', 'gif') - - # File that does exist - use the contents - self.check_mimetype(Mime.get_type2(example_file('png_file')), 'image', 'png') - - # Does exist - use name before contents - self.check_mimetype(Mime.get_type2(example_file('file.png')), 'image', 'png') - self.check_mimetype(Mime.get_type2(example_file('word.doc')), 'application', 'msword') - - # Ambiguous file extension - glade_mime = Mime.get_type2(example_file('glade.ui')) - self.assertEqual(glade_mime.media, 'application') - # Grumble, this is still ambiguous on some systems - self.assertIn(glade_mime.subtype, {'x-gtk-builder', 'x-glade'}) - self.check_mimetype(Mime.get_type2(example_file('qtdesigner.ui')), 'application', 'x-designer') - - # text/x-python has greater weight than text/x-readme - self.check_mimetype(Mime.get_type2(example_file('README.py')), 'text', 'x-python') - - # Directory - special filesystem object - self.check_mimetype(Mime.get_type2(example_file('subdir')), 'inode', 'directory') - - # Mystery files: - mystery_missing = Mime.get_type2(example_file('mystery_missing')) - self.check_mimetype(mystery_missing, 'application', 'octet-stream') - mystery_binary = Mime.get_type2(example_file('mystery_binary')) - self.check_mimetype(mystery_binary, 'application', 'octet-stream') - mystery_text = Mime.get_type2(example_file('mystery_text')) - self.check_mimetype(mystery_text, 'text', 'plain') - mystery_exe = Mime.get_type2(example_file('mystery_exe')) - self.check_mimetype(mystery_exe, 'application', 'executable') - - # Symlink - self.check_mimetype(Mime.get_type2(example_file("png_symlink")), - 'image', 'png') - self.check_mimetype(Mime.get_type2(example_file("png_symlink"), follow=False), - 'inode', 'symlink') - - def test_lookup(self): - pdf1 = Mime.lookup("application/pdf") - pdf2 = Mime.lookup("application", "pdf") - self.assertEqual(pdf1, pdf2) - self.check_mimetype(pdf1, 'application', 'pdf') - - def test_get_comment(self): - # Check these don't throw an error. One that is likely to exist: - Mime.MIMEtype("application", "pdf").get_comment() - # And one that's unlikely to exist: - Mime.MIMEtype("application", "ierjg").get_comment() - - def test_by_name(self): - dot_c = Mime.get_type_by_name('foo.c') - self.check_mimetype(dot_c, 'text', 'x-csrc') - dot_C = Mime.get_type_by_name('foo.C') - self.check_mimetype(dot_C, 'text', 'x-c++src') - - # But most names should be case insensitive - dot_GIF = Mime.get_type_by_name('IMAGE.GIF') - self.check_mimetype(dot_GIF, 'image', 'gif') - - def test_canonical(self): - text_xml = Mime.lookup('text/xml') - self.check_mimetype(text_xml, 'text', 'xml') - self.check_mimetype(text_xml.canonical(), 'application', 'xml') - - # Already is canonical - python = Mime.lookup('text/x-python') - self.check_mimetype(python.canonical(), 'text', 'x-python') - - def test_inheritance(self): - text_python = Mime.lookup('text/x-python') - self.check_mimetype(text_python, 'text', 'x-python') - text_plain = Mime.lookup('text/plain') - app_executable = Mime.lookup('application/x-executable') - self.assertEqual(text_python.inherits_from(), set([text_plain, app_executable])) - - def test_is_text(self): - assert Mime._is_text(b'abcdef \n') - assert not Mime._is_text(b'abcdef\x08') - assert not Mime._is_text(b'abcdef\x0e') - assert not Mime._is_text(b'abcdef\x1f') - assert not Mime._is_text(b'abcdef\x7f') - - # Check nonexistant file. - assert not Mime.is_text_file('/fwoijorij') - -class MagicDBTest(MimeTestBase): - def setUp(self): - self.tmpdir = tempfile.mkdtemp() - self.path = os.path.join(self.tmpdir, 'mimemagic') - with open(self.path, 'wb') as f: - f.write(resources.mime_magic_db) - - self.path2 = os.path.join(self.tmpdir, 'mimemagic2') - with open(self.path2, 'wb') as f: - f.write(resources.mime_magic_db2) - - # Read the files - self.magic = Mime.MagicDB() - self.magic.merge_file(self.path) - self.magic.merge_file(self.path2) - self.magic.finalise() - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def test_parsing(self): - self.assertEqual(len(self.magic.bytype), 9) - - # Check repr() doesn't throw an error - repr(self.magic) - - prio, png = self.magic.bytype[Mime.lookup('image', 'png')][0] - self.assertEqual(prio, 50) - assert isinstance(png, Mime.MagicRule), type(png) - repr(png) # Check this doesn't throw an error. - self.assertEqual(png.start, 0) - self.assertEqual(png.value, b'\x89PNG') - self.assertEqual(png.mask, None) - self.assertEqual(png.also, None) - - prio, jpeg = self.magic.bytype[Mime.lookup('image', 'jpeg')][0] - assert isinstance(jpeg, Mime.MagicMatchAny), type(jpeg) - self.assertEqual(len(jpeg.rules), 2) - self.assertEqual(jpeg.rules[0].value, b'\xff\xd8\xff') - - prio, ora = self.magic.bytype[Mime.lookup('image', 'openraster')][0] - assert isinstance(ora, Mime.MagicRule), type(ora) - self.assertEqual(ora.value, b'PK\x03\x04') - ora1 = ora.also - assert ora1 is not None - self.assertEqual(ora1.start, 30) - ora2 = ora1.also - assert ora2 is not None - self.assertEqual(ora2.start, 38) - self.assertEqual(ora2.value, b'image/openraster') - - prio, svg = self.magic.bytype[Mime.lookup('image', 'svg+xml')][0] - self.assertEqual(len(svg.rules), 2) - self.assertEqual(svg.rules[0].value, b' + + Accessibility + + Settings + + + screenreader.desktop + + """, + 'data': [ + ('app1.desktop', ['Accessibility'], True), + ('app2.desktop', ['Accessibility', 'Settings'], False), + ('app3.desktop', ['Accessibility', 'Preferences'], True), + ('app4.desktop', ['Graphics', 'Settings'], False), + ('screenreader.desktop', ['Utility', 'Other'], True) + ] + }, + { + 'doc': """ + + + Settings + + + System + X-GNOME-Settings-Panel + foobar.desktop + + + + + """, + 'data': [ + ('app0.desktop', [], False), + ('app1.desktop', ['Settings'], True), + ('app2.desktop', ['System', 'Settings'], False), + ('app3.desktop', ['Games', 'Preferences'], False), + ('app4.desktop', ['Graphics', 'Settings'], True), + ('app5.desktop', ['X-GNOME-Settings-Panel', 'Settings'], False), + ('foobar.desktop', ['Settings', 'Other'], False) + ] + }, + # Empty conditions + { + 'doc': "", + 'data': [ + ('app0.desktop', ['Graphics', 'Settings'], False), + ('screenreader.desktop', [], False) + ] + }, + { + 'doc': "", + 'data': [ + ('app0.desktop', ['Graphics', 'Settings'], False), + ('screenreader.desktop', [], False) + ] + }, + { + 'doc': "", + 'data': [ + ('app0.desktop', ['Graphics', 'Settings'], False), + ('screenreader.desktop', [], False) + ] + }, + { + 'doc': "", + 'data': [ + ('app0.desktop', ['Graphics', 'Settings'], False), + ('screenreader.desktop', [], False) + ] + }, + { + 'doc': """ + + screenreader.desktop + + + """, + 'data': [ + ('app0.desktop', ['Graphics', 'Settings'], False), + ('screenreader.desktop', [], True) + ] + }, + { + 'doc': """ + + + screenreader.desktop + + + + """, + 'data': [ + ('app0.desktop', ['Graphics', 'Settings'], False), + ('screenreader.desktop', [], True) + ] + }, + # Single condition + { + 'doc': "foobar.desktop", + 'data': [ + ('app0.desktop', ['Graphics', 'Settings'], False), + ('foobar.desktop', [], True) + ] + }, + # All + { + 'doc': "", + 'data': [ + ('app0.desktop', ['Graphics', 'Settings'], True), + ('foobar.desktop', [], True) + ] + }, + { + 'doc': "foobar.desktop", + 'data': [ + ('app0.desktop', ['Graphics', 'Settings'], True), + ('foobar.desktop', [], True) + ] + }, + { + 'doc': """ + + foobar.desktop + Graphics + + + """, + 'data': [ + ('app0.desktop', ['Graphics', 'Settings'], True), + ('app1.desktop', ['Accessibility'], False), + ('app2.desktop', ['Accessibility', 'Settings'], False), + ('foobar.desktop', [], True), + ] + } +] + + +class MockMenuEntry(object): + + def __init__(self, id, categories): + self.DesktopFileID = id + self.Categories = categories + + def __str__(self): + return "<%s: %s>" % (self.DesktopFileID, self.Categories) + + +class RulesTest(unittest.TestCase): + """Basic rule matching tests""" + + def test_rule_from_node(self): + parser = XMLMenuBuilder(debug=True) + for i, test in enumerate(_tests): + root = etree.fromstring(test['doc']) + rule = parser.parse_rule(root) + for j, data in enumerate(test['data']): + menuentry = MockMenuEntry(data[0], data[1]) + result = eval(rule.code) + message = "Error in test %s with result set %s: got %s, expected %s" + assert result == data[2], message % (i, j, result, data[2]) + + def test_rule_from_filename(self): + tests = [ + ('foobar.desktop', 'foobar.desktop', True), + ('barfoo.desktop', 'foobar.desktop', False) + ] + for i, test in enumerate(tests): + rule = Rule.fromFilename(Rule.TYPE_INCLUDE, test[0]) + menuentry = MockMenuEntry(test[1], []) + result = eval(rule.code) + message = "Error with result set %s: got %s, expected %s" + assert result == test[2], message % (i, result, test[2]) diff --git a/test/test_mime.py b/test/test_mime.py new file mode 100644 index 0000000..cc10a3c --- /dev/null +++ b/test/test_mime.py @@ -0,0 +1,404 @@ +from xdg import Mime +import unittest +import os.path +import tempfile, shutil + +import resources + +example_dir = os.path.join(os.path.dirname(__file__), 'example') +def example_file(filename): + return os.path.join(example_dir, filename) + +class MimeTestBase(unittest.TestCase): + def check_mimetype(self, mimetype, media, subtype): + self.assertEqual(mimetype.media, media) + self.assertEqual(mimetype.subtype, subtype) + +class MimeTest(MimeTestBase): + def test_create_mimetype(self): + mt1 = Mime.MIMEtype('application', 'pdf') + mt2 = Mime.MIMEtype('application', 'pdf') + self.assertEqual(id(mt1), id(mt2)) # Check caching + + amr = Mime.MIMEtype('audio', 'AMR') + self.check_mimetype(amr, 'audio', 'amr') # Check lowercase + + ogg = Mime.MIMEtype('audio/ogg') + self.check_mimetype(ogg, 'audio', 'ogg') # Check split on / + + self.assertRaises(Exception, Mime.MIMEtype, 'audio/foo/bar') + + def test_get_type_by_name(self): + appzip = Mime.get_type_by_name("foo.zip") + self.check_mimetype(appzip, 'application', 'zip') + + def test_get_type_by_data(self): + imgpng = Mime.get_type_by_data(resources.png_data) + self.check_mimetype(imgpng, 'image', 'png') + + def test_mimetype_repr(self): + mt = Mime.lookup('application', 'zip') + repr(mt) # Just check that this doesn't throw an error. + + def test_get_type_by_contents(self): + tmpdir = tempfile.mkdtemp() + try: + test_file = os.path.join(tmpdir, "test") + with open(test_file, "wb") as f: + f.write(resources.png_data) + + imgpng = Mime.get_type_by_contents(test_file) + self.check_mimetype(imgpng, 'image', 'png') + + finally: + shutil.rmtree(tmpdir) + + def test_get_type(self): + # File that doesn't exist - get type by name + imgpng = Mime.get_type(example_file("test.gif")) + self.check_mimetype(imgpng, 'image', 'gif') + + # File that does exist - get type by contents + imgpng = Mime.get_type(example_file("png_file")) + self.check_mimetype(imgpng, 'image', 'png') + + # Directory - special case + inodedir = Mime.get_type(example_file("subdir")) + self.check_mimetype(inodedir, 'inode', 'directory') + + # Mystery files + mystery_text = Mime.get_type(example_file('mystery_text')) + self.check_mimetype(mystery_text, 'text', 'plain') + mystery_exe = Mime.get_type(example_file('mystery_exe')) + self.check_mimetype(mystery_exe, 'application', 'executable') + + # Symlink + self.check_mimetype(Mime.get_type(example_file("png_symlink")), + 'image', 'png') + self.check_mimetype(Mime.get_type(example_file("png_symlink"), follow=False), + 'inode', 'symlink') + + def test_get_type2(self): + # File that doesn't exist - use the name + self.check_mimetype(Mime.get_type2(example_file('test.gif')), 'image', 'gif') + + # File that does exist - use the contents + self.check_mimetype(Mime.get_type2(example_file('png_file')), 'image', 'png') + + # Does exist - use name before contents + self.check_mimetype(Mime.get_type2(example_file('file.png')), 'image', 'png') + self.check_mimetype(Mime.get_type2(example_file('word.doc')), 'application', 'msword') + + # Ambiguous file extension + glade_mime = Mime.get_type2(example_file('glade.ui')) + self.assertEqual(glade_mime.media, 'application') + # Grumble, this is still ambiguous on some systems + self.assertIn(glade_mime.subtype, {'x-gtk-builder', 'x-glade'}) + self.check_mimetype(Mime.get_type2(example_file('qtdesigner.ui')), 'application', 'x-designer') + + # text/x-python has greater weight than text/x-readme + self.check_mimetype(Mime.get_type2(example_file('README.py')), 'text', 'x-python') + + # Directory - special filesystem object + self.check_mimetype(Mime.get_type2(example_file('subdir')), 'inode', 'directory') + + # Mystery files: + mystery_missing = Mime.get_type2(example_file('mystery_missing')) + self.check_mimetype(mystery_missing, 'application', 'octet-stream') + mystery_binary = Mime.get_type2(example_file('mystery_binary')) + self.check_mimetype(mystery_binary, 'application', 'octet-stream') + mystery_text = Mime.get_type2(example_file('mystery_text')) + self.check_mimetype(mystery_text, 'text', 'plain') + mystery_exe = Mime.get_type2(example_file('mystery_exe')) + self.check_mimetype(mystery_exe, 'application', 'executable') + + # Symlink + self.check_mimetype(Mime.get_type2(example_file("png_symlink")), + 'image', 'png') + self.check_mimetype(Mime.get_type2(example_file("png_symlink"), follow=False), + 'inode', 'symlink') + + def test_lookup(self): + pdf1 = Mime.lookup("application/pdf") + pdf2 = Mime.lookup("application", "pdf") + self.assertEqual(pdf1, pdf2) + self.check_mimetype(pdf1, 'application', 'pdf') + + def test_get_comment(self): + # Check these don't throw an error. One that is likely to exist: + Mime.MIMEtype("application", "pdf").get_comment() + # And one that's unlikely to exist: + Mime.MIMEtype("application", "ierjg").get_comment() + + def test_by_name(self): + dot_c = Mime.get_type_by_name('foo.c') + self.check_mimetype(dot_c, 'text', 'x-csrc') + dot_C = Mime.get_type_by_name('foo.C') + self.check_mimetype(dot_C, 'text', 'x-c++src') + + # But most names should be case insensitive + dot_GIF = Mime.get_type_by_name('IMAGE.GIF') + self.check_mimetype(dot_GIF, 'image', 'gif') + + def test_canonical(self): + text_xml = Mime.lookup('text/xml') + self.check_mimetype(text_xml, 'text', 'xml') + self.check_mimetype(text_xml.canonical(), 'application', 'xml') + + # Already is canonical + python = Mime.lookup('text/x-python') + self.check_mimetype(python.canonical(), 'text', 'x-python') + + def test_inheritance(self): + text_python = Mime.lookup('text/x-python') + self.check_mimetype(text_python, 'text', 'x-python') + text_plain = Mime.lookup('text/plain') + app_executable = Mime.lookup('application/x-executable') + self.assertEqual(text_python.inherits_from(), set([text_plain, app_executable])) + + def test_is_text(self): + assert Mime._is_text(b'abcdef \n') + assert not Mime._is_text(b'abcdef\x08') + assert not Mime._is_text(b'abcdef\x0e') + assert not Mime._is_text(b'abcdef\x1f') + assert not Mime._is_text(b'abcdef\x7f') + + # Check nonexistant file. + assert not Mime.is_text_file('/fwoijorij') + +class MagicDBTest(MimeTestBase): + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + self.path = os.path.join(self.tmpdir, 'mimemagic') + with open(self.path, 'wb') as f: + f.write(resources.mime_magic_db) + + self.path2 = os.path.join(self.tmpdir, 'mimemagic2') + with open(self.path2, 'wb') as f: + f.write(resources.mime_magic_db2) + + # Read the files + self.magic = Mime.MagicDB() + self.magic.merge_file(self.path) + self.magic.merge_file(self.path2) + self.magic.finalise() + + def tearDown(self): + shutil.rmtree(self.tmpdir) + + def test_parsing(self): + self.assertEqual(len(self.magic.bytype), 9) + + # Check repr() doesn't throw an error + repr(self.magic) + + prio, png = self.magic.bytype[Mime.lookup('image', 'png')][0] + self.assertEqual(prio, 50) + assert isinstance(png, Mime.MagicRule), type(png) + repr(png) # Check this doesn't throw an error. + self.assertEqual(png.start, 0) + self.assertEqual(png.value, b'\x89PNG') + self.assertEqual(png.mask, None) + self.assertEqual(png.also, None) + + prio, jpeg = self.magic.bytype[Mime.lookup('image', 'jpeg')][0] + assert isinstance(jpeg, Mime.MagicMatchAny), type(jpeg) + self.assertEqual(len(jpeg.rules), 2) + self.assertEqual(jpeg.rules[0].value, b'\xff\xd8\xff') + + prio, ora = self.magic.bytype[Mime.lookup('image', 'openraster')][0] + assert isinstance(ora, Mime.MagicRule), type(ora) + self.assertEqual(ora.value, b'PK\x03\x04') + ora1 = ora.also + assert ora1 is not None + self.assertEqual(ora1.start, 30) + ora2 = ora1.also + assert ora2 is not None + self.assertEqual(ora2.start, 38) + self.assertEqual(ora2.value, b'image/openraster') + + prio, svg = self.magic.bytype[Mime.lookup('image', 'svg+xml')][0] + self.assertEqual(len(svg.rules), 2) + self.assertEqual(svg.rules[0].value, b'