1# Copyright 2013 Christoph Reiter
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7
8import os
9from io import BytesIO
10
11from mutagen import asf
12
13from tests import TestCase, get_data_path
14from quodlibet.formats.wma import WMAFile, unpack_image, pack_image
15from quodlibet.formats._image import APICType, EmbeddedImage
16
17from .helper import get_temp_copy
18
19
20class TWMAFile(TestCase):
21
22    def setUp(self):
23        self.f = get_temp_copy(get_data_path('test.wma'))
24        self.song = WMAFile(self.f)
25
26        self.f2 = get_temp_copy(get_data_path('test-2.wma'))
27        self.song2 = WMAFile(self.f2)
28
29        self.f3 = get_temp_copy(get_data_path('test.asf'))
30        self.song3 = WMAFile(self.f3)
31
32    def tearDown(self):
33        os.unlink(self.f)
34        os.unlink(self.f2)
35        os.unlink(self.f3)
36
37    def test_basic(self):
38        self.song["title"] = u"SomeTestValue"
39        self.song.write()
40        self.song.reload()
41        self.assertEqual(self.song("title"), u"SomeTestValue")
42
43    def test_multi(self):
44        self.song["genre"] = u"Rock\nPop"
45        self.song.write()
46        self.song.reload()
47        # XXX: mutagen doesn't preserve order.. fix it!
48        self.assertEqual(set(self.song.list("genre")), {u"Rock", u"Pop"})
49
50    def test_length(self):
51        self.assertAlmostEqual(self.song("~#length"), 3.7120, 3)
52        self.assertAlmostEqual(self.song2("~#length"), 3.684, 3)
53        self.assertAlmostEqual(self.song3("~#length"), 11.38, 2)
54
55    def test_channels(self):
56        assert self.song("~#channels") == 2
57        assert self.song2("~#channels") == 2
58        assert self.song3("~#channels") == 1
59
60    def test_bitrate(self):
61        self.assertEqual(self.song("~#bitrate"), 64)
62        self.assertEqual(self.song2("~#bitrate"), 38)
63        self.assertEqual(self.song3("~#bitrate"), 5)
64
65    def test_sample_rate(self):
66        assert self.song("~#samplerate") == 48000
67        assert self.song2("~#samplerate") == 44100
68        assert self.song3("~#samplerate") == 8000
69
70    def test_write(self):
71        self.song.write()
72        self.song2.write()
73        self.song3.write()
74
75    def test_can_change(self):
76        self.assertTrue(self.song.can_change("title"))
77        self.assertFalse(self.song.can_change("foobar"))
78        self.assertTrue("albumartist" in self.song.can_change())
79
80    def test_format(self):
81        self.assertEqual(self.song("~format"), "ASF")
82        self.assertEqual(self.song2("~format"), "ASF")
83        self.assertEqual(self.song3("~format"), "ASF")
84
85    def test_codec(self):
86        self.assertEqual(self.song("~codec"),
87                         u"Windows Media Audio 9 Standard")
88        self.assertEqual(self.song2("~codec"),
89                         u"Windows Media Audio 9 Professional")
90        self.assertEqual(self.song3("~codec"),
91                         u"Intel G.723")
92
93    def test_encoding(self):
94        self.assertEqual(
95            self.song("~encoding"),
96            u"Windows Media Audio 9.1\n64 kbps, 48 kHz, stereo 2-pass CBR")
97        self.assertEqual(
98            self.song2("~encoding"),
99            (u"Windows Media Audio 9.1 Professional\n192 kbps, 44 kHz, "
100             "2 channel 24 bit 2-pass VBR"))
101        self.assertEqual(self.song3("~encoding"),
102                         u"Microsoft G.723.1\n8 kHz Mono, 5333 Bit/s")
103
104    def test_mb_release_track_id(self):
105        tag = asf.ASF(self.f)
106        tag["MusicBrainz/Release Track Id"] = [u"foo"]
107        tag.save()
108        song = WMAFile(self.f)
109        self.assertEqual(song("musicbrainz_releasetrackid"), u"foo")
110        song["musicbrainz_releasetrackid"] = u"bla"
111        song.write()
112        tag = asf.ASF(self.f)
113        self.assertEqual(tag["MusicBrainz/Release Track Id"], [u"bla"])
114
115    def test_invalid(self):
116        path = get_data_path('empty.xm')
117        self.assertTrue(os.path.exists(path))
118        self.assertRaises(Exception, WMAFile, path)
119
120    def test_get_images(self):
121        tag = asf.ASF(self.f2)
122        tag["WM/Picture"] = [tag["WM/Picture"][0], tag["WM/Picture"][0]]
123        tag.save()
124        self.song2.reload()
125
126        images = self.song2.get_images()
127        self.assertTrue(images and len(images) == 2)
128
129    def test_get_image(self):
130        self.assertFalse(self.song.get_primary_image())
131
132        image = self.song2.get_primary_image()
133        self.assertTrue(image)
134        self.assertEqual(image.mime_type, "image/jpeg")
135        self.assertTrue(image.read())
136
137    def test_get_image_invalid_data(self):
138        tag = asf.ASF(self.f)
139        tag["WM/Picture"] = [asf.ASFValue(b"nope", asf.BYTEARRAY)]
140        tag.save()
141
142        self.assertFalse(self.song.has_images)
143        self.song.reload()
144        self.assertTrue(self.song.has_images)
145
146        image = self.song.get_primary_image()
147        self.assertFalse(image)
148
149    def test_unpack_image_min(self):
150        data = b"\x03" + b"\x00" * 4 + b"\x00" * 4
151        mime, desc, data, type_ = unpack_image(data)
152        self.assertEqual(mime, u"")
153        self.assertEqual(desc, u"")
154        self.assertEqual(data, b"")
155        self.assertEqual(type_, 3)
156
157    def test_unpack_image_invalid(self):
158        self.assertRaises(ValueError, unpack_image, b"")
159        self.assertRaises(ValueError, unpack_image, b"\x00" * 6)
160        self.assertRaises(ValueError, unpack_image, b"\x00" * 8)
161        self.assertRaises(ValueError, unpack_image, b"\x00" * 100)
162
163    def test_pack_image(self):
164        d = pack_image(
165            u"image/jpeg", u"Description", b"foo", APICType.COVER_FRONT)
166        mime, desc, data, type_ = unpack_image(d)
167        self.assertEqual(mime, u"image/jpeg")
168        self.assertEqual(desc, u"Description")
169        self.assertEqual(data, b"foo")
170        self.assertEqual(type_, APICType.COVER_FRONT)
171
172    def test_clear_images(self):
173        # cover case
174        image = self.song2.get_primary_image()
175        self.assertTrue(image)
176        self.song2.clear_images()
177        self.assertFalse(self.song2.has_images)
178        self.song2.reload()
179        image = self.song2.get_primary_image()
180        self.assertFalse(image)
181
182        # no cover case
183        self.song.clear_images()
184
185    def test_set_image(self):
186        fileobj = BytesIO(b"foo")
187        image = EmbeddedImage(fileobj, "image/jpeg", 10, 10, 8)
188        self.assertFalse(self.song.has_images)
189        self.song.set_image(image)
190        self.assertTrue(self.song.has_images)
191
192        image = self.song.get_primary_image()
193        self.assertEqual(image.mime_type, "image/jpeg")
194        self.assertEqual(image.read(), b"foo")
195
196    def test_can_change_images(self):
197        self.assertTrue(self.song.can_change_images)
198
199    def test_can_multiple_values(self):
200        self.assertTrue("artist" in self.song.can_multiple_values())
201        self.assertTrue(self.song.can_multiple_values("genre"))
202