1# -*- coding: utf-8 -*-
2
3from tests import TestCase
4from mutagen._vorbis import VComment, VCommentDict, istag, error
5from mutagen._compat import text_type, PY3
6
7
8class Tistag(TestCase):
9
10    def test_empty(self):
11        self.failIf(istag(""))
12
13    def test_tilde(self):
14        self.failIf(istag("ti~tle"))
15
16    def test_equals(self):
17        self.failIf(istag("ti=tle"))
18
19    def test_less(self):
20        self.failIf(istag("ti\x19tle"))
21
22    def test_greater(self):
23        self.failIf(istag("ti\xa0tle"))
24
25    def test_simple(self):
26        self.failUnless(istag("title"))
27
28    def test_space(self):
29        self.failUnless(istag("ti tle"))
30
31    def test_ugly(self):
32        self.failUnless(istag("!{}[]-_()*&"))
33
34    def test_unicode(self):
35        self.failUnless(istag(u"ti tle"))
36
37    if PY3:
38        def test_py3(self):
39            self.failUnlessRaises(TypeError, istag, b"abc")
40
41
42class TVComment(TestCase):
43
44    def setUp(self):
45        self.c = VComment()
46        self.c.append(("artist", u"piman"))
47        self.c.append(("artist", u"mu"))
48        self.c.append(("title", u"more fakes"))
49
50    def test_invalid_init(self):
51        self.failUnlessRaises(TypeError, VComment, [])
52
53    def test_equal(self):
54        self.failUnlessEqual(self.c, self.c)
55
56    def test_not_header(self):
57        self.failUnlessRaises(error, VComment, b"foo")
58
59    def test_unset_framing_bit(self):
60        self.failUnlessRaises(
61            error, VComment, b"\x00\x00\x00\x00" * 2 + b"\x00")
62
63    def test_empty_valid(self):
64        self.failIf(VComment(b"\x00\x00\x00\x00" * 2 + b"\x01"))
65
66    def test_validate(self):
67        self.failUnless(self.c.validate())
68
69    def test_validate_broken_key(self):
70        self.c.append((1, u"valid"))
71        self.failUnlessRaises(ValueError, self.c.validate)
72        self.failUnlessRaises(ValueError, self.c.write)
73
74    def test_validate_broken_value(self):
75        self.c.append((u"valid", 1))
76        self.failUnlessRaises(ValueError, self.c.validate)
77        self.failUnlessRaises(ValueError, self.c.write)
78
79    def test_validate_nonunicode_value(self):
80        self.c.append((u"valid", b"wt\xff"))
81        self.failUnlessRaises(ValueError, self.c.validate)
82        self.failUnlessRaises(ValueError, self.c.write)
83
84    def test_vendor_default(self):
85        self.failUnless(self.c.vendor.startswith(u"Mutagen"))
86
87    def test_vendor_set(self):
88        self.c.vendor = u"Not Mutagen"
89        self.failUnless(self.c.write()[4:].startswith(b"Not Mutagen"))
90
91    def test_vendor_invalid(self):
92        self.c.vendor = b"\xffNot Mutagen"
93        self.failUnlessRaises(ValueError, self.c.validate)
94        self.failUnlessRaises(ValueError, self.c.write)
95
96    def test_validate_utf8_value(self):
97        self.c.append((u"valid", b"\xc3\xbc\xc3\xb6\xc3\xa4"))
98        if PY3:
99            self.failUnlessRaises(ValueError, self.c.validate)
100        else:
101            self.c.validate()
102
103    def test_invalid_format_strict(self):
104        data = (b'\x07\x00\x00\x00Mutagen\x01\x00\x00\x00\x03\x00\x00'
105                b'\x00abc\x01')
106        self.failUnlessRaises(error, VComment, data, errors='strict')
107
108    def test_invalid_format_replace(self):
109        data = (b'\x07\x00\x00\x00Mutagen\x01\x00\x00\x00\x03\x00\x00'
110                b'\x00abc\x01')
111        comment = VComment(data)
112        self.failUnlessEqual(u"abc", comment[0][1])
113
114    def test_python_key_value_type(self):
115        data = (b'\x07\x00\x00\x00Mutagen\x01\x00\x00\x00\x03\x00\x00'
116                b'\x00abc\x01')
117        comment = VComment(data)
118        self.assertTrue(isinstance(comment[0][0], type('')))
119        self.assertTrue(isinstance(comment[0][1], text_type))
120
121    if PY3:
122        def test_python3_strict_str(self):
123            comment = VComment()
124            comment.append((u"abc", u"test"))
125            comment.validate()
126            comment[0] = (u"abc", b"test")
127            self.failUnlessRaises(ValueError, comment.validate)
128            comment[0] = (b"abc", u"test")
129            self.failUnlessRaises(ValueError, comment.validate)
130
131    def test_invalid_format_ignore(self):
132        data = (b'\x07\x00\x00\x00Mutagen\x01\x00\x00\x00\x03\x00\x00'
133                b'\x00abc\x01')
134        comment = VComment(data, errors='ignore')
135        self.failIf(len(comment))
136
137    # Slightly different test data than above, we want the tag name
138    # to be valid UTF-8 but not valid ASCII.
139    def test_invalid_tag_strict(self):
140        data = (b'\x07\x00\x00\x00Mutagen\x01\x00\x00\x00\x04\x00\x00'
141                b'\x00\xc2\xaa=c\x01')
142        self.failUnlessRaises(error, VComment, data, errors='strict')
143
144    def test_invalid_tag_replace(self):
145        data = (b'\x07\x00\x00\x00Mutagen\x01\x00\x00\x00\x04\x00\x00'
146                b'\x00\xc2\xaa=c\x01')
147        comment = VComment(data)
148        self.failUnlessEqual(u"?=c", comment.pprint())
149
150    def test_invalid_tag_ignore(self):
151        data = (b'\x07\x00\x00\x00Mutagen\x01\x00\x00\x00\x04\x00\x00'
152                b'\x00\xc2\xaa=c\x01')
153        comment = VComment(data, errors='ignore')
154        self.failIf(len(comment))
155
156    def test_roundtrip(self):
157        self.assertReallyEqual(self.c, VComment(self.c.write()))
158
159
160class TVCommentDict(TestCase):
161
162    Kind = VCommentDict
163
164    def setUp(self):
165        self.c = self.Kind()
166        self.c["artist"] = ["mu", "piman"]
167        self.c["title"] = u"more fakes"
168
169    def test_correct_len(self):
170        self.failUnlessEqual(len(self.c), 3)
171
172    def test_keys(self):
173        self.failUnless("artist" in self.c.keys())
174        self.failUnless("title" in self.c.keys())
175
176    def test_values(self):
177        self.failUnless(["mu", "piman"] in self.c.values())
178        self.failUnless(["more fakes"] in self.c.values())
179
180    def test_items(self):
181        self.failUnless(("artist", ["mu", "piman"]) in self.c.items())
182        self.failUnless(("title", ["more fakes"]) in self.c.items())
183
184    def test_equal(self):
185        self.failUnlessEqual(self.c, self.c)
186
187    def test_get(self):
188        self.failUnlessEqual(self.c["artist"], ["mu", "piman"])
189        self.failUnlessEqual(self.c["title"], ["more fakes"])
190
191    def test_set(self):
192        self.c["woo"] = "bar"
193        self.failUnlessEqual(self.c["woo"], ["bar"])
194
195    def test_slice(self):
196        l = [("foo", "bar"), ("foo", "bar2")]
197        self.c[:] = l
198        self.assertEqual(self.c[:], l)
199        self.failUnlessEqual(self.c["foo"], ["bar", "bar2"])
200        del self.c[:]
201        self.assertEqual(self.c[:], [])
202
203    def test_iter(self):
204        self.assertEqual(next(iter(self.c)), ("artist", "mu"))
205        self.assertEqual(list(self.c)[0], ("artist", "mu"))
206
207    def test_del(self):
208        del(self.c["title"])
209        self.failUnlessRaises(KeyError, self.c.__getitem__, "title")
210
211    def test_contains(self):
212        self.failIf("foo" in self.c)
213        self.failUnless("title" in self.c)
214
215    def test_get_case(self):
216        self.failUnlessEqual(self.c["ARTIST"], ["mu", "piman"])
217
218    def test_set_case(self):
219        self.c["TITLE"] = "another fake"
220        self.failUnlessEqual(self.c["title"], ["another fake"])
221
222    def test_set_preserve_case(self):
223        del(self.c["title"])
224        self.c["TiTlE"] = "blah"
225        self.failUnless(("TiTlE", "blah") in list(self.c))
226        self.failUnless("title" in self.c)
227
228    def test_contains_case(self):
229        self.failUnless("TITLE" in self.c)
230
231    def test_del_case(self):
232        del(self.c["TITLE"])
233        self.failUnlessRaises(KeyError, self.c.__getitem__, "title")
234
235    def test_get_failure(self):
236        self.failUnlessRaises(KeyError, self.c.__getitem__, "woo")
237
238    def test_del_failure(self):
239        self.failUnlessRaises(KeyError, self.c.__delitem__, "woo")
240
241    def test_roundtrip(self):
242        self.failUnlessEqual(self.c, self.Kind(self.c.write()))
243
244    def test_roundtrip_vc(self):
245        self.failUnlessEqual(self.c, VComment(self.c.write()))
246
247    def test_case_items_426(self):
248        self.c.append(("WOO", "bar"))
249        self.failUnless(("woo", ["bar"]) in self.c.items())
250
251    def test_empty(self):
252        self.c = VCommentDict()
253        self.failIf(list(self.c.keys()))
254        self.failIf(list(self.c.values()))
255        self.failIf(list(self.c.items()))
256
257    def test_as_dict(self):
258        d = self.c.as_dict()
259        self.failUnless("artist" in d)
260        self.failUnless("title" in d)
261        self.failUnlessEqual(d["artist"], self.c["artist"])
262        self.failUnlessEqual(d["title"], self.c["title"])
263
264    def test_bad_key(self):
265        self.failUnlessRaises(ValueError, self.c.get, u"\u1234")
266        self.failUnlessRaises(
267            ValueError, self.c.__setitem__, u"\u1234", "foo")
268        self.failUnlessRaises(
269            ValueError, self.c.__delitem__, u"\u1234")
270
271    if PY3:
272        def test_py3_bad_key(self):
273            self.failUnlessRaises(TypeError, self.c.get, b"a")
274            self.failUnlessRaises(
275                TypeError, self.c.__setitem__, b"a", "foo")
276            self.failUnlessRaises(
277                TypeError, self.c.__delitem__, b"a")
278
279    def test_duplicate_keys(self):
280        self.c = VCommentDict()
281        keys = ("key", "Key", "KEY")
282        for key in keys:
283            self.c.append((key, "value"))
284        self.failUnlessEqual(len(self.c.keys()), 1)
285        self.failUnlessEqual(len(self.c.as_dict()), 1)
286