[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/python-ffmpegio/python-ebml/master/test/test_container.py [Back]  [Original]

#pylint: disable=too-many-locals,no-self-use
#pylint: disable=too-many-public-methods,too-many-statements
"""
Element container tests.
"""

from .test import EbmlTest, UNK_ID

__all__ = ['ContainerTest']

class ContainerTest(EbmlTest):
    "Container tests."

    def make_test_container(self):
        """Return a container with elements from 5--10, 16--25, 33--40.

        The middle element is shrinkable to size 5.
        """
        from ebml.element import ElementMaster, ElementUnsupported, ElementVoid
        from ebml.atomic import ElementString
        elt = ElementMaster.new(UNK_ID)
        ElementVoid.of_size(5, elt, 0)
        ElementUnsupported.of_size(UNK_ID, 5, elt, 5)
        ElementVoid.of_size(6, elt, 10)
        ElementString.new_with_value(UNK_ID, '', elt, 16).resize_total(9)
        ElementVoid.of_size(8, elt, 25)
        ElementUnsupported.of_size(UNK_ID, 7, elt, 33)
        ElementVoid.of_size(8, elt, 40)
        elt.resize(48)
        return elt

    def check_child_pos(self, elt, *positions):
        "Check elements have the specified start and end positions."
        children = iter(elt)
        prev_child = None
        for start in positions:
            try:
                child = next(children)
            except StopIteration:
                child = None
            if prev_child is not None:
                self.assertEqual(prev_child.pos_end_relative, start)
            if child is not None:
                self.assertEqual(child.pos_relative, start)
            prev_child = child
        self.assertEqual(len(positions), len(elt) + 1)

    def test_1_containers(self):
        "Test Container methods."
        from ebml import Inconsistent
        from ebml.element import ElementVoid, ElementMaster, ElementUnsupported
        from ebml.atomic import ElementString, ElementUnicode
        from ebml.tags import MATROSKA_TAGS

        ebmlf = self.read_file_data()
        seg = ebmlf[1]
        elt = self.track_entry_elt(ebmlf)

        # Test end_last_child
        self.assertEqual(elt.end_last_child, elt.size)
        # Two elements starting at the same final position
        void = ElementVoid.of_size(20, elt, elt[-1].pos_relative)
        self.assertEqual(elt.end_last_child, void.pos_end_relative)
        elt.remove_child(void)

        # Test children_named, children_with_id
        self.assertEqual(list(seg.children_named('SeekHead')),
                         [seg[0], seg[2], seg[10], seg[12]])
        ebml_id = MATROSKA_TAGS['Void'].ebml_id
        self.assertEqual(list(seg.children_with_id(ebml_id)),
                         [seg[1], seg[7]])

        # Test children_in_region
        children = seg.children_in_region(seg[-1].pos_relative + 1)
        self.assertEqual(list(children), [])
        children = seg.children_in_region(seg[-2].pos_relative)
        self.assertEqual(list(children), seg[-2:])
        children = seg.children_in_region(seg[-2].pos_relative-1)
        self.assertEqual(list(children), seg[-2:])
        children = seg.children_in_region(seg[1].pos_relative,
                                          seg[1].total_size)
        self.assertEqual(list(children), seg[1:2])
        children = seg.children_in_region(seg[1].pos_relative,
                                          seg[1].total_size+1)
        self.assertEqual(list(children), seg[1:3])
        children = seg.children_in_region(seg[-2].pos_relative, 1000)
        self.assertEqual(list(children), seg[-2:])
        children = seg.children_in_region(0, seg[3].pos_relative, novoids=True)
        self.assertEqual(list(children), [seg[0], seg[2]])

        # Test adding and moving children
        void = ElementVoid.of_size(20)
        old_end = seg.end_last_child
        seg.add_child(void)
        self.assertIs(void.parent, seg)
        self.assertEqual(void.pos_relative, old_end)
        seg.remove_child(void)
        seg.add_child(void, 3)
        self.assertEqual(void.pos_relative, 3)
        seg.remove_child(void)
        elt = seg[3]
        seg.move_child(elt, 3)
        self.assertEqual(elt.pos_relative, 3)
        self.assertIs(seg[1], elt)
        seg.move_child(1, 24)
        self.assertEqual(elt.pos_relative, 24)
        self.assertIs(seg[2], elt)

        # Test find_gap()
        elt = ElementMaster.new(UNK_ID)
        # No children
        #self.assertEqual(elt.find_gap(100), (0, MAX_DATA_SIZE, None))
        self.assertEqual(elt.find_gap(100), None)
        self.assertEqual(elt.find_gap(100, region_size=150), (0, 150, None))
        self.assertEqual(elt.find_gap(100, region_size=50), None)
        ElementUnsupported.of_size(UNK_ID, 20, elt, 5)
        elt1 = ElementString.new_with_value(UNK_ID, 'abcde', elt, 31)
        elt1.resize_total(20)
        # gaps: 0--5, 25--31, 51--
        self.assertEqual(elt.find_gap(100, start=51, region_size=150),
                         (51, 150, None))
        # Gap at beginning
        self.assertEqual(elt.find_gap(5), (0, 5, None))
        self.assertEqual(elt.find_gap(5, start=25), None)
        self.assertEqual(elt.find_gap(5, start=25, region_size=35),
                         (51, 9, elt[1]))
        self.assertEqual(elt.find_gap(5, start=25, one_byte_ok=True),
                         (25, 6, None))
        # Gap in the middle
        self.assertEqual(elt.find_gap(6), (25, 6, elt[0]))
        self.assertEqual(elt.find_gap(5), (0, 5, None))
        # Gap at the end
        self.assertEqual(elt.find_gap(4, region_size=55), (51, 4, elt[1]))
        self.assertEqual(elt.find_gap(7), None)
        self.assertEqual(elt.find_gap(7, region_size=60), (51, 9, elt[1]))
        # No solution
        self.assertEqual(elt.find_gap(7, region_size=57), None)
        self.assertEqual(elt.find_gap(7, region_size=59), None)
        self.assertEqual(elt.find_gap(7, region_size=58),
                         (51, 7, elt[1]))
        # Several gaps: 0--5, 25--31, 51--55, 75--
        ElementUnsupported.of_size(UNK_ID, 20, elt, 55)
        self.assertEqual(elt.find_gap(3), (0, 5, None))
        self.assertEqual(elt.find_gap(3, one_byte_ok=True), (51, 4, elt[1]))
        self.assertEqual(elt.find_gap(4), (51, 4, elt[1]))
        self.assertEqual(elt.find_gap(5), (0, 5, None))
        self.assertEqual(elt.find_gap(5, start=10, one_byte_ok=True),
                         (25, 6, elt[0]))
        self.assertEqual(elt.find_gap(6), (25, 6, elt[0]))
        self.assertEqual(elt.find_gap(7), None)
        self.assertEqual(elt.find_gap(7, region_size=100), (75, 25, elt[2]))
        # Shrinking child: gaps 0--5, 25--31, 41--55, 75--
        self.assertEqual(elt.find_gap(4, shrink=True, one_byte_ok=True),
                         (0, 5, None))
        self.assertEqual(elt.find_gap(6, shrink=True), (25, 6, elt[0]))
        self.assertEqual(elt.find_gap(7, shrink=True), (41, 14, elt[1]))
        self.assertEqual(elt.find_gap(14, shrink=True), (41, 14, elt[1]))
        self.assertEqual(elt.find_gap(15, region_size=100, shrink=True),
                         (75, 25, elt[2]))

        # Test place_child()
        # No shrink necessary
        elt = self.make_test_container()
        child = ElementVoid.of_size(3)
        elt.place_child(child, shrink_child=False, shrink_previous=False,
                        grow_child=False)
        self.assertEqual((child.pos_relative, child.total_size), (0, 3))
        elt = self.make_test_container()
        child = ElementVoid.of_size(4)
        elt.place_child(child, shrink_child=False, shrink_previous=False,
                        grow_child=False)
        self.assertEqual((child.pos_relative, child.total_size), (10, 4))
        elt = self.make_test_container()
        child = ElementVoid.of_size(4)
        elt.place_child(child, shrink_child=False, shrink_previous=False,
                        grow_child=True)
        self.assertEqual((child.pos_relative, child.total_size), (0, 5))
        elt = self.make_test_container()
        child = ElementVoid.of_size(7)
        with self.assertRaises(Inconsistent):
            elt.place_child(child, region_size=40, shrink_child=False,
                            shrink_previous=False, grow_child=False)
        elt.place_child(child, shrink_child=False, shrink_previous=False,
                        grow_child=False)
        self.assertEqual((child.pos_relative, child.total_size), (40, 7))
        elt = self.make_test_container()
        child = ElementVoid.of_size(7)
        elt.place_child(child, shrink_child=False, shrink_previous=False,
                        grow_child=True)
        self.assertEqual((child.pos_relative, child.total_size), (25, 8))
        # Shrink child
        elt = self.make_test_container()
        child = ElementVoid.of_size(10)
        elt.place_child(child, shrink_child=True, shrink_previous=False,
                        grow_child=False)
        self.assertEqual((child.pos_relative, child.total_size), (0, 2))
        elt = self.make_test_container()
        child = ElementString.new_with_value(UNK_ID, 'a') # min size == 6
        child.resize_total(10)
        elt.place_child(child, shrink_child=True, shrink_previous=False,
                        grow_child=False)
        self.assertEqual((child.pos_relative, child.total_size), (10, 6))
        elt = self.make_test_container()
        child = ElementString.new_with_value(UNK_ID, 'ab') # min size == 7
        child.resize_total(10)
        elt.place_child(child, shrink_child=True, shrink_previous=False,
                        grow_child=False)
        self.assertEqual((child.pos_relative, child.total_size), (25, 8))
        elt = self.make_test_container()
        child = ElementString.new_with_value(UNK_ID, 'abcd') # min size == 9
        child.resize_total(10)
        with self.assertRaises(Inconsistent):
            elt.place_child(child, region_size=40, shrink_child=True,
                            shrink_previous=False, grow_child=False)
        elt.place_child(child, shrink_child=True, shrink_previous=False,
                        grow_child=False)
        self.assertEqual((child.pos_relative, child.total_size), (40, 10))
        # Shrink previous
        elt = self.make_test_container()
        child = ElementString.new_with_value(UNK_ID, 'abcd') # min size == 9
        elt.place_child(child, shrink_child=False, shrink_previous=True,
                        grow_child=False)
        self.assertEqual((child.pos_relative, child.total_size), (24, 9))
        self.assertEqual(elt.find(16).total_size, 8)
        elt = self.make_test_container()
        child = ElementString.new_with_value(UNK_ID, 'abcd') # min size == 9
        child.resize_total(10)
        elt.place_child(child, shrink_child=False, shrink_previous=True,
                        grow_child=False)
        self.assertEqual((child.pos_relative, child.total_size), (23, 10))
        self.assertEqual(elt.find(16).total_size, 7)
        elt = self.make_test_container()
        child = ElementString.new_with_value(UNK_ID, 'abcd') # min size == 9
        child.resize_total(10)
        elt.place_child(child, shrink_child=True, shrink_previous=True,
                        grow_child=False)
        self.assertEqual((child.pos_relative, child.total_size), (24, 9))
        self.assertEqual(elt.find(16).total_size, 8)
        elt = self.make_test_container()
        elt.remove_child(elt.find(16))
        ElementMaster.new(UNK_ID, elt, 16, size=2) # total size == 7
        # gap from 23 -- 33, shrinks to 22--33
        child = ElementString.new_with_value(UNK_ID, 'abcd')
        child.resize_total(11)
        with self.assertRaises(Inconsistent):
            # Won't find the gap with grow_child=False
            elt.place_child(child, region_size=40, shrink_child=False,
                            shrink_previous=True, grow_child=False)
        elt.place_child(child, shrink_child=False, shrink_previous=True,
                        grow_child=True)
        self.assertEqual((child.pos_relative, child.total_size), (22, 11))
        self.assertEqual(elt.find(16).total_size, 6)

        # Test get_overlapping()
        elt = self.make_test_container()
        self.assertEqual(elt.get_overlapping(), frozenset())
        # Negative position
        child = ElementUnicode.new_with_value('MuxingApp', 'abcd', elt, -1)
        self.assertEqual(elt.get_overlapping(), frozenset({child}))
        elt.add_child(child, -1)
        self.assertRaises(Inconsistent, elt.get_overlapping, ('MuxingApp', ))
        # Two fixed
        elt.add_child(child, 100)
        ElementUnicode.new_with_value('MuxingApp', 'efgh', elt, 105)
        self.assertRaises(Inconsistent, elt.get_overlapping, ('MuxingApp', ))
        # One fixed
        elt = self.make_test_container()
        result = frozenset({elt[0], elt[1], elt[2]})
        child = ElementUnicode.new_with_value('MuxingApp', 'abcd', elt, 2)
        child.resize_total(10)
        self.assertEqual(elt.get_overlapping(('MuxingApp',)), result)
        # None fixed
        elt = self.make_test_container()
        result = frozenset({elt[0], elt[1], elt[2]})
        child = ElementUnicode.new_with_value('MuxingApp', 'abcd', elt, 2)
        child.resize_total(10) # this one is largest
        self.assertEqual(elt.get_overlapping(), result)
        elt = self.make_test_container()
        child = ElementVoid.of_size(2, elt, 4) # this one is smallest
        self.assertEqual(elt.get_overlapping(), frozenset({child}))
        # One-byte gap
        elt = self.make_test_container()
        result = frozenset({elt[0]})
        elt[0].resize_total(4)
        self.assertEqual(elt.get_overlapping(), result)

    def test_2_rearrange(self):
        "Test Container.rearrange() and its relatives."
        from ebml.element import ElementMaster, ElementVoid, ElementUnsupported

        # -- Test rearrange_resize()
        # Already arranged
        elt = self.make_test_container()
        elt.resize(40)
        elt.rearrange_resize()
        self.check_child_pos(elt, 0, 5, 10, 16, 25, 33, 40)
        self.assertEqual(elt.size, 40)
        # Shrink
        elt = self.make_test_container()
        elt.resize(50)
        elt.rearrange_resize()
        self.check_child_pos(elt, 0, 5, 10, 16, 25, 33, 40)
        self.assertEqual(elt.size, 40)
        # Grow
        elt = self.make_test_container()
        elt.resize(30)
        elt.rearrange_resize()
        self.check_child_pos(elt, 0, 5, 10, 16, 25, 33, 40)
        self.assertEqual(elt.size, 40)
        # Grow because we're lazy
        elt = self.make_test_container()
        elt.resize(40)
        ElementUnsupported.of_size(UNK_ID, 15, elt, 24)
        elt.rearrange_resize()
        self.check_child_pos(elt, 0, 5, 10, 16, 24, 39, 46)
        self.assertEqual(elt.size, 46)
        # Grow because we're forced to
        elt = self.make_test_container()
        elt.resize(40)
        ElementUnsupported.of_size(UNK_ID, 35, elt, 0)
        elt.rearrange_resize(prefer_grow=False)
        self.check_child_pos(elt, 0, 35, 40, 45, 52)
        self.assertEqual(elt.size, 52)
        elt = self.make_test_container()
        elt.resize(16)
        elt.rearrange_resize(prefer_grow=False)
        self.check_child_pos(elt, 0, 5, 10, 17)
        self.assertEqual(elt.size, 17)
        # Add a Void at the end
        elt = self.make_test_container()
        elt.resize(50)
        elt.rearrange_resize(allow_shrink=False)
        self.check_child_pos(elt, 0, 5, 10, 16, 25, 33, 40, 50)
        self.assertEqual(elt.size, 50)
        elt = self.make_test_container()
        elt.resize(41)
        elt.rearrange_resize(allow_shrink=False)
        self.check_child_pos(elt, 0, 5, 10, 16, 25, 33, 40, 42)
        self.assertEqual(elt.size, 42)
        elt = self.make_test_container()
        elt.resize(20)
        elt.rearrange_resize(prefer_grow=False, allow_shrink=False)
        self.check_child_pos(elt, 0, 5, 10, 17, 20)
        self.assertEqual(elt.size, 20)
        elt = self.make_test_container()
        elt.resize(18)
        elt.rearrange_resize(prefer_grow=False, allow_shrink=False)
        self.check_child_pos(elt, 0, 5, 10, 17, 19)
        self.assertEqual(elt.size, 19)

        # -- Test rearrange() --
        # No children
        elt = ElementMaster.new(UNK_ID)
        ElementVoid.of_size(5, elt, 0)
        elt.rearrange()
        self.assertEqual(len(elt), 0)

        # Eliminate overlaps (part 1 of the algorithm)
        # Push everything forward
        elt = self.make_test_container()
        ElementUnsupported.of_size(UNK_ID, 35, elt, 0)
        elt.rearrange()
        self.check_child_pos(elt, 0, 35, 40, 49, 56)
        # Push first and second forward less
        elt = self.make_test_container()
        ElementUnsupported.of_size(UNK_ID, 24, elt, 0)
        elt.rearrange()
        self.check_child_pos(elt, 0, 24, 29, 38, 45)
        # Push first and second forward and shrink second
        elt = self.make_test_container()
        ElementUnsupported.of_size(UNK_ID, 23, elt, 0)
        elt.rearrange()
        self.check_child_pos(elt, 0, 23, 28, 33, 40)
        # Push first and second forward and shrink second less
        elt = self.make_test_container()
        ElementUnsupported.of_size(UNK_ID, 22, elt, 0)
        elt.rearrange()
        self.check_child_pos(elt, 0, 22, 27, 33, 40)
        # No need to shrink second
        elt = self.make_test_container()
        ElementUnsupported.of_size(UNK_ID, 19, elt, 0)
        elt.rearrange()
        self.check_child_pos(elt, 0, 19, 24, 33, 40)
        # Push first and second forward with 1-byte gap
        elt = self.make_test_container()
        ElementUnsupported.of_size(UNK_ID, 18, elt, 0)
        elt.rearrange()
        self.check_child_pos(elt, 0, 18, 23, 32, 39)
        # Push first and second forward with 4-byte gap
        elt = self.make_test_container()
        ElementUnsupported.of_size(UNK_ID, 15, elt, 0)
        elt.rearrange()
        self.check_child_pos(elt, 0, 15, 20, 29, 33, 40)
        # One-byte gap at beginning
        elt = self.make_test_container()
        ElementUnsupported.of_size(0x012233, 4, elt, 1)
        elt.rearrange()
        self.check_child_pos(elt, 0, 4, 9, 16, 25, 33, 40)

        # Fit in goal size (part 2 of the algorithm)
        # Everything already fits
        elt = self.make_test_container()
        elt.rearrange(40)
        self.check_child_pos(elt, 0, 5, 10, 16, 25, 33, 40)
        # One-byte gap
        elt = self.make_test_container()
        elt.rearrange(41)
        self.check_child_pos(elt, 0, 5, 10, 16, 25, 32)
        # Move last
        elt = self.make_test_container()
        elt.rearrange(39)
        self.check_child_pos(elt, 0, 5, 10, 16, 25, 32)
        elt = self.make_test_container()
        elt.rearrange(34)
        self.check_child_pos(elt, 0, 5, 10, 16, 25, 32)
        elt = self.make_test_container()
        elt.rearrange(32)
        self.check_child_pos(elt, 0, 5, 10, 16, 25, 32)
        # Move last with 1-byte gap (shrinks second)
        elt = self.make_test_container()
        elt.rearrange(33)
        self.check_child_pos(elt, 0, 5, 10, 16, 21, 28)
        # Move last and shrink second
        elt = self.make_test_container()
        elt.rearrange(31)
        self.check_child_pos(elt, 0, 5, 10, 16, 21, 28)
        elt = self.make_test_container()
        elt.rearrange(30)
        self.check_child_pos(elt, 0, 5, 10, 16, 21, 28)
        elt = self.make_test_container()
        elt.rearrange(28)
        self.check_child_pos(elt, 0, 5, 10, 16, 21, 28)
        # Move two last
        elt = self.make_test_container()
        elt.rearrange(29)
        self.check_child_pos(elt, 0, 5, 10, 15, 22)
        elt = self.make_test_container()
        elt.rearrange(27)
        self.check_child_pos(elt, 0, 5, 10, 15, 22)
        elt = self.make_test_container()
        elt.rearrange(24)
        self.check_child_pos(elt, 0, 5, 10, 15, 22)
        elt = self.make_test_container()
        elt.rearrange(22)
        self.check_child_pos(elt, 0, 5, 10, 15, 22)
        # Maximal shrink
        elt = self.make_test_container()
        elt.rearrange(23)
        self.check_child_pos(elt, 0, 5, 10, 17)
        elt = self.make_test_container()
        elt.rearrange(21)
        self.check_child_pos(elt, 0, 5, 10, 17)
        elt = self.make_test_container()
        elt.rearrange(17)
        self.check_child_pos(elt, 0, 5, 10, 17)
        # Nothing to do about the trailing 1-byte gap
        elt = self.make_test_container()
        elt.rearrange(18)
        self.check_child_pos(elt, 0, 5, 10, 17)
        # Doesn't fit
        elt = self.make_test_container()
        elt.rearrange(16)
        self.check_child_pos(elt, 0, 5, 10, 17)

        # Recursively rearrange (part 3 of the algorithm)
        elt = self.make_test_container()
        elt2 = self.make_test_container()
        elt.add_child(elt2, 7)
        elt.rearrange()
        self.check_child_pos(elt, 0, 5, 10, 63, 72, 79)
        self.check_child_pos(elt2, 0, 5, 10, 16, 25, 33, 40, 48)
        self.assertEqual(elt2.size, 48)
        elt = self.make_test_container()
        elt2 = self.make_test_container()
        elt.add_child(elt2, 7)
        elt.rearrange(0)
        self.check_child_pos(elt, 0, 5, 27, 32, 39)
        self.check_child_pos(elt2, 0, 5, 10, 17)
        self.assertEqual(elt2.size, 17)

        # Test expand_header() and element at negative position
        elt = self.make_test_container()
        size = elt.total_size
        elt.remove_child(0)
        elt.remove_child(-1)
        ElementUnsupported.of_size(UNK_ID, 5, elt, 0)
        elt.expand_header(4)
        self.assertEqual(elt.total_size, size)
        self.check_child_pos(elt, -3, 2, 7, 13, 22, 30, 37)
        elt.rearrange()
        self.check_child_pos(elt, 0, 5, 10, 13, 22, 30, 37)

Web Proxy Viewer  |  New URL  |  Original Page