1# -*- coding: utf-8 -*-
2
3import os
4import shutil
5
6from mutagen._compat import cBytesIO
7from mutagen.ogg import OggPage
8from mutagen.oggvorbis import OggVorbis, OggVorbisInfo, delete, error
9
10from tests import TestCase, DATA_DIR, get_temp_copy
11from tests.test_ogg import TOggFileTypeMixin
12
13
14class TOggVorbis(TestCase, TOggFileTypeMixin):
15    Kind = OggVorbis
16
17    def setUp(self):
18        self.filename = get_temp_copy(os.path.join(DATA_DIR, "empty.ogg"))
19        self.audio = self.Kind(self.filename)
20
21    def tearDown(self):
22        os.unlink(self.filename)
23
24    def test_module_delete(self):
25        delete(self.filename)
26        self.scan_file()
27        self.failIf(OggVorbis(self.filename).tags)
28
29    def test_bitrate(self):
30        self.failUnlessEqual(112000, self.audio.info.bitrate)
31
32    def test_channels(self):
33        self.failUnlessEqual(2, self.audio.info.channels)
34
35    def test_sample_rate(self):
36        self.failUnlessEqual(44100, self.audio.info.sample_rate)
37
38    def test_invalid_not_first(self):
39        with open(self.filename, "rb") as h:
40            page = OggPage(h)
41        page.first = False
42        self.failUnlessRaises(error, OggVorbisInfo, cBytesIO(page.write()))
43
44    def test_avg_bitrate(self):
45        with open(self.filename, "rb") as h:
46            page = OggPage(h)
47        packet = page.packets[0]
48        packet = (packet[:16] + b"\x00\x00\x01\x00" + b"\x00\x00\x00\x00" +
49                  b"\x00\x00\x00\x00" + packet[28:])
50        page.packets[0] = packet
51        info = OggVorbisInfo(cBytesIO(page.write()))
52        self.failUnlessEqual(info.bitrate, 32768)
53
54    def test_overestimated_bitrate(self):
55        with open(self.filename, "rb") as h:
56            page = OggPage(h)
57        packet = page.packets[0]
58        packet = (packet[:16] + b"\x00\x00\x01\x00" + b"\x00\x00\x00\x01" +
59                  b"\x00\x00\x00\x00" + packet[28:])
60        page.packets[0] = packet
61        info = OggVorbisInfo(cBytesIO(page.write()))
62        self.failUnlessEqual(info.bitrate, 65536)
63
64    def test_underestimated_bitrate(self):
65        with open(self.filename, "rb") as h:
66            page = OggPage(h)
67        packet = page.packets[0]
68        packet = (packet[:16] + b"\x00\x00\x01\x00" + b"\x01\x00\x00\x00" +
69                  b"\x00\x00\x01\x00" + packet[28:])
70        page.packets[0] = packet
71        info = OggVorbisInfo(cBytesIO(page.write()))
72        self.failUnlessEqual(info.bitrate, 65536)
73
74    def test_negative_bitrate(self):
75        with open(self.filename, "rb") as h:
76            page = OggPage(h)
77        packet = page.packets[0]
78        packet = (packet[:16] + b"\xff\xff\xff\xff" + b"\xff\xff\xff\xff" +
79                  b"\xff\xff\xff\xff" + packet[28:])
80        page.packets[0] = packet
81        info = OggVorbisInfo(cBytesIO(page.write()))
82        self.failUnlessEqual(info.bitrate, 0)
83
84    def test_vendor(self):
85        self.failUnless(
86            self.audio.tags.vendor.startswith("Xiph.Org libVorbis"))
87        self.failUnlessRaises(KeyError, self.audio.tags.__getitem__, "vendor")
88
89    def test_vorbiscomment(self):
90        self.audio.save()
91        self.scan_file()
92        if ogg is None:
93            return
94        self.failUnless(ogg.vorbis.VorbisFile(self.filename))
95
96    def test_vorbiscomment_big(self):
97        self.test_really_big()
98        self.audio.save()
99        self.scan_file()
100        if ogg is None:
101            return
102        vfc = ogg.vorbis.VorbisFile(self.filename).comment()
103        self.failUnlessEqual(self.audio["foo"], vfc["foo"])
104
105    def test_vorbiscomment_delete(self):
106        self.audio.delete()
107        self.scan_file()
108        if ogg is None:
109            return
110        vfc = ogg.vorbis.VorbisFile(self.filename).comment()
111        self.failUnlessEqual(vfc.keys(), ["VENDOR"])
112
113    def test_vorbiscomment_delete_readd(self):
114        self.audio.delete()
115        self.audio.tags.clear()
116        self.audio["foobar"] = "foobar" * 1000
117        self.audio.save()
118        self.scan_file()
119        if ogg is None:
120            return
121        vfc = ogg.vorbis.VorbisFile(self.filename).comment()
122        self.failUnlessEqual(self.audio["foobar"], vfc["foobar"])
123        self.failUnless("FOOBAR" in vfc.keys())
124        self.failUnless("VENDOR" in vfc.keys())
125
126    def test_huge_tag(self):
127        vorbis = self.Kind(
128            os.path.join(DATA_DIR, "multipagecomment.ogg"))
129        self.failUnless("big" in vorbis.tags)
130        self.failUnless("bigger" in vorbis.tags)
131        self.failUnlessEqual(vorbis.tags["big"], ["foobar" * 10000])
132        self.failUnlessEqual(vorbis.tags["bigger"], ["quuxbaz" * 10000])
133        self.scan_file()
134
135    def test_not_my_ogg(self):
136        fn = os.path.join(DATA_DIR, 'empty.oggflac')
137        self.failUnlessRaises(error, type(self.audio), fn)
138        self.failUnlessRaises(error, self.audio.save, fn)
139        self.failUnlessRaises(error, self.audio.delete, fn)
140
141    def test_save_split_setup_packet(self):
142        fn = os.path.join(DATA_DIR, "multipage-setup.ogg")
143        shutil.copy(fn, self.filename)
144        audio = OggVorbis(self.filename)
145        tags = audio.tags
146        self.failUnless(tags)
147        audio.save()
148        self.audio = OggVorbis(self.filename)
149        self.failUnlessEqual(self.audio.tags, tags)
150
151    def test_save_split_setup_packet_reference(self):
152        if ogg is None:
153            return
154        self.test_save_split_setup_packet()
155        vfc = ogg.vorbis.VorbisFile(self.filename).comment()
156        for key in self.audio:
157            self.failUnlessEqual(vfc[key], self.audio[key])
158        self.ogg_reference(self.filename)
159
160    def test_save_grown_split_setup_packet_reference(self):
161        if ogg is None:
162            return
163        fn = os.path.join(DATA_DIR, "multipage-setup.ogg")
164        shutil.copy(fn, self.filename)
165        audio = OggVorbis(self.filename)
166        audio["foobar"] = ["quux" * 50000]
167        tags = audio.tags
168        self.failUnless(tags)
169        audio.save()
170        self.audio = OggVorbis(self.filename)
171        self.failUnlessEqual(self.audio.tags, tags)
172        vfc = ogg.vorbis.VorbisFile(self.filename).comment()
173        for key in self.audio:
174            self.failUnlessEqual(vfc[key], self.audio[key])
175        self.ogg_reference(self.filename)
176
177    def test_mime(self):
178        self.failUnless("audio/vorbis" in self.audio.mime)
179
180    def test_init_padding(self):
181        self.assertEqual(self.audio.tags._padding, 0)
182
183try:
184    import ogg.vorbis
185except ImportError:
186    print("WARNING: Skipping Ogg Vorbis reference tests.")
187    ogg = None
188