1# This program is free software; you can redistribute it and/or modify 2# it under the terms of the GNU General Public License as published by 3# the Free Software Foundation; either version 2 of the License, or 4# (at your option) any later version. 5 6import os 7import importlib 8import sys 9import shutil 10 11from quodlibet.util.modulescanner import ModuleScanner 12from quodlibet.util.importhelper import get_importables, load_dir_modules 13 14from tests import TestCase, mkdtemp 15 16 17class TModuleScanner(TestCase): 18 19 def setUp(self): 20 self.d = mkdtemp("ql-mod") 21 spec = importlib.machinery.ModuleSpec("qlfake", None) 22 sys.modules["qlfake"] = importlib.util.module_from_spec(spec) 23 24 def tearDown(self): 25 del sys.modules["qlfake"] 26 shutil.rmtree(self.d) 27 28 def _create_mod(self, name, package=None): 29 if package is not None: 30 base = os.path.join(self.d, package) 31 else: 32 base = self.d 33 return open(os.path.join(base, name), "wb") 34 35 def _create_pkg(self, name): 36 base = os.path.join(self.d, name) 37 os.mkdir(base) 38 return open(os.path.join(base, "__init__.py"), "wb") 39 40 def test_importables(self): 41 self.failUnlessEqual(list(get_importables(self.d)), []) 42 h = self._create_mod("foo.py") 43 h.close() 44 self.failUnlessEqual(list(get_importables(self.d))[0], 45 ("foo", h.name, [h.name])) 46 47 def test_importables_ignore_init(self): 48 h = self._create_mod("foo7.py") 49 h.close() 50 self._create_mod("__init__.py").close() 51 self.failUnlessEqual(list(get_importables(self.d))[0], 52 ("foo7", h.name, [h.name])) 53 54 def test_importables_package(self): 55 h = self._create_pkg("foobar") 56 self.failUnlessEqual(list(get_importables(self.d))[0], 57 ("foobar", os.path.dirname(h.name), [h.name])) 58 h.close() 59 60 def test_importables_package_deps(self): 61 h = self._create_pkg("foobar3") 62 h2 = self._create_mod("sub.py", "foobar3") 63 name, path, deps = list(get_importables(self.d))[0] 64 self.failUnlessEqual(name, "foobar3") 65 self.failUnlessEqual(path, os.path.dirname(h.name)) 66 self.failUnlessEqual(set(deps), {h.name, h2.name}) 67 h2.close() 68 h.close() 69 70 def test_load_dir_modules(self): 71 h = self._create_mod("x.py") 72 h.write(b"test=42\n") 73 h.close() 74 mods = load_dir_modules(self.d, "qlfake") 75 self.failUnlessEqual(len(mods), 1) 76 self.failUnlessEqual(mods[0].test, 42) 77 78 def test_load_dir_modules_packages(self): 79 h = self._create_pkg("somepkg2") 80 h2 = self._create_mod("sub.py", "somepkg2") 81 h2.write(b"test=456\n") 82 h2.close() 83 h.write(b"from .sub import *\nmain=654\n") 84 h.close() 85 mods = load_dir_modules(self.d, "qlfake") 86 self.failUnlessEqual(len(mods), 1) 87 self.failUnlessEqual(mods[0].test, 456) 88 89 def test_scanner_add(self): 90 self._create_mod("q1.py").close() 91 self._create_mod("q2.py").close() 92 s = ModuleScanner([self.d]) 93 self.failIf(s.modules) 94 removed, added = s.rescan() 95 self.failIf(removed) 96 self.failUnlessEqual(set(added), {"q1", "q2"}) 97 self.failUnlessEqual(len(s.modules), 2) 98 self.failUnlessEqual(len(s.failures), 0) 99 100 def test_unimportable_package(self): 101 self._create_pkg("_foobar").close() 102 s = ModuleScanner([self.d]) 103 self.failIf(s.modules) 104 removed, added = s.rescan() 105 self.failIf(added) 106 self.failIf(removed) 107 108 def test_scanner_remove(self): 109 h = self._create_mod("q3.py") 110 h.close() 111 s = ModuleScanner([self.d]) 112 s.rescan() 113 os.remove(h.name) 114 try: 115 os.remove(h.name + "c") 116 except OSError: 117 pass 118 removed, added = s.rescan() 119 self.failIf(added) 120 self.failUnlessEqual(removed, ["q3"]) 121 self.failUnlessEqual(len(s.modules), 0) 122 self.failUnlessEqual(len(s.failures), 0) 123 124 def test_scanner_error(self): 125 h = self._create_mod("q4.py") 126 h.write(b"1syntaxerror\n") 127 h.close() 128 s = ModuleScanner([self.d]) 129 removed, added = s.rescan() 130 self.failIf(added) 131 self.failIf(removed) 132 self.failUnlessEqual(len(s.failures), 1) 133 self.failUnless("q4" in s.failures) 134 135 def test_scanner_add_package(self): 136 h = self._create_pkg("somepkg") 137 h2 = self._create_mod("sub.py", "somepkg") 138 h2.write(b"test=123\n") 139 h2.close() 140 h.write(b"from .sub import *\nmain=321\n") 141 h.close() 142 s = ModuleScanner([self.d]) 143 removed, added = s.rescan() 144 self.failUnlessEqual(added, ["somepkg"]) 145 self.failUnlessEqual(s.modules["somepkg"].module.main, 321) 146 self.failUnlessEqual(s.modules["somepkg"].module.test, 123) 147