1#!/usr/bin/env python
2import ApeTag
3import cStringIO
4import unittest
5import os.path
6
7EMPTY_APE_TAG = "APETAGEX\320\a\0\0 \0\0\0\0\0\0\0\0\0\0\240\0\0\0\0\0\0\0\0APETAGEX\320\a\0\0 \0\0\0\0\0\0\0\0\0\0\200\0\0\0\0\0\0\0\0TAG\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377"
8EXAMPLE_APE_TAG = "APETAGEX\xd0\x07\x00\x00\xb0\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00Track\x001\x04\x00\x00\x00\x00\x00\x00\x00Date\x002007\t\x00\x00\x00\x00\x00\x00\x00Comment\x00XXXX-0000\x0b\x00\x00\x00\x00\x00\x00\x00Title\x00Love Cheese\x0b\x00\x00\x00\x00\x00\x00\x00Artist\x00Test Artist\x16\x00\x00\x00\x00\x00\x00\x00Album\x00Test Album\x00Other AlbumAPETAGEX\xd0\x07\x00\x00\xb0\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00TAGLove Cheese\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Test Artist\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Test Album, Other Album\x00\x00\x00\x00\x00\x00\x002007XXXX-0000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff"
9EXAMPLE_APE_TAG2 = "APETAGEX\xd0\x07\x00\x00\x99\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00Blah\x00Blah\x04\x00\x00\x00\x00\x00\x00\x00Date\x002007\t\x00\x00\x00\x00\x00\x00\x00Comment\x00XXXX-0000\x0b\x00\x00\x00\x00\x00\x00\x00Artist\x00Test Artist\x16\x00\x00\x00\x00\x00\x00\x00Album\x00Test Album\x00Other AlbumAPETAGEX\xd0\x07\x00\x00\x99\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00TAG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Test Artist\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Test Album, Other Album\x00\x00\x00\x00\x00\x00\x002007XXXX-0000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff"
10EMPTY_ID3_FIELDS = {'album': '', 'comment': '', 'title': '', 'track': '0', 'artist': '', 'year': '', 'genre': ''}
11EXAMPLE_ID3_FIELDS = {'album': 'Test Album, Other Album', 'comment': 'XXXX-0000', 'title': 'Love Cheese', 'track': '1', 'artist': 'Test Artist', 'year': '2007', 'genre': ''}
12EXAMPLE_ID3_FIELDS2 = {'album': 'Test Album, Other Album', 'comment': 'XXXX-0000', 'title': '', 'track': '0', 'artist': 'Test Artist', 'year': '2007', 'genre': ''}
13EXAMPLE_APE_FIELDS = {"Track":["1"], "Comment":["XXXX-0000"], "Album":["Test Album", "Other Album"], "Title":["Love Cheese"], "Artist":["Test Artist"], "Date":["2007"]}
14EXAMPLE_APE_FIELDS2 = {"Blah":["Blah"], "Comment":["XXXX-0000"], "Album":["Test Album", "Other Album"], "Artist":["Test Artist"], "Date":["2007"]}
15EXAMPLE_APE_TAG_PRETTY_PRINT = "Album: Test Album, Other Album\nArtist: Test Artist\nComment: XXXX-0000\nDate: 2007\nTitle: Love Cheese\nTrack: 1"
16
17# Replace character
18def rc(string, position, character, io = True):
19    s = '%s%s%s' % (string[:position], chr(character), string[position+1:])
20    if io:
21        return sio(s)
22    return s
23
24# Replace range of characters
25def rr(string, position, characters, io = True):
26    s = '%s%s%s' % (string[:position], characters, string[position+len(characters):])
27    if io:
28        return sio(s)
29    return s
30
31def sio(string):
32    x = cStringIO.StringIO()
33    x.write(string)
34    return x
35
36def filesize(f):
37    if hasattr(f, 'seek'):
38        f.seek(0,2)
39        return f.tell()
40    return os.path.getsize(f)
41
42class TestApeTag(unittest.TestCase):
43    def tag_test(self, f):
44        size = filesize(f)
45        self.assertEqual(False, ApeTag.hasapetag(f))
46        self.assertEqual(size, filesize(f))
47        self.assertEqual(False, ApeTag.hasid3tag(f))
48        self.assertEqual(size, filesize(f))
49        self.assertEqual(False, ApeTag.hastags(f))
50        self.assertEqual(size, filesize(f))
51
52        self.assertEqual(0, ApeTag.deleteape(f))
53        self.assertEqual(size, filesize(f))
54        self.assertEqual(0, ApeTag.deleteid3(f))
55        self.assertEqual(size, filesize(f))
56        self.assertEqual(0, ApeTag.deletetags(f))
57        self.assertEqual(size, filesize(f))
58
59        self.assertRaises(ApeTag.TagError, ApeTag.getrawape, f)
60        self.assertRaises(ApeTag.TagError, ApeTag.getrawid3, f)
61        self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, f)
62        self.assertRaises(ApeTag.TagError, ApeTag.printapetag, f)
63        self.assertRaises(ApeTag.TagError, ApeTag.printid3tag, f)
64        self.assertRaises(ApeTag.TagError, ApeTag.printtags, f)
65        self.assertRaises(ApeTag.TagError, ApeTag.updateape, f)
66        self.assertRaises(ApeTag.TagError, ApeTag.updateid3, f)
67        self.assertRaises(ApeTag.TagError, ApeTag.updatetags, f)
68
69        self.assertEqual({}, ApeTag.createape(f, {}))
70        self.assertEqual({}, ApeTag.getapefields(f))
71        self.assertEqual(True, ApeTag.hasapetag(f))
72        self.assertEqual(False, ApeTag.hasid3tag(f))
73        self.assertEqual(False, ApeTag.hastags(f))
74        self.assertEqual(size+64, filesize(f))
75        self.assertEqual(EMPTY_APE_TAG[:64], ApeTag.getrawape(f))
76        self.assertEqual(0, ApeTag.deleteape(f))
77        self.assertEqual(size, filesize(f))
78
79        self.assertEqual(EMPTY_ID3_FIELDS, ApeTag.createid3(f, {}))
80        self.assertEqual(EMPTY_ID3_FIELDS, ApeTag.getid3fields(f))
81        self.assertEqual(False, ApeTag.hasapetag(f))
82        self.assertEqual(True, ApeTag.hasid3tag(f))
83        self.assertEqual(False, ApeTag.hastags(f))
84        self.assertEqual(size+128, filesize(f))
85        self.assertEqual(EMPTY_APE_TAG[64:], ApeTag.getrawid3(f))
86        self.assertEqual(0, ApeTag.deleteid3(f))
87        self.assertEqual(size, filesize(f))
88
89        self.assertEqual({}, ApeTag.createtags(f, {}))
90        self.assertEqual(({},EMPTY_ID3_FIELDS), ApeTag.gettagfields(f))
91        self.assertEqual(True, ApeTag.hasapetag(f))
92        self.assertEqual(True, ApeTag.hasid3tag(f))
93        self.assertEqual(True, ApeTag.hastags(f))
94        self.assertEqual(size+192, filesize(f))
95        self.assertEqual((EMPTY_APE_TAG[:64], EMPTY_APE_TAG[64:]), ApeTag.getrawtags(f))
96        self.assertEqual(0, ApeTag.deletetags(f))
97        self.assertEqual(size, filesize(f))
98
99
100        self.assertEqual(EXAMPLE_APE_FIELDS, ApeTag.createape(f, EXAMPLE_APE_FIELDS))
101        self.assertEqual(EXAMPLE_APE_FIELDS, ApeTag.getapefields(f))
102        self.assertEqual(EXAMPLE_APE_FIELDS, ApeTag.createape(f, EXAMPLE_APE_FIELDS))
103        self.assertEqual(True, ApeTag.hasapetag(f))
104        self.assertEqual(False, ApeTag.hasid3tag(f))
105        self.assertEqual(False, ApeTag.hastags(f))
106        self.assertEqual(size+208, filesize(f))
107        self.assertEqual(EXAMPLE_APE_TAG[:-128], ApeTag.getrawape(f))
108        self.assertEqual(0, ApeTag.deleteape(f))
109        self.assertEqual(size, filesize(f))
110
111        self.assertEqual(EXAMPLE_ID3_FIELDS, ApeTag.createid3(f, EXAMPLE_ID3_FIELDS))
112        self.assertEqual(EXAMPLE_ID3_FIELDS, ApeTag.getid3fields(f))
113        self.assertEqual(EXAMPLE_ID3_FIELDS, ApeTag.createid3(f, EXAMPLE_ID3_FIELDS))
114        self.assertEqual(False, ApeTag.hasapetag(f))
115        self.assertEqual(True, ApeTag.hasid3tag(f))
116        self.assertEqual(False, ApeTag.hastags(f))
117        self.assertEqual(size+128, filesize(f))
118        self.assertEqual(EXAMPLE_APE_TAG[-128:], ApeTag.getrawid3(f))
119        self.assertEqual(0, ApeTag.deleteid3(f))
120        self.assertEqual(size, filesize(f))
121
122        self.assertEqual(EXAMPLE_APE_FIELDS, ApeTag.createtags(f, EXAMPLE_APE_FIELDS))
123        self.assertEqual((EXAMPLE_APE_FIELDS,EXAMPLE_ID3_FIELDS), ApeTag.gettagfields(f))
124        self.assertEqual(EXAMPLE_APE_FIELDS, ApeTag.createtags(f, EXAMPLE_APE_FIELDS))
125        self.assertEqual(True, ApeTag.hasapetag(f))
126        self.assertEqual(True, ApeTag.hasid3tag(f))
127        self.assertEqual(True, ApeTag.hastags(f))
128        self.assertEqual(size+336, filesize(f))
129        self.assertEqual((EXAMPLE_APE_TAG[:-128], EXAMPLE_APE_TAG[-128:]), ApeTag.getrawtags(f))
130        self.assertEqual(0, ApeTag.deletetags(f))
131        self.assertEqual(size, filesize(f))
132
133
134        self.assertEqual(EXAMPLE_APE_FIELDS, ApeTag.createape(f, EXAMPLE_APE_FIELDS))
135        self.assertEqual(EXAMPLE_APE_FIELDS2, ApeTag.updateape(f, {'Blah':'Blah'}, ['Track', 'Title']))
136        self.assertEqual(EXAMPLE_APE_FIELDS2, ApeTag.getapefields(f))
137        self.assertEqual(True, ApeTag.hasapetag(f))
138        self.assertEqual(False, ApeTag.hasid3tag(f))
139        self.assertEqual(False, ApeTag.hastags(f))
140        self.assertEqual(size+185, filesize(f))
141        self.assertEqual(EXAMPLE_APE_TAG2[:-128], ApeTag.getrawape(f))
142
143        self.assertEqual(EXAMPLE_APE_FIELDS, ApeTag.replaceape(f, EXAMPLE_APE_FIELDS))
144        self.assertEqual(EXAMPLE_APE_FIELDS, ApeTag.getapefields(f))
145        self.assertEqual(True, ApeTag.hasapetag(f))
146        self.assertEqual(False, ApeTag.hasid3tag(f))
147        self.assertEqual(False, ApeTag.hastags(f))
148        self.assertEqual(size+208, filesize(f))
149        self.assertEqual(EXAMPLE_APE_TAG[:-128], ApeTag.getrawape(f))
150        self.assertEqual(EXAMPLE_APE_FIELDS2, ApeTag.updateape(f, {'Blah':'Blah'}, ['track', 'title']))
151        self.assertEqual(EXAMPLE_APE_TAG2[:-128], ApeTag.getrawape(f))
152        self.assertEqual(0, ApeTag.deleteape(f))
153        self.assertEqual(size, filesize(f))
154
155        self.assertEqual(EXAMPLE_ID3_FIELDS, ApeTag.createid3(f, EXAMPLE_ID3_FIELDS))
156        self.assertEqual(EXAMPLE_ID3_FIELDS2, ApeTag.updateid3(f, {'Track':0, 'Title':''}))
157        self.assertEqual(EXAMPLE_ID3_FIELDS2, ApeTag.getid3fields(f))
158        self.assertEqual(False, ApeTag.hasapetag(f))
159        self.assertEqual(True, ApeTag.hasid3tag(f))
160        self.assertEqual(False, ApeTag.hastags(f))
161        self.assertEqual(size+128, filesize(f))
162        self.assertEqual(EXAMPLE_APE_TAG2[-128:], ApeTag.getrawid3(f))
163
164        self.assertEqual(EXAMPLE_ID3_FIELDS, ApeTag.replaceid3(f, EXAMPLE_ID3_FIELDS))
165        self.assertEqual(EXAMPLE_ID3_FIELDS, ApeTag.getid3fields(f))
166        self.assertEqual(False, ApeTag.hasapetag(f))
167        self.assertEqual(True, ApeTag.hasid3tag(f))
168        self.assertEqual(False, ApeTag.hastags(f))
169        self.assertEqual(size+128, filesize(f))
170        self.assertEqual(EXAMPLE_APE_TAG[-128:], ApeTag.getrawid3(f))
171        self.assertEqual(0, ApeTag.deleteid3(f))
172        self.assertEqual(size, filesize(f))
173
174        self.assertEqual(EXAMPLE_APE_FIELDS, ApeTag.createtags(f, EXAMPLE_APE_FIELDS))
175        self.assertEqual(EXAMPLE_APE_FIELDS2, ApeTag.updatetags(f, {'Blah':'Blah'}, ['Track', 'Title']))
176        self.assertEqual((EXAMPLE_APE_FIELDS2, EXAMPLE_ID3_FIELDS2), ApeTag.gettagfields(f))
177        self.assertEqual(True, ApeTag.hasapetag(f))
178        self.assertEqual(True, ApeTag.hasid3tag(f))
179        self.assertEqual(True, ApeTag.hastags(f))
180        self.assertEqual(size+313, filesize(f))
181        self.assertEqual((EXAMPLE_APE_TAG2[:-128], EXAMPLE_APE_TAG2[-128:]), ApeTag.getrawtags(f))
182
183        self.assertEqual(EXAMPLE_APE_FIELDS, ApeTag.replacetags(f, EXAMPLE_APE_FIELDS))
184        self.assertEqual((EXAMPLE_APE_FIELDS, EXAMPLE_ID3_FIELDS), ApeTag.gettagfields(f))
185        self.assertEqual(True, ApeTag.hasapetag(f))
186        self.assertEqual(True, ApeTag.hasid3tag(f))
187        self.assertEqual(True, ApeTag.hastags(f))
188        self.assertEqual(size+336, filesize(f))
189        self.assertEqual((EXAMPLE_APE_TAG[:-128], EXAMPLE_APE_TAG[-128:]), ApeTag.getrawtags(f))
190        self.assertEqual(EXAMPLE_APE_FIELDS2, ApeTag.updatetags(f, {'Blah':'Blah'}, ['track', 'title']))
191        self.assertEqual((EXAMPLE_APE_TAG2[:-128], EXAMPLE_APE_TAG2[-128:]), ApeTag.getrawtags(f))
192        self.assertEqual(0, ApeTag.deletetags(f))
193        self.assertEqual(size, filesize(f))
194
195    def test_multiple_sizes(self):
196        filename = 'test.apetag'
197        file(filename, 'wb').close()
198        for x in [0,1,63,64,65,127,128,129,191,192,193,8191,8192,8193]:
199            s = ' ' * x
200            f = sio(s)
201            self.tag_test(f)
202            f = file(filename,'r+b')
203            f.write(s)
204            self.tag_test(f)
205            f.close()
206            self.tag_test(filename)
207        os.remove(filename)
208
209    def test_ape_item_init(self):
210        ai = ApeTag.ApeItem()
211        self.assertEqual([], ai)
212
213        ai = ApeTag.ApeItem('BlaH')
214        self.assertEqual(False, ai.readonly)
215        self.assertEqual('utf8', ai.type)
216        self.assertEqual('BlaH', ai.key)
217        self.assertEqual([], ai)
218
219        ai = ApeTag.ApeItem('BlaH', ['BlAh'])
220        self.assertEqual(False, ai.readonly)
221        self.assertEqual('utf8', ai.type)
222        self.assertEqual('BlaH', ai.key)
223        self.assertEqual(['BlAh'], ai)
224
225        ai = ApeTag.ApeItem('BlaH', ['BlAh'], 'external')
226        self.assertEqual(False, ai.readonly)
227        self.assertEqual('external', ai.type)
228        self.assertEqual('BlaH', ai.key)
229        self.assertEqual(['BlAh'], ai)
230
231        ai = ApeTag.ApeItem('BlaH', ['BlAh'], 'external', True)
232        self.assertEqual(True, ai.readonly)
233        self.assertEqual('external', ai.type)
234        self.assertEqual('BlaH', ai.key)
235        self.assertEqual(['BlAh'], ai)
236
237    def test_ape_item_valid_key(self):
238        ai = ApeTag.ApeItem()
239        # Test bad keys
240        for x in [None, 1, '', 'x', 'x'*256]+["%s  " % c for c in ApeTag._badapeitemkeychars]+ApeTag._badapeitemkeys:
241            self.assertEqual(False, ai.validkey(x))
242        # Test good keys
243        for x in ['xx', 'x'*255]+["%s  " % chr(c) for c in range(32,128)]+["%s  " % c for c in ApeTag._badapeitemkeys]:
244            self.assertEqual(True, ai.validkey(x))
245
246    def test_ape_item_maketag(self):
247        ai = ApeTag.ApeItem('BlaH', ['BlAh'])
248        self.assertEqual("\04\0\0\0\0\0\0\0BlaH\0BlAh", ai.maketag())
249        ai.readonly=True
250        self.assertEqual("\04\0\0\0\0\0\0\01BlaH\0BlAh", ai.maketag())
251        ai.type='external'
252        self.assertEqual("\04\0\0\0\0\0\0\05BlaH\0BlAh", ai.maketag())
253        ai.append('XYZ')
254        self.assertEqual("\010\0\0\0\0\0\0\05BlaH\0BlAh\0XYZ", ai.maketag())
255
256    def test_ape_item_parsetag(self):
257        data = "\010\0\0\0\0\0\0\05BlaH\0BlAh\0XYZ"
258        # Test simple parsing
259        ai = ApeTag.ApeItem()
260        cp = ai.parsetag(data, 0)
261        self.assertEqual(2, len(ai))
262        self.assertEqual(len(data), cp)
263        self.assertEqual(True, ai.readonly)
264        self.assertEqual('external', ai.type)
265        self.assertEqual('BlaH', ai.key)
266
267        # Test parsing with bad key
268        self.assertRaises(ApeTag.TagError, ApeTag.ApeItem().parsetag, "\0\0\0\0\0\0\0\0x\0", 0)
269
270        # Test parsing with no key end
271        self.assertRaises(ApeTag.TagError, ApeTag.ApeItem().parsetag, "\0\0\0\0\0\0\0\0xx", 0)
272
273        # Test prasing with bad start value
274        self.assertRaises(ApeTag.TagError, ApeTag.ApeItem().parsetag, data, 1)
275
276        # Test parsing with bad flags
277        self.assertRaises(ApeTag.TagError, ApeTag.ApeItem().parsetag, "\0\0\0\0\0\0\0\010xx\0", 1)
278
279        # Test parsing with length longer than string
280        self.assertRaises(ApeTag.TagError, ApeTag.ApeItem().parsetag, "\01\0\0\0\0\0\0\010xx\0", 1)
281
282        # Test parsing with length shorter than string gives valid ApeItem
283        # Of course, the next item will probably be parsed incorrectly
284        ai = ApeTag.ApeItem()
285        cp = ai.parsetag('\03'+data[1:], 0)
286        self.assertEqual(16, cp)
287        self.assertEqual('BlaH', ai.key)
288        self.assertEqual(['BlA'], ai)
289
290        # Test parsing of invalid UTF-8
291        self.assertRaises(ApeTag.TagError, ApeTag.ApeItem().parsetag, "\01\0\0\0\0\0\0\010xx\0\x83", 1)
292
293    def test_bad_tags(self):
294        # Test read only tag flag works
295        ro_tag = rc(rc(EMPTY_APE_TAG, 20, 1, False), 52, 1)
296        ro_tag.seek(0)
297        ro_tag = ro_tag.read()
298        self.assertEqual(''.join(ApeTag.getrawtags(rc(rc(EMPTY_APE_TAG, 20, 1, False), 52, 1))), ro_tag)
299        # Test bad tag flags
300        for i in range(2,256):
301            self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, rc(EMPTY_APE_TAG, 20, i))
302            self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, rc(EMPTY_APE_TAG, 52, i))
303            self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, rc(rc(EMPTY_APE_TAG, 20, i, False), 52, i))
304
305        # Test footer size less than minimum size (32)
306        self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, rc(EMPTY_APE_TAG, 44, 31))
307        self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, rc(EMPTY_APE_TAG, 44, 0))
308
309        # Test tag size > 8192, when both larger than file and smaller than file
310        large = rc(rc(EMPTY_APE_TAG, 44, 225, False), 45, 31, False)
311        self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, sio(large))
312        self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, sio(' '*8192+large))
313
314        # Test unmatching header and footer tag size, with footer size wrong
315        self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, rc(EMPTY_APE_TAG, 44, 33))
316
317        # Test matching header and footer but size to large for file
318        wrong = rc(rc(EMPTY_APE_TAG, 12, 33, False), 44, 33, False)
319        self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, sio(wrong))
320
321        # Test that header and footer size isn't too large for file, but doesn't
322        # find the header
323        wrong=" "+wrong
324        self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, sio(wrong))
325
326        # Test unmatching header and footer tag size, with header size wrong
327        self.assertRaises(ApeTag.TagError, ApeTag.getrawtags, rc(EMPTY_APE_TAG, 45, 32))
328
329        # Test item count greater than possible given tag size
330        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rc(EMPTY_APE_TAG, 48, 1))
331
332        # Test unmatched header and footer item size, header size wrong
333        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rc(EMPTY_APE_TAG, 16, 1))
334
335        # Test unmatched header and footer item size, footer size wrong
336        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rc(EXAMPLE_APE_TAG, 192, ord(EXAMPLE_APE_TAG[192])-1))
337
338        # Test missing/corrupt header
339        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rc(EMPTY_APE_TAG, 0, 0))
340
341        # Test parsing bad first item size
342        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rc(EXAMPLE_APE_TAG, 32, ord(EXAMPLE_APE_TAG[32])+1))
343
344        # Test parsing bad first item invalid key
345        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rc(EXAMPLE_APE_TAG, 40, 0))
346
347        # Test parsing bad first item key end
348        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rc(EXAMPLE_APE_TAG, 45, 1))
349
350        # Test parsing bad second item length too long
351        self.assertRaises((ApeTag.TagError, UnicodeDecodeError), ApeTag.gettagfields, rc(EXAMPLE_APE_TAG, 47, 255))
352
353        # Test parsing case insensitive duplicate keys
354        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rr(EXAMPLE_APE_TAG, 40, 'Album'))
355        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rr(EXAMPLE_APE_TAG, 40, 'album'))
356        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rr(EXAMPLE_APE_TAG, 40, 'ALBUM'))
357
358        # Test parsing incorrect item counts
359        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rc(rc(EXAMPLE_APE_TAG, 16, ord(EXAMPLE_APE_TAG[16])+1, False), 192, ord(EXAMPLE_APE_TAG[192])+1))
360        self.assertRaises(ApeTag.TagError, ApeTag.gettagfields, rc(rc(EXAMPLE_APE_TAG, 16, ord(EXAMPLE_APE_TAG[16])-1, False), 192, ord(EXAMPLE_APE_TAG[192])-1))
361
362        # Test updating with invalid key
363        self.assertRaises(ApeTag.TagError, ApeTag.updatetags, sio(EXAMPLE_APE_TAG), {'x':'x'})
364
365        # Test updating with too large a tag
366        self.assertRaises(ApeTag.TagError, ApeTag.updatetags, sio(EXAMPLE_APE_TAG), {'x':'x'*8192})
367
368    def test_ape_to_id3_fields_conversion(self):
369        pass
370
371if __name__ == '__main__':
372    unittest.main()
373