1
from tests import TestCase, add
5
from quodlibet import config
7
from quodlibet.formats._audio import AudioFile
11
"discnumber": "1/2", "tracknumber": "1/3",
12
"artist": "Foo", "album": "Bar" })
14
"title": "Perhaps another",
15
"discnumber": "1", "tracknumber": "2/3",
16
"artist": "Lali-ho!", "album": "Bar",
17
"date": "2004-12-12"})
19
"~filename": "does not/exist",
20
"title": "more songs",
21
"discnumber": "2/2", "tracknumber": "1",
22
"artist": "Foo\nI have two artists", "album": "Bar",
23
"lyricist": "Foo", "composer": "Foo", "performer": "I have two artists"})
26
"~filename": "tests/data/asong.ogg",
30
class TAudioFile(TestCase):
32
file(quux["~filename"], "w")
35
l = [quux, bar_1_2, bar_2_1, bar_1_1]
37
self.assertEqual(l, [bar_1_1, bar_1_2, bar_2_1, quux])
38
self.assertEqual(quux, quux)
39
self.assertEqual(bar_1_1, bar_1_1)
40
self.assertNotEqual(bar_2_1, bar_1_2)
42
def test_realkeys(self):
43
self.failIf("artist" in quux.realkeys())
44
self.failIf("~filename" in quux.realkeys())
45
self.failUnless("album" in quux.realkeys())
47
def test_trackdisc(self):
48
self.failUnlessEqual(bar_1_1("~#track"), 1)
49
self.failUnlessEqual(bar_1_1("~#disc"), 1)
50
self.failUnlessEqual(bar_1_1("~#tracks"), 3)
51
self.failUnlessEqual(bar_1_1("~#discs"), 2)
52
self.failIf(bar_1_2("~#discs"))
53
self.failIf(bar_2_1("~#tracks"))
56
# real keys should lookup the same
57
for key in bar_1_1.realkeys():
58
self.failUnlessEqual(bar_1_1[key], bar_1_1(key))
60
# fake/generated key checks
61
self.failIf(quux("not a key"))
62
self.failUnlessEqual(quux("not a key", "foo"), "foo")
63
self.failUnlessEqual(quux("artist"), "")
64
self.failUnlessEqual(quux("~basename"), "asong.ogg")
65
self.failUnlessEqual(quux("~dirname"), "tests/data")
66
self.failUnlessEqual(quux("title"), "asong.ogg [Unknown]")
68
self.failUnlessEqual(bar_1_1("~#disc"), 1)
69
self.failUnlessEqual(bar_1_2("~#disc"), 1)
70
self.failUnlessEqual(bar_2_1("~#disc"), 2)
71
self.failUnlessEqual(bar_1_1("~#track"), 1)
72
self.failUnlessEqual(bar_1_2("~#track"), 2)
73
self.failUnlessEqual(bar_2_1("~#track"), 1)
76
self.failUnlessEqual(bar_1_2("~year"), "2004")
77
self.failUnlessEqual(bar_1_2("~#year"), 2004)
78
self.failUnlessEqual(bar_1_1("~#year", 1999), 1999)
80
def test_call_people(self):
81
self.failUnlessEqual(quux("~people"), "")
82
self.failUnlessEqual(bar_1_1("~people"), "Foo")
83
self.failUnlessEqual(bar_1_2("~people"), "Lali-ho!")
84
self.failUnlessEqual(bar_2_1("~people"), "Foo\nI have two artists")
86
def test_call_multiple(self):
87
for song in [quux, bar_1_1, bar_2_1]:
88
self.failUnlessEqual(song("~~people"), song("~people"))
89
self.failUnlessEqual(song("~title~people"), song("title"))
90
self.failUnlessEqual(song("~title~~people"), song("~title~artist"))
93
for key in bar_1_1.realkeys():
94
self.failUnlessEqual(bar_1_1.list(key), [bar_1_1(key)])
96
self.failUnlessEqual(quux.list("artist"), [])
97
self.failUnlessEqual(quux.list("title"), [quux("title")])
98
self.failUnlessEqual(quux.list("not a key"), [])
100
self.failUnlessEqual(len(bar_2_1.list("artist")), 2)
101
self.failUnlessEqual(bar_2_1.list("artist"),
102
bar_2_1["artist"].split("\n"))
104
def test_comma(self):
105
for key in bar_1_1.realkeys():
106
self.failUnlessEqual(bar_1_1.comma(key), bar_1_1(key))
107
self.failUnless(", " in bar_2_1.comma("artist"))
109
def test_exist(self):
110
self.failIf(bar_2_1.exists())
111
self.failUnless(quux.exists())
113
def test_valid(self):
114
self.failIf(bar_2_1.valid())
117
self.failIf(quux.valid())
118
quux["~#mtime"] = os.path.getmtime(quux["~filename"])
119
self.failUnless(quux.valid())
120
os.utime(quux["~filename"], (quux["~#mtime"], quux["~#mtime"] - 1))
121
self.failIf(quux.valid())
122
quux["~#mtime"] = os.path.getmtime(quux["~filename"])
123
self.failUnless(quux.valid())
125
os.utime(quux["~filename"], (quux["~#mtime"], quux["~#mtime"] - 1))
127
self.failUnless(quux.valid())
129
def test_can_change(self):
130
self.failIf(quux.can_change("~foobar"))
131
self.failIf(quux.can_change("=foobar"))
132
self.failIf(quux.can_change("foo=bar"))
133
self.failIf(quux.can_change(""))
135
self.failUnless(quux.can_change("foo bar"))
136
os.chmod(quux["~filename"], 0444)
137
self.failIf(quux.can_change("foo bar"))
138
os.chmod(quux["~filename"], 0644)
139
self.failUnless(quux.can_change("foo bar"))
141
def test_rename(self):
142
old_fn = quux("~basename")
143
new_fn = "anothersong.mp3"
144
dir = os.getcwd() + "/tests/data/"
145
self.failUnless(quux.exists())
147
self.failIf(os.path.exists(dir + old_fn))
148
self.failUnless(quux.exists())
150
self.failIf(os.path.exists(dir + new_fn))
151
self.failUnless(quux.exists())
153
# move out of parent dir and back
154
quux.rename("/tmp/more_test_data")
155
self.failIf(os.path.exists(dir + old_fn))
156
self.failUnless(quux.exists())
157
quux.rename(dir + old_fn)
158
self.failUnless(quux.exists())
160
def test_rename_to_existing(self):
161
quux.rename(quux("~basename"))
162
self.failUnlessRaises(ValueError, quux.rename, "/dev/null")
163
self.failUnlessRaises(ValueError, quux.rename, "silence-44-s.ogg")
165
def test_website(self):
167
song["comment"] = "www.foo"
168
song["contact"] = "eh@foo.org"
169
self.failUnlessEqual(song.website(), "www.foo")
170
song["contact"] = "https://www.foo.org"
171
self.failUnlessEqual(song.website(), "https://www.foo.org")
172
song["website"] = "foo\nhttps://another.com"
173
self.failUnlessEqual(song.website(), "foo")
175
song = AudioFile({"artist": "Artist", "album": "Album"})
176
for value in song.values(): self.failUnless(value in song.website())
177
song["labelid"] = "QL-12345"
178
self.failIf(song["artist"] in song.website())
179
self.failUnless(song["labelid"] in song.website())
181
def test_sanitize(self):
183
b = AudioFile(bar_1_1)
185
self.failUnlessRaises(ValueError, b.sanitize)
187
def test_performers(self):
188
q = AudioFile([("performer:vocals", "A"), ("performer:guitar", "B"),
190
self.failUnless("A (vocals)" in q.list("~performers"))
191
self.failUnless("B (guitar)" in q.list("~performers"))
192
self.failUnless("C" in q.list("~performers"))
193
self.failUnless("A (vocals)" in q.list("~people"))
194
self.failUnless("B (guitar)" in q.list("~people"))
195
self.failUnlessEqual(len(q.list("~performers")), 3)
197
def test_to_dump(self):
198
dump = bar_1_1.to_dump()
199
self.failUnlessEqual(dump.count("\n"), len(bar_1_1) + 1)
200
for key, value in bar_1_1.items():
201
self.failUnless(key in dump)
202
self.failUnless(value in dump)
204
def test_to_dump_long(self):
205
b = AudioFile(bar_1_1); b["~#length"] = 200000000000L
207
self.failUnlessEqual(dump.count("\n"), len(b) + 1)
211
self.failIf("foo" in song)
212
song.add("foo", "bar")
213
self.failUnlessEqual(song["foo"], "bar")
214
song.add("foo", "another")
215
self.failUnlessEqual(song.list("foo"), ["bar", "another"])
217
def test_remove(self):
219
song.add("foo", "bar")
220
song.add("foo", "another")
221
song.add("foo", "one more")
222
song.remove("foo", "another")
223
self.failUnlessEqual(song.list("foo"), ["bar", "one more"])
224
song.remove("foo", "bar")
225
self.failUnlessEqual(song.list("foo"), ["one more"])
226
song.remove("foo", "one more")
227
self.failIf("foo" in song)
229
song.add("foo", "bar")
230
song.add("foo", "another")
231
song.add("foo", "one more")
232
song.remove("foo", "not in list")
233
self.failIf("foo" in song)
235
def test_change(self):
237
song.add("foo", "bar")
238
song.add("foo", "another")
239
song.change("foo", "bar", "one more")
240
self.failUnlessEqual(song.list("foo"), ["one more", "another"])
241
song.change("foo", "does not exist", "finally")
242
self.failUnlessEqual(song["foo"], "finally")
243
song.change("foo", "finally", "we're done")
244
self.failUnlessEqual(song["foo"], "we're done")
246
def test_bookmarks_none(self):
247
self.failUnlessEqual([], AudioFile().bookmarks)
249
def test_bookmarks_simple(self):
250
af = AudioFile({"~bookmark": "1:20 Mark 1"})
251
self.failUnlessEqual([(80, "Mark 1")], af.bookmarks)
253
def test_bookmarks_two(self):
254
af = AudioFile({"~bookmark": "1:40 Mark 2\n1:20 Mark 1"})
255
self.failUnlessEqual([(80, "Mark 1"), (100, "Mark 2")], af.bookmarks)
257
def test_bookmark_invalid(self):
258
af = AudioFile({"~bookmark": ("Not Valid\n1:40 Mark 2\n"
259
"-20 Not Valid 2\n1:20 Mark 1")})
260
self.failUnlessEqual(
261
[(80, "Mark 1"), (100, "Mark 2"), (-1, "Not Valid"),
262
(-1, "-20 Not Valid 2")], af.bookmarks)
264
def test_set_bookmarks_none(self):
265
af = AudioFile({"bookmark": "foo"})
267
self.failUnlessEqual([], AudioFile().bookmarks)
268
self.failIf("~bookmark" in af)
270
def test_set_bookmarks_simple(self):
272
af.bookmarks = [(120, "A mark"), (140, "Mark twain")]
273
self.failUnlessEqual(af["~bookmark"], "2:00 A mark\n2:20 Mark twain")
275
def test_set_bookmarks_invalid_value(self):
276
self.failUnlessRaises(
277
ValueError, setattr, AudioFile(), 'bookmarks', "huh?")
278
def test_set_bookmarks_invalid_time(self):
279
self.failUnlessRaises(
280
TypeError, setattr, AudioFile(), 'bookmarks', [("notint", "!")])
281
def test_set_bookmarks_unrealistic_time(self):
282
self.failUnlessRaises(
283
ValueError, setattr, AudioFile(), 'bookmarks', [(-1, "!")])
285
def test_album_key(self):
286
self.failUnlessEqual(AudioFile().album_key, ("", ""))
288
album = AudioFile(album="foo")
289
self.failUnlessEqual(album.album_key, ("foo", ""))
291
labelid = AudioFile(labelid="foo")
292
self.failUnlessEqual(labelid.album_key, ("", "foo"))
294
mbid = AudioFile(musicbrainz_albumid="foo")
295
self.failUnlessEqual(mbid.album_key, ("", "foo"))
297
title_id = AudioFile(album="foo", labelid="bar")
298
self.failUnlessEqual(title_id.album_key, ("foo", "bar"))
300
all = AudioFile(album="foo", labelid="bar", musicbrainz_albumid="quux")
301
self.failUnlessEqual(all.album_key, ("foo", "bar"))
304
os.unlink(quux["~filename"])
307
class Treplay_gain(TestCase):
309
self.song = AudioFile({"replaygain_album_gain": "-1.00 dB",
310
"replaygain_album_peak": "1.1",
311
"replaygain_track_gain": "+1.0 dB",
312
"replaygain_track_peak": "0.9"})
314
def test_nogain(self):
315
self.failUnlessEqual(self.song.replay_gain(["none", "track"]), 1)
317
def test_trackgain(self):
318
self.failUnless(self.song.replay_gain(["track"]) > 1)
320
def test_albumgain(self):
321
self.failUnless(self.song.replay_gain(["album"]) < 1)
323
def test_invalid(self):
324
self.song["replaygain_album_gain"] = "fdsodgbdf"
325
self.failUnlessEqual(self.song.replay_gain(["album"]), 1)
327
def test_track_fallback(self):
328
radio_rg = self.song.replay_gain(["track"])
329
del(self.song["replaygain_album_gain"])
330
del(self.song["replaygain_album_peak"])
331
# verify defaulting to track when album is present
332
self.failUnlessAlmostEqual(
333
self.song.replay_gain(["album", "track"]), radio_rg)
336
# Special test case for find_cover since it has to create/remove
338
class Tfind_cover(TestCase):
340
self.dir = os.path.realpath(quux("~dirname"))
341
self.files = [os.path.join(self.dir, "12345.jpg"),
342
os.path.join(self.dir, "nothing.jpg")
344
for f in self.files: file(f, "w").close()
346
def test_dir_not_exist(self):
347
self.failIf(bar_2_1.find_cover())
349
def test_nothing(self):
350
self.failIf(quux.find_cover())
352
def test_labelid(self):
353
quux["labelid"] = "12345"
354
self.failUnlessEqual(os.path.abspath(quux.find_cover().name),
355
os.path.join(self.dir, "12345.jpg"))
358
def test_regular(self):
359
files = [os.path.join(self.dir, f) for f in
360
["cover.png", "frontcover.jpg", "frontfoldercover.gif",
361
"jacketcoverfrontfolder.jpeg"]]
365
self.failUnlessEqual(os.path.abspath(quux.find_cover().name), f)
366
self.test_labelid() # labelid must work with other files present
369
map(os.unlink, self.files)