def test_unsupported_version(self): page = OggPage(open(self.filename, "rb")) data = bytearray(page.packets[0]) data[8] = 0x03 page.packets[0] = bytes(data) OggOpusInfo(BytesIO(page.write())) data[8] = 0x10 page.packets[0] = bytes(data) self.failUnlessRaises(IOError, OggOpusInfo, BytesIO(page.write()))
def __init__(self, fileobj, info): pages = self.__get_comment_pages(fileobj, info) data = OggPage.to_packets(pages)[0][8:] # Strip OpusTags fileobj = BytesIO(data) super(OggOpusVComment, self).__init__(fileobj, framing=False) # in case the LSB of the first byte after v-comment is 1, preserve the # following data padding_flag = fileobj.read(1) if padding_flag and ord(padding_flag) & 0x1: self._pad_data = padding_flag + fileobj.read() else: self._pad_data = b""
def test_renumber_extradata(self): fileobj = BytesIO() for page in self.pages: fileobj.write(page.write()) fileobj.write(b"left over data") fileobj.seek(0) # Trying to rewrite should raise an error... self.failUnlessRaises(Exception, OggPage.renumber, fileobj, 1, 10) fileobj.seek(0) # But the already written data should remain valid, pages = [OggPage(fileobj) for i in range(3)] self.failUnlessEqual([page.sequence for page in pages], [10, 11, 12]) # And the garbage that caused the error should be okay too. self.failUnlessEqual(fileobj.read(), b"left over data")
def test_replace_continued(self): # take a partial packet and replace it with a new page # replace() should make it spanning again fileobj = BytesIO() pages = [OggPage(), OggPage()] pages[0].serial = 1 pages[0].sequence = 0 pages[0].complete = False pages[0].packets = [b"foo"] pages[1].serial = 1 pages[1].sequence = 1 pages[1].continued = True pages[1].packets = [b"bar"] fileobj = BytesIO() for page in pages: fileobj.write(page.write()) fileobj.seek(0, 0) pages_from_file = [OggPage(fileobj), OggPage(fileobj)] self.assertEqual(OggPage.to_packets(pages_from_file), [b"foobar"]) packets_part = OggPage.to_packets([pages_from_file[0]]) self.assertEqual(packets_part, [b"foo"]) new_pages = OggPage.from_packets([b"quuux"]) OggPage.replace(fileobj, [pages_from_file[0]], new_pages) fileobj.seek(0, 0) written = OggPage.to_packets([OggPage(fileobj), OggPage(fileobj)]) self.assertEquals(written, [b"quuuxbar"])
def __init__(self, fileobj, info): pages = self.__get_comment_pages(fileobj, info) data = OggPage.to_packets(pages)[0][8:] # Strip OpusTags fileobj = BytesIO(data) super(OggOpusVComment, self).__init__(fileobj, framing=False) self._padding = len(data) - self._size # in case the LSB of the first byte after v-comment is 1, preserve the # following data padding_flag = fileobj.read(1) if padding_flag and ord(padding_flag) & 0x1: self._pad_data = padding_flag + fileobj.read() self._padding = 0 # we have to preserve, so no padding else: self._pad_data = b""
def test_renumber_muxed(self): pages = [OggPage() for i in range(10)] for seq, page in enumerate(pages[0:1] + pages[2:]): page.serial = 0 page.sequence = seq pages[1].serial = 2 pages[1].sequence = 100 data = BytesIO(b"".join([page.write() for page in pages])) OggPage.renumber(data, 0, 20) data.seek(0) pages = [OggPage(data) for i in range(10)] self.failUnlessEqual(pages[1].serial, 2) self.failUnlessEqual(pages[1].sequence, 100) pages.pop(1) self.failUnlessEqual([page.sequence for page in pages], list(range(20, 29)))
def test_find_last(self): pages = [OggPage() for i in range(10)] for i, page in enumerate(pages): page.sequence = i data = BytesIO(b"".join([page.write() for page in pages])) self.failUnlessEqual(OggPage.find_last(data, pages[0].serial), pages[-1])
def test_find_last_single_muxed(self): page1 = OggPage() page1.last = True page2 = OggPage() page2.serial = page1.serial + 1 pages = [page1, page2] data = BytesIO(b"".join([page.write() for page in pages])) assert OggPage.find_last(data, page2.serial).serial == page2.serial
def test_resize_dev_full(self): def raise_no_space(*args): raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC)) # fail on first write h = BytesIO(b"abc") h.write = raise_no_space self.assertRaises(IOError, resize_file, h, 1) h.seek(0, 2) self.assertEqual(h.tell(), 3) # fail on flush h = BytesIO(b"abc") h.flush = raise_no_space self.assertRaises(IOError, resize_file, h, 1) h.seek(0, 2) self.assertEqual(h.tell(), 3)
def test_find_last_none_finishing_mux(self): page1 = OggPage() page1.last = True page1.position = -1 page2 = OggPage() page2.serial = page1.serial + 1 pages = [page1, page2] data = BytesIO(b"".join([page.write() for page in pages])) assert OggPage.find_last(data, page1.serial, finishing=True) is None assert OggPage.find_last(data, page2.serial, finishing=True) == page2
def test_replace_fast_path(self): # create interleaved pages fileobj = BytesIO() pages = [OggPage(), OggPage(), OggPage()] pages[0].serial = 42 pages[0].sequence = 0 pages[0].packets = [b"foo"] pages[1].serial = 24 pages[1].sequence = 0 pages[1].packets = [b"bar"] pages[2].serial = 42 pages[2].sequence = 1 pages[2].packets = [b"baz"] for page in pages: fileobj.write(page.write()) fileobj.seek(0, 0) pages_from_file = [ OggPage(fileobj), OggPage(fileobj), OggPage(fileobj) ] old_pages = [pages_from_file[0], pages_from_file[2]] packets = OggPage.to_packets(old_pages, strict=True) self.assertEqual(packets, [b"foo", b"baz"]) new_packets = [b"111", b"222"] new_pages = OggPage._from_packets_try_preserve(new_packets, old_pages) self.assertEqual(len(new_pages), 2) # remove insert_bytes, so we can be sure the fast path was taken old_insert_bytes = _util.insert_bytes _util.insert_bytes = None try: OggPage.replace(fileobj, old_pages, new_pages) finally: _util.insert_bytes = old_insert_bytes # validate that the new data was written and the other pages # are untouched fileobj.seek(0, 0) pages_from_file = [ OggPage(fileobj), OggPage(fileobj), OggPage(fileobj) ] packets = OggPage.to_packets([pages_from_file[0], pages_from_file[2]], strict=True) self.assertEqual(packets, [b"111", b"222"]) packets = OggPage.to_packets([pages_from_file[1]], strict=True) self.assertEqual(packets, [b"bar"])
def test_read_max_size(self): page = OggPage() page.packets = [b"1" * 255 * 255] page.complete = False page2 = OggPage() page2.packets = [b"", b"foo"] page2.sequence = 1 page2.continued = True data = page.write() + page2.write() fileobj = BytesIO(data) self.failUnlessEqual(OggPage(fileobj), page) self.failUnlessEqual(OggPage(fileobj), page2) self.failUnlessRaises(EOFError, OggPage, fileobj)
def test_find_last_last_empty(self): # https://github.com/quodlibet/mutagen/issues/308 pages = [OggPage() for i in xrange(10)] for i, page in enumerate(pages): page.sequence = i page.position = i pages[-1].last = True pages[-1].position = -1 data = BytesIO(b"".join([page.write() for page in pages])) page = OggPage.find_last(data, pages[-1].serial, finishing=True) assert page is not None assert page.position == 8 page = OggPage.find_last(data, pages[-1].serial, finishing=False) assert page is not None assert page.position == -1
def test_replace_fast_path(self): # create interleaved pages fileobj = BytesIO() pages = [OggPage(), OggPage(), OggPage()] pages[0].serial = 42 pages[0].sequence = 0 pages[0].packets = [b"foo"] pages[1].serial = 24 pages[1].sequence = 0 pages[1].packets = [b"bar"] pages[2].serial = 42 pages[2].sequence = 1 pages[2].packets = [b"baz"] for page in pages: fileobj.write(page.write()) fileobj.seek(0, 0) pages_from_file = [OggPage(fileobj), OggPage(fileobj), OggPage(fileobj)] old_pages = [pages_from_file[0], pages_from_file[2]] packets = OggPage.to_packets(old_pages, strict=True) self.assertEqual(packets, [b"foo", b"baz"]) new_packets = [b"111", b"222"] new_pages = OggPage._from_packets_try_preserve(new_packets, old_pages) self.assertEqual(len(new_pages), 2) # remove insert_bytes, so we can be sure the fast path was taken old_insert_bytes = _util.insert_bytes _util.insert_bytes = None try: OggPage.replace(fileobj, old_pages, new_pages) finally: _util.insert_bytes = old_insert_bytes # validate that the new data was written and the other pages # are untouched fileobj.seek(0, 0) pages_from_file = [OggPage(fileobj), OggPage(fileobj), OggPage(fileobj)] packets = OggPage.to_packets( [pages_from_file[0], pages_from_file[2]], strict=True) self.assertEqual(packets, [b"111", b"222"]) packets = OggPage.to_packets([pages_from_file[1]], strict=True) self.assertEqual(packets, [b"bar"])
def test_replace(self): # create interleaved pages fileobj = BytesIO() pages = [OggPage(), OggPage(), OggPage()] pages[0].serial = 42 pages[0].sequence = 0 pages[0].packets = [b"foo"] pages[1].serial = 24 pages[1].sequence = 0 pages[1].packets = [b"bar"] pages[2].serial = 42 pages[2].sequence = 1 pages[2].packets = [b"baz"] for page in pages: fileobj.write(page.write()) fileobj.seek(0, 0) pages_from_file = [ OggPage(fileobj), OggPage(fileobj), OggPage(fileobj) ] old_pages = [pages_from_file[0], pages_from_file[2]] packets = OggPage.to_packets(old_pages, strict=True) self.assertEqual(packets, [b"foo", b"baz"]) new_packets = [b"1111", b"2222"] new_pages = OggPage.from_packets(new_packets, sequence=old_pages[0].sequence) self.assertEqual(len(new_pages), 1) OggPage.replace(fileobj, old_pages, new_pages) fileobj.seek(0, 0) first = OggPage(fileobj) self.assertEqual(first.serial, 42) self.assertEqual(OggPage.to_packets([first], strict=True), [b"1111", b"2222"]) second = OggPage(fileobj) self.assertEqual(second.serial, 24) self.assertEqual(OggPage.to_packets([second], strict=True), [b"bar"])
def test_replace(self): # create interleaved pages fileobj = BytesIO() pages = [OggPage(), OggPage(), OggPage()] pages[0].serial = 42 pages[0].sequence = 0 pages[0].packets = [b"foo"] pages[1].serial = 24 pages[1].sequence = 0 pages[1].packets = [b"bar"] pages[2].serial = 42 pages[2].sequence = 1 pages[2].packets = [b"baz"] for page in pages: fileobj.write(page.write()) fileobj.seek(0, 0) pages_from_file = [OggPage(fileobj), OggPage(fileobj), OggPage(fileobj)] old_pages = [pages_from_file[0], pages_from_file[2]] packets = OggPage.to_packets(old_pages, strict=True) self.assertEqual(packets, [b"foo", b"baz"]) new_packets = [b"1111", b"2222"] new_pages = OggPage.from_packets(new_packets, sequence=old_pages[0].sequence) self.assertEqual(len(new_pages), 1) OggPage.replace(fileobj, old_pages, new_pages) fileobj.seek(0, 0) first = OggPage(fileobj) self.assertEqual(first.serial, 42) self.assertEqual(OggPage.to_packets([first], strict=True), [b"1111", b"2222"]) second = OggPage(fileobj) self.assertEqual(second.serial, 24) self.assertEqual(OggPage.to_packets([second], strict=True), [b"bar"])
def test_renumber(self): self.failUnlessEqual([page.sequence for page in self.pages], [0, 1, 2]) fileobj = BytesIO() for page in self.pages: fileobj.write(page.write()) fileobj.seek(0) OggPage.renumber(fileobj, 1, 10) fileobj.seek(0) pages = [OggPage(fileobj) for i in range(3)] self.failUnlessEqual([page.sequence for page in pages], [10, 11, 12]) fileobj.seek(0) OggPage.renumber(fileobj, 1, 20) fileobj.seek(0) pages = [OggPage(fileobj) for i in range(3)] self.failUnlessEqual([page.sequence for page in pages], [20, 21, 22])
def test_single_page_roundtrip(self): self.failUnlessEqual(self.page, OggPage(BytesIO(self.page.write())))
def test_find_last_invalid_sync(self): data = BytesIO(b"if you think this is an OggS, you're crazy") page = OggPage.find_last(data, 0) self.failIf(page)
def test_find_last_invalid(self): data = BytesIO(b"if you think this is an Ogg, you're crazy") self.failUnlessRaises(OggError, OggPage.find_last, data, 0)
def test_not_enough_data(self): data = OggPage().write()[:-1] + b"\x01\x10" self.failUnlessRaises(OggError, OggPage, BytesIO(data))
def test_invalid_version(self): page = OggPage() OggPage(BytesIO(page.write())) page.version = 1 self.failUnlessRaises(OggError, OggPage, BytesIO(page.write()))
def test_complete_zero_length(self): packets = [b""] * 20 page = OggPage.from_packets(packets)[0] new_page = OggPage(BytesIO(page.write())) self.failUnlessEqual(new_page, page) self.failUnlessEqual(OggPage.to_packets([new_page]), packets)
def test_renumber(self): self.failUnlessEqual( [page.sequence for page in self.pages], [0, 1, 2]) fileobj = BytesIO() for page in self.pages: fileobj.write(page.write()) fileobj.seek(0) OggPage.renumber(fileobj, 1, 10) fileobj.seek(0) pages = [OggPage(fileobj) for i in range(3)] self.failUnlessEqual([page.sequence for page in pages], [10, 11, 12]) fileobj.seek(0) OggPage.renumber(fileobj, 1, 20) fileobj.seek(0) pages = [OggPage(fileobj) for i in range(3)] self.failUnlessEqual([page.sequence for page in pages], [20, 21, 22])
def test_invalid_not_first(self): page = OggPage(open(self.filename, "rb")) page.first = False self.failUnlessRaises(IOError, OggOpusInfo, BytesIO(page.write()))
def test_find_last_no_serial(self): pages = [OggPage() for i in xrange(10)] for i, page in enumerate(pages): page.sequence = i data = BytesIO(b"".join([page.write() for page in pages])) self.failUnless(OggPage.find_last(data, pages[0].serial + 1) is None)
def test_find_last_none_finishing(self): page = OggPage() page.position = -1 data = BytesIO(page.write()) assert OggPage.find_last(data, page.serial, finishing=True) is None