def test_conv(self): empty = fsnative(u"") in_ = fsnative(u"foo \u00c1 \u1234") out = fsnative(u"foo _ _") v = self.c.filter(empty, in_) self.failUnlessEqual(v, out) self.failUnless(is_fsnative(v))
def test_conv(self): empty = fsnative(u"") test = fsnative(u"\u00c1 test") out = fsnative(u"A test") v = self.c.filter(empty, test) self.failUnlessEqual(v, out) self.failUnless(is_fsnative(v))
def test_disctrack(self): pat = TagsFromPattern('<discnumber><tracknumber>. <title>') self.assertEquals(pat.match_path(fsnative(u'101. T1.ogg')), dict(discnumber='1', tracknumber='01', title='T1')) self.assertEquals(pat.match_path(fsnative(u'1318. T18.ogg')), dict(discnumber='13', tracknumber='18', title='T18')) self.assertEquals(pat.match_path(fsnative(u'24. T4.ogg')), dict(discnumber='2', tracknumber='4', title='T4'))
def test_fsn2uri(self): if os.name != "nt": uri = fsn2uri(fsnative(u"/öäü.txt")) self.assertEqual(uri, u"file:///%C3%B6%C3%A4%C3%BC.txt") else: uri = fsn2uri(fsnative(u"C:\\öäü.txt")) self.assertEqual(uri, "file:///C:/%C3%B6%C3%A4%C3%BC.txt") self.assertEqual(fsn2uri(u"C:\\SomeDir\xe4"), "file:///C:/SomeDir%C3%A4")
def test_uri2fsn(self): if os.name != "nt": path = uri2fsn("file:///home/piman/cr%21azy") self.assertTrue(is_fsnative(path)) self.assertEqual(path, fsnative(u"/home/piman/cr!azy")) else: path = uri2fsn("file:///C:/foo") self.assertTrue(is_fsnative(path)) self.assertEqual(path, fsnative(u"C:\\foo"))
def test_uri_to_path(self): if os.name != "nt": path = uri_to_path("file:///home/piman/cr%21azy") self.assertTrue(is_fsnative(path)) self.assertEqual(path, fsnative(u"/home/piman/cr!azy")) else: path = uri_to_path("file:///C:/foo") self.assertTrue(is_fsnative(path)) self.assertEqual(path, fsnative(u"C:\\foo"))
def test_roundtrip(self): if os.name == "nt": paths = [u"C:\\öäü.txt"] else: paths = [u"/öäü.txt", u"//foo/bar", u"///foo/bar"] for source in paths: path = uri2fsn(fsn2uri(fsnative(source))) self.assertTrue(is_fsnative(path)) self.assertEqual(path, fsnative(source))
def test_uri_from_path(self): if os.name != "nt": uri = uri_from_path(fsnative(u"/öäü.txt")) self.assertEqual(uri, u"file:///%C3%B6%C3%A4%C3%BC.txt") else: uri = uri_from_path(fsnative(u"C:\\öäü.txt")) self.assertEqual( uri, "file:///C:/%C3%B6%C3%A4%C3%BC.txt") self.assertEqual( uri_from_path(u"C:\\SomeDir\xe4"), "file:///C:/SomeDir%C3%A4")
def test_ends_with_dots_or_spaces(self): empty = fsnative(u"") v = self.c.filter(empty, fsnative(u"foo. . ")) self.failUnlessEqual(v, fsnative(u"foo. ._")) self.assertTrue(is_fsnative(v)) if os.name == "nt": self.failUnlessEqual(self.c.filter(empty, u"foo. \\bar ."), u"foo._\\bar _") else: self.failUnlessEqual(self.c.filter(empty, u"foo. /bar ."), "foo._/bar _")
def test_conv(self): empty = fsnative(u"") v = self.c.filter(empty, fsnative(u"foobar baz")) self.failUnlessEqual(v, fsnative(u"foobar baz")) self.failUnless(is_fsnative(v)) v = self.c.filter(empty, fsnative(u"Foobar.BAZ")) self.failUnlessEqual(v, fsnative(u"foobar.baz")) self.failUnless(is_fsnative(v))
def test_roundtrip(self): if os.name == "nt": paths = [u"C:\\öäü.txt"] else: paths = [u"/öäü.txt", u"//foo/bar", u"///foo/bar"] for source in paths: path = uri_to_path(uri_from_path(fsnative(source))) self.assertTrue(is_fsnative(path)) self.assertEqual(path, fsnative(source))
def init_test_environ(): """This needs to be called before any test can be run. Before exiting the process call exit_test_environ() to clean up any resources created. """ global _TEMP_DIR, _BUS_INFO # create a user dir in /tmp and set env vars _TEMP_DIR = tempfile.mkdtemp(prefix=fsnative(u"QL-TEST-")) # needed for dbus/dconf runtime_dir = tempfile.mkdtemp(prefix=fsnative(u"RUNTIME-"), dir=_TEMP_DIR) os.chmod(runtime_dir, 0o700) environ["XDG_RUNTIME_DIR"] = runtime_dir # force the old cache dir so that GStreamer can re-use the GstRegistry # cache file environ["XDG_CACHE_HOME"] = xdg_get_cache_home() # GStreamer will update the cache if the environment has changed # (in Gst.init()). Since it takes 0.5s here and doesn't add much, # disable it. If the registry cache is missing it will be created # despite this setting. environ["GST_REGISTRY_UPDATE"] = fsnative(u"no") # set HOME and remove all XDG vars that default to it if not set home_dir = tempfile.mkdtemp(prefix=fsnative(u"HOME-"), dir=_TEMP_DIR) environ["HOME"] = home_dir # set to new default environ.pop("XDG_DATA_HOME", None) _BUS_INFO = None if os.name != "nt" and "DBUS_SESSION_BUS_ADDRESS" in environ: try: out = subprocess.check_output(["dbus-launch"]) except (subprocess.CalledProcessError, OSError): pass else: if PY3: out = out.decode("ascii") _BUS_INFO = dict([l.split("=", 1) for l in out.splitlines()]) environ.update(_BUS_INFO) # Ideally nothing should touch the FS on import, but we do atm.. # Get rid of all modules so QUODLIBET_USERDIR gets used everywhere. for key in list(sys.modules.keys()): if key.startswith('quodlibet'): del(sys.modules[key]) import quodlibet quodlibet.init(no_translations=True, no_excepthook=True) quodlibet.app.name = "QL Tests"
def test_embedded_special_cover_words(self): """Tests that words incidentally containing embedded "special" words album keywords (e.g. cover, disc, back) don't trigger See Issue 818""" song = AudioFile({ "~filename": fsnative(u"tests/data/asong.ogg"), "album": "foobar", "title": "Ode to Baz", "artist": "Q-Man", }) files = [self.full_path(f) for f in ['back.jpg', 'discovery.jpg', "Pharell - frontin'.jpg", 'nickelback - Curb.jpg', 'foobar.jpg', 'folder.jpg', # Though this is debatable 'Q-Man - foobar.jpg', 'Q-man - foobar (cover).jpg']] for f in files: file(f, "w").close() self.files.append(f) cover = self._find_cover(song) if cover: actual = os.path.abspath(cover.name) self.failUnlessEqual( actual, f, "\"%s\" should trump \"%s\"" % (f, actual)) else: self.failUnless(f, self.full_path('back.jpg'))
def test_embedded_special_cover_words(self): """Tests that words incidentally containing embedded "special" words album keywords (e.g. cover, disc, back) don't trigger See Issue 818""" song = AudioFile({ "~filename": fsnative(os.path.join(self.dir, u"asong.ogg")), "album": "foobar", "title": "Ode to Baz", "artist": "Q-Man", }) data = [('back.jpg', False), ('discovery.jpg', False), ("Pharell - frontin'.jpg", False), ('nickelback - Curb.jpg', False), ('foobar.jpg', True), ('folder.jpg', True), # Though this order is debatable ('Q-Man - foobar.jpg', True), ('Q-man - foobar (cover).jpg', True)] for fn, should_find in data: f = self.add_file(fn) cover = self._find_cover(song) if cover: actual = os.path.abspath(cover.name) self.failUnlessEqual( actual, f, "\"%s\" should trump \"%s\"" % (f, actual)) else: self.failIf(should_find, msg="Couldn't find %s for %s" % (f, song("~filename")))
def test_rename_to_existing(self): quux.rename(quux("~basename")) if os.name != "nt": self.failUnlessRaises( ValueError, quux.rename, fsnative(u"/dev/null")) self.failUnlessRaises(ValueError, quux.rename, os.path.join(DATA_DIR, "silence-44-s.ogg"))
def test_multiple_people(self): song = AudioFile({ "~filename": fsnative(os.path.join(self.dir, u"asong.ogg")), "album": "foobar", "title": "Ode to Baz", "performer": "The Performer", "artist": "The Composer\nThe Conductor", "composer": "The Composer", }) for fn in [ "foobar.jpg", "The Performer - foobar.jpg", "The Composer: The Performer - foobar.jpg", "The Composer: The Conductor, The Performer - foobar.jpg" ]: f = self.add_file(fn) cover = self._find_cover(song) self.failUnless(cover) actual = os.path.abspath(cover.name) self.failUnlessEqual(actual, f, "\"%s\" should trump \"%s\"" % (f, actual))
def test_main(self): self.assertEqual(decode_value("~#foo", 0.25), u"0.25") self.assertEqual(decode_value("~#foo", 4), u"4") self.assertEqual(decode_value("~#foo", "bar"), u"bar") self.assertTrue(isinstance(decode_value("~#foo", "bar"), unicode)) path = fsnative(u"/foobar") self.assertEqual(decode_value("~filename", path), fsdecode(path))
def _post(self, value, song, keep_extension=True): if value: assert isinstance(value, unicode) value = fsnative(value) if keep_extension: fn = song.get("~filename", ".") ext = fn[fn.rfind("."):].lower() val_ext = value[-len(ext):].lower() if not ext == val_ext: value += ext.lower() if os.name == "nt": assert isinstance(value, unicode) value = strip_win32_incompat_from_path(value) value = expanduser(value) # Limit each path section to 255 (bytes on linux, chars on win). # http://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits path, ext = os.path.splitext(value) path = path.split(sep) limit = [255] * len(path) limit[-1] -= len(ext) elip = lambda (p, l): (len(p) > l and p[:l - 2] + "..") or p path = sep.join(map(elip, zip(path, limit))) value = path + ext if sep in value and not os.path.isabs(value): raise ValueError("Pattern is not rooted") return value
def test_masked_handling(self): if os.name == "nt": # FIXME: masking isn't properly implemented on Windows return # playlists can contain songs and paths for masked handling.. lib = FileLibrary("foobar") pl = Playlist(self.temp, "playlist", lib) song = Fakesong({"date": "2038", "~filename": fsnative(u"/fake")}) song.sanitize() lib.add([song]) # mask and update lib.mask("/") pl.append(song) pl.remove_songs([song]) self.failUnless("/fake" in pl) pl.extend(self.TWO_SONGS) # check if collections can handle the mix self.failUnlessEqual(pl("date"), "2038") # unmask and update lib.unmask("/") pl.add_songs(["/fake"], lib) self.failUnless(song in pl) pl.delete() lib.destroy()
def setUp(self): config.RATINGS = config.HardCodedRatingsPrefs() self.failUnlessEqual(config.RATINGS.number, NUM_RATINGS) self.library = SongLibrary() self.library.librarian = SongLibrarian() self.af = AudioFile({"~filename": fsnative(u"/foo"), "~#rating": 1.0}) self.af.sanitize() self.rmi = RatingsMenuItem([self.af], self.library)
def setUp(self): config.init() player = NullPlayer() song = AudioFile() song.bookmarks = [(10, "bla")] song.sanitize(fsnative(u"/")) player.song = song self.player = player
def test_no_rating(self): af = AudioFile({"~filename": fsnative(u"/foobar"), 'artist': 'foo'}) rmi = RatingsMenuItem([af], self.library) children = [ mi for mi in rmi.get_submenu().get_children() if isinstance(mi, Gtk.CheckMenuItem) ] self.failIf(any([c.get_active() for c in children]))
def lyric_filename(self): """Returns the (potential) lyrics filename for this file""" filename = self.comma("title").replace(u"/", u"")[:128] + u".lyric" sub_dir = (self.comma("lyricist") or self.comma("artist")).replace(u"/", u"")[:128] if os.name == "nt": # this was added at a later point. only use escape_filename here # to keep the linux case the same as before filename = escape_filename(filename) sub_dir = escape_filename(sub_dir) else: filename = fsnative(filename) sub_dir = fsnative(sub_dir) path = os.path.join(expanduser(fsnative(u"~/.lyrics")), sub_dir, filename) return path
def test_write(self): with self.wrap("playlist") as pl: pl.extend(NUMERIC_SONGS) pl.extend([fsnative(u"xf0xf0")]) pl.write() with open(pl.filename, "rb") as h: self.assertEqual(len(h.read().splitlines()), len(NUMERIC_SONGS) + 1)
def test_msic(self): with realized(self.b): self.b.activate() self.b.statusbar(1000) self.b.statusbar(1) song = AudioFile({"~filename": fsnative(u"/fake")}) song.sanitize() self.b.scroll(song)
def sanitize(self, filename=None): """Fill in metadata defaults. Find ~mountpoint, ~#mtime, ~#filesize and ~#added. Check for null bytes in tags. Does not raise. """ # Replace nulls with newlines, trimming zero-length segments for key, val in self.items(): if isinstance(val, string_types) and '\0' in val: self[key] = '\n'.join(filter(lambda s: s, val.split('\0'))) # Remove unnecessary defaults if key in INTERN_NUM_DEFAULT and val == 0: del self[key] if filename: self["~filename"] = filename elif "~filename" not in self: raise ValueError("Unknown filename!") assert is_fsnative(self["~filename"]) if self.is_file: self["~filename"] = normalize_path( self["~filename"], canonicalise=True) # Find mount point (terminating at "/" if necessary) head = self["~filename"] while "~mountpoint" not in self: head, tail = os.path.split(head) # Prevent infinite loop without a fully-qualified filename # (the unit tests use these). head = head or "/" if os.path.ismount(head): self["~mountpoint"] = head else: self["~mountpoint"] = fsnative(u"/") # Fill in necessary values. self.setdefault("~#added", int(time.time())) # For efficiency, do a single stat here. See Issue 504 try: stat = os.stat(self['~filename']) self["~#mtime"] = stat.st_mtime self["~#filesize"] = stat.st_size # Issue 342. This is a horrible approximation (due to headers) but # on FLACs, the most common case, this should be close enough if "~#bitrate" not in self: try: # kbps = bytes * 8 / seconds / 1000 self["~#bitrate"] = int(stat.st_size / (self["~#length"] * (1000 / 8))) except (KeyError, ZeroDivisionError): pass except OSError: self["~#mtime"] = 0
def test_lyric_filename(self): song = AudioFile() song["~filename"] = fsnative(u"filename") self.assertTrue(is_fsnative(song.lyric_filename)) song["title"] = u"Title" song["artist"] = u"Artist" self.assertTrue(is_fsnative(song.lyric_filename)) song["lyricist"] = u"Lyricist" self.assertTrue(is_fsnative(song.lyric_filename))
def test_rename(self): old_fn = quux("~basename") new_fn = fsnative(u"anothersong.mp3") dir = DATA_DIR self.failUnless(quux.exists()) quux.rename(new_fn) self.failIf(os.path.exists(dir + old_fn), "%s already exists" % (dir + old_fn)) self.failUnless(quux.exists()) quux.rename(old_fn) self.failIf(os.path.exists(dir + new_fn)) self.failUnless(quux.exists()) # move out of parent dir and back quux.rename(fsnative(u"/tmp/more_test_data")) self.failIf(os.path.exists(dir + old_fn)) self.failUnless(quux.exists()) quux.rename(dir + old_fn) self.failUnless(quux.exists())
def setUp(self): config.init() self.library = SongLibrary() backend = quodlibet.player.init_backend("nullbe") self.device = backend.init(self.library) self.songs = [AudioFile({"title": x}) for x in ["song1", "song2", "song3"]] for song in self.songs: song.sanitize(fsnative(unicode(song["title"])))
def _print_playing(app, fstring="<artist~album~tracknumber~title>"): from quodlibet.formats import AudioFile from quodlibet.pattern import Pattern song = app.player.song if song is None: song = AudioFile({"~filename": fsnative(u"/")}) song.sanitize() return Pattern(fstring).format(song) + "\n"
def test_sanitize(self): q = AudioFile(quux) b = AudioFile(bar_1_1) q.sanitize() b.pop("~filename") self.failUnlessRaises(ValueError, b.sanitize) n = AudioFile({"artist": u"foo\0bar", "title": u"baz\0", "~filename": fsnative(u"whatever")}) n.sanitize() self.failUnlessEqual(n["artist"], "foo\nbar") self.failUnlessEqual(n["title"], "baz")
def test_menuitem(self): library = SongLibrary() library.librarian = SongLibrarian() a = AudioFile({"~filename": fsnative(u"/foo")}) a.sanitize() x = RatingsMenuItem([a], library) x.set_rating(0, [a], library) x.destroy() library.destroy() library.librarian.destroy()
def init_test_environ(): """This needs to be called before any test can be run. Before exiting the process call exit_test_environ() to clean up any resources created. """ global _TEMP_DIR, _BUS_INFO # create a user dir in /tmp and set env vars _TEMP_DIR = tempfile.mkdtemp(prefix=fsnative(u"QL-TEST-")) # needed for dbus/dconf runtime_dir = tempfile.mkdtemp(prefix=fsnative(u"RUNTIME-"), dir=_TEMP_DIR) os.chmod(runtime_dir, 0o700) os.environ["XDG_RUNTIME_DIR"] = runtime_dir # set HOME and remove all XDG vars that default to it if not set home_dir = tempfile.mkdtemp(prefix=fsnative(u"HOME-"), dir=_TEMP_DIR) os.environ["HOME"] = home_dir os.environ.pop("XDG_DATA_HOME", None) os.environ.pop("XDG_CACHE_HOME", None) _BUS_INFO = None if os.name != "nt" and "DBUS_SESSION_BUS_ADDRESS" in os.environ: try: out = subprocess.check_output(["dbus-launch"]) except (subprocess.CalledProcessError, OSError): pass else: if PY3: out = out.decode("ascii") _BUS_INFO = dict([l.split("=", 1) for l in out.splitlines()]) os.environ.update(_BUS_INFO) # Ideally nothing should touch the FS on import, but we do atm.. # Get rid of all modules so QUODLIBET_USERDIR gets used everywhere. for key in list(sys.modules.keys()): if key.startswith('quodlibet'): del(sys.modules[key]) import quodlibet quodlibet.init(no_translations=True)
def main(argv): import quodlibet from quodlibet.qltk import add_signal_watch, icons add_signal_watch(app.quit) opts = util.OptionParser("Ex Falso", const.VERSION, _("an audio tag editor"), "[%s]" % _("directory")) # FIXME: support unicode on Windows, sys.argv isn't good enough argv.append(os.path.abspath(fsnative(u"."))) opts, args = opts.parse(argv[1:]) args[0] = os.path.realpath(args[0]) config.init(os.path.join(quodlibet.get_user_dir(), "config")) app.name = "Ex Falso" app.id = "exfalso" quodlibet.init(icon=icons.EXFALSO, name=app.name, proc_title=app.id) import quodlibet.library import quodlibet.player app.library = quodlibet.library.init() app.player = quodlibet.player.init_player("nullbe", app.librarian) from quodlibet.qltk.songlist import PlaylistModel app.player.setup(PlaylistModel(), None, 0) pm = quodlibet.init_plugins() pm.rescan() from quodlibet.qltk.exfalsowindow import ExFalsoWindow dir_ = args[0] if os.name == "nt": dir_ = fsdecode(dir_) app.window = ExFalsoWindow(app.library, dir_) app.window.init_plugins() from quodlibet.util.cover import CoverManager app.cover_manager = CoverManager() app.cover_manager.init_plugins() from quodlibet.qltk import session session.init("exfalso") quodlibet.enable_periodic_save(save_library=False) quodlibet.main(app.window) quodlibet.finish_first_session(app.id) config.save() print_d("Finished shutdown.")
def unit(*args, **kwargs): global _TEMP_DIR # create a user dir in /tmp and set env vars _TEMP_DIR = tempfile.mkdtemp(prefix=fsnative(u"QL-TEST-")) # needed for dbus/dconf runtime_dir = tempfile.mkdtemp(prefix=fsnative(u"RUNTIME-"), dir=_TEMP_DIR) os.chmod(runtime_dir, 0700) os.environ["XDG_RUNTIME_DIR"] = runtime_dir # set HOME and remove all XDG vars that default to it if not set home_dir = tempfile.mkdtemp(prefix=fsnative(u"HOME-"), dir=_TEMP_DIR) os.environ["HOME"] = home_dir os.environ.pop("XDG_DATA_HOME", None) os.environ.pop("XDG_CACHE_HOME", None) bus = None if os.name != "nt" and "DBUS_SESSION_BUS_ADDRESS" in os.environ: try: out = subprocess.check_output(["dbus-launch"]) except (subprocess.CalledProcessError, OSError): pass else: bus = dict([l.split("=", 1) for l in out.splitlines()]) os.environ.update(bus) try: return _run_tests(*args, **kwargs) finally: try: shutil.rmtree(_TEMP_DIR) except EnvironmentError: pass if bus: try: subprocess.check_call( ["kill", "-9", bus["DBUS_SESSION_BUS_PID"]]) except (subprocess.CalledProcessError, OSError): pass