def test_overlaping_deletes(delete_index, single_first):
    original_snapshot = 'abcdefghijklmnopqrstuvwxyz'
    doc = Document(snapshot=original_snapshot)
    doc.HAS_EVENT_LOOP = False

    z_index = 14
    if delete_index >= 5 and delete_index < 15:
        z_index = 15
    if delete_index == 25:
        z_index = 15

    single_id = 'A' if single_first else 'B'
    range_id = 'B' if single_first else 'A'

    css_data = [
        ('sd', delete_index, 1, ['root'], single_id),
        ('sd', 5, 10, ['root'], range_id),  # delete 'fghijklmno'
        ('si', z_index, 'Z', ['A', 'B'], 'C'),

        ('sd', 10, 10, ['root'], '0'),  # delete 'klmnopqrst'
    ]

    css = build_changesets_from_tuples(css_data, doc)

    for cs in css:
        doc.receive_changeset(cs)

    resulting_snapshot = 'abcdeuvwxyZz'
    l = original_snapshot[delete_index]
    resulting_snapshot = resulting_snapshot.replace(l, '')

    assert doc.get_snapshot() == resulting_snapshot
def test_insert_within_many_overlaping_deletes():
    doc = Document(snapshot='abcdefghij')
    doc.HAS_EVENT_LOOP = False
    css_data = [
        ('si', 5, 'X', ['root'], 'A'),  # should result in abcdeXfghij
        ('sd', 4, 2, ['root'], 'B'),  # deletes 'ef'
        ('sd', 3, 4, ['root'], 'C'),  # deletes 'defg'
        ('si', 5, 'J', ['B', 'C'], 'D'),  # insert 'J' right before 'j'

        ('sd', 3, 4, ['root'], 'E')  # deletes 'defg'
    ]

    css = build_changesets_from_tuples(css_data, doc)

    for cs in css:
        doc.receive_changeset(cs)
    assert doc.get_snapshot() == 'abchiJj'
def test_insert_within_overlaping_deletes(insert_index, resulting_index,
                                          insert_first,
                                          low_index_in_0_branch):

    doc = Document(snapshot='abcdefghijklmnopqrstuvwxyz')
    doc.HAS_EVENT_LOOP = False

    first_delete_index = 10 if low_index_in_0_branch else 5
    zero_branch_index = 5 if low_index_in_0_branch else 10

    z_index = 16
    if insert_index > first_delete_index and \
       insert_index < first_delete_index + 10:
        z_index = 15
    if insert_index == 26:
        z_index = 15

    insert_id = 'A' if insert_first else 'B'
    delete_id = 'B' if insert_first else 'A'

    css_data = [
        ('si', insert_index, 'X', ['root'], insert_id),  # insert letter X
        ('sd', first_delete_index, 10, ['root'], delete_id),  # delete 'fghijklmno'
        ('si', z_index, 'Z', ['A', 'B'], 'C'),  # at a 'Z' right before the
                                                # existing 'z'

        ('sd', zero_branch_index, 10, ['root'], '0'),  # delete 'klmnopqrst'
    ]

    css = build_changesets_from_tuples(css_data, doc)

    for cs in css:
        doc.receive_changeset(cs)

    resulting_snapshot = 'abcdeuvwxyZz'
    if not resulting_index is None:
        rs = resulting_snapshot
        ri = resulting_index
        resulting_snapshot = rs[:ri] + 'X' + rs[ri:]
    assert doc.get_snapshot() == resulting_snapshot
    def test_hazard_for_insert_when_future_insert_is_deleted(self):
        doc = Document(snapshot="05IiYTALOC")
        doc.HAS_EVENT_LOOP = False

        css_data = [
            ("si", 8, "3Z", ["root"], "ba4"),  # 05IiYTAL 3Z OC
            ("si", 2, "XkGu", ["ba4"], "179"),  # 05 XkGu IiYTAL3ZOC
            ("si", 9, "Mpb", ["179"], "9b5"),  # 05XkGuIiY Mpb TAL3ZOC
            ("si", 18, "6wc2", ["9b5"], "133"),  # 05XkGuIiYMpbTAL3ZO 6wc2 C
            ("si", 4, "xUg", ["133"], "36f"),  # 05Xk xUg GuIiYMpbTAL3ZO6wc2C
            ("si", 4, "NdKa", ["36f"], "6ad"),
            # 05Xk NdKa xUgGuIiYMpbTAL3ZO6wc2C
            ("si", 15, "hE", ["6ad"], "ebe"),
            # 05XkNdKaxUgGuIi hE YMpbTAL3ZO6wc2C
            ("si", 23, "H7", ["ebe"], "2b6"),
            # 05XkNdKaxUgGuIihEYMpbTA H7 L3ZO6wc2C
            ("si", 34, "yD", ["2b6"], "c0c"),
            # 05XkNdKaxUgGuIihEYMpbTAH7L3ZO6wc2C yD
            ("sd", 5, 5, ["ba4"], "b31"),  # delete TAL3Z
            ("si", 4, "9R", ["b31"], "96a"),  # 05Ii 9R YOC
            ("sd", 2, 4, ["96a"], "74e"),  # delete Ii9R
            ("si", 1, "41", ["74e"], "2f0"),  # 0 41 5YOC
            ("si", 0, "oQmB", ["2f0"], "ffc"),  # oQmB 0415YOC
            ("sd", 2, 4, ["ffc"], "da8"),  # delete mB04
            ("si", 3, "rn", ["da8"], "36d"),  # oQ1 rn 5YOC
            ("si", 0, "qtWS", ["74e"], "d96"),  # qtWS 05YOC'
            ("si", 2, "Psj", ["d96"], "319"),  # qt Psj WS05YOC
            ("si", 6, "FV", ["319"], "20e"),  # qtPsjW FV S05YOC
            ("si", 9, "lJve", ["20e"], "5ef"),  # qtPsjWFVS lJve 05YOC
            ("si", 8, "zf8", ["5ef", "36d"], "c73"),  # oQ1rn5YO zf8 C
            ("sd", 29, 3, ["c0c", "c73"], "5f3"),
        ]

        self.css = build_changesets_from_tuples(css_data, doc)
        get_cs = self.get_cs

        doc.receive_changeset(self.css[0])
        assert doc.get_snapshot() == "05IiYTAL3ZOC"

        if True:
            cs = get_cs("179")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "05XkGuIiYTAL3ZOC"

            cs = get_cs("9b5")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "05XkGuIiYMpbTAL3ZOC"

            cs = get_cs("133")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "05XkGuIiYMpbTAL3ZO6wc2C"

            cs = get_cs("36f")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "05XkxUgGuIiYMpbTAL3ZO6wc2C"

            cs = get_cs("6ad")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "05XkNdKaxUgGuIiYMpbTAL3ZO6wc2C"

            cs = get_cs("ebe")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "05XkNdKaxUgGuIihEYMpbTAL3ZO6wc2C"

            cs = get_cs("2b6")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "05XkNdKaxUgGuIihEYMpbTAH7L3ZO6wc2C"

            cs = get_cs("c0c")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "05XkNdKaxUgGuIihEYMpbTAH7L3ZO6wc2CyD"

        cs = get_cs("b31")
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == "05XkNdKaxUgGuIihEYMpbO6wc2CyD"

        cs = get_cs("96a")
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == "05XkNdKaxUgGuIihE9RYMpbO6wc2CyD"

        cs = get_cs("74e")
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == "05XkNdKaxUgGuYMpbO6wc2CyD"

        if True:
            cs = get_cs("2f0")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "0415XkNdKaxUgGuYMpbO6wc2CyD"

            cs = get_cs("ffc")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "oQmB0415XkNdKaxUgGuYMpbO6wc2CyD"

            cs = get_cs("da8")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "oQ15XkNdKaxUgGuYMpbO6wc2CyD"

            cs = get_cs("36d")
            doc.receive_changeset(cs)
            assert doc.get_snapshot() == "oQ1rn5XkNdKaxUgGuYMpbO6wc2CyD"

        cs = get_cs("d96")
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == "oQ1rn5XkNdKaxUgGuYMpbO6wc2CyD"

        cs = get_cs("319")
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == "oQ1rn5XkNdKaxUgGuYMpbO6wc2CyD"

        cs = get_cs("20e")
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == "oQ1rn5XkNdKaxUgGuYMpbO6wc2CyD"

        cs = get_cs("5ef")
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == "oQ1rn5XkNdKaxUgGuYMpbO6wc2CyD"

        cs = get_cs("c73")
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == "oQ1rn5XkNdKaxUgGuYMpbO6wc2zf8CyD"
    def test_hazard_for_insert_with_future_overlapping_deletes(self):
        doc = Document(snapshot='WfjxUPBNyE')
        doc.HAS_EVENT_LOOP = False

        # Both dd8 and 64d delete the string '7j'. That overlap must be relayed
        # back to cs 98c.

        css_data = [
            ('si', 3, 'iu0I', ['root'], 'b3a'),  # Wfj iu0I xUPBNyE

            ('si', 12, 'p5Z', ['b3a'], '98c'),  # Wfjiu0IxUPBN p5Z yE
            ('sd', 1, 3, ['98c'], 'c3e'),  # delete fji
            ('si', 11, 'DRv', ['c3e'], '3c6'),  # Wu0IxUPBNp5 DRv ZyE
            ('si', 0, 'Tt9G', ['3c6'], 'bdd'),  # Tt9G Wu0IxUPBNp5DRvZyE
            ('si', 0, 'gkrY', ['bdd'], '44e'),  # gkrY Tt9GWu0IxUPBNp5DRvZyE
            ('si', 0, 'M', ['44e'], '79b'),  # M gkrYTt9GWu0IxUPBNp5DRvZyE

            ('si', 0, '7O', ['b3a'], 'fb7'),  # 7O Wfjiu0IxUPBNyE
            ('si', 14, 'ad', ['fb7'], '26f'),  # 7OWfjiu0IxUPBN ad yE
            ('si', 11, 'w8cK', ['26f'], '7c3'),  # 7OWfjiu0IxU w8cK PBNadyE
            ('si', 20, 'mb', ['7c3'], '810'),  # 7OWfjiu0IxUw8cKPBNad mb yE
            ('sd', 1, 3, ['810'], '254'),  # delete OWf

            ('si', 7, 'J1', ['254'], '39c'),  # 7jiu0Ix J1 Uw8cKPBNadmbyE
            ('sd', 19, 1, ['39c'], '4c6'),  # delete m
            ('si', 12, 'e4', ['4c6'], '44f'),  # 7jiu0IxJ1Uw8 e4 cKPBNadbyE
            ('si', 19, 'LV', ['44f'], 'b25'),  # 7jiu0IxJ1Uw8e4cKPBN LV adbyE
            ('sd', 0, 3, ['b25'], 'dd8'),  # delete 7ji
            ('si', 14, 'hH2s', ['dd8'], 'bac'),
            # u0IxJ1Uw8e4cKP hH2s BNLVadbyE

            ('sd', 0, 2, ['254'], '64d'),  # delete 7j

            ('si', 2, '6nA', ['bac', '64d'], '25f'),
            # u0 6nA IxJ1Uw8e4cKPhH2sBNLVadbyE
            ('sd', 7, 4, ['25f'], '35a'),
            # delete J1Uw
            ('si', 9, '3lSz', ['35a'], 'b0c'),
            # u06nAIx8e 3lSz 4cKPhH2sBNLVadbyE
            ('si', 21, 'CXqQ', ['b0c'], '017'),
            # u06nAIx8e3lSz4cKPhH2s CXqQ BNLVadbyE
            ('si', 26, 'Fo', ['017'], '68e'),
            # u06nAIx8e3lSz4cKPhH2sCXqQB Fo NLVadbyE

            ('sd', 23, 5, ['79b', '68e'], '895'),  # delete cKPhH
        ]

        self.css = build_changesets_from_tuples(css_data, doc)
        get_cs = self.get_cs

        for i in self.css[:7]:
            doc.receive_changeset(i)
        assert doc.get_snapshot() == 'MgkrYTt9GWu0IxUPBNp5DRvZyE'

        cs = get_cs('fb7')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'MgkrYTt9G7OWu0IxUPBNp5DRvZyE'

        cs = get_cs('26f')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'MgkrYTt9G7OWu0IxUPBNp5DRvZadyE'

        cs = get_cs('7c3')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'MgkrYTt9G7OWu0IxUw8cKPBNp5DRvZadyE'

        cs = get_cs('810')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'MgkrYTt9G7OWu0IxUw8cKPBNp5DRvZadmbyE'

        cs = get_cs('254')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'MgkrYTt9G7u0IxUw8cKPBNp5DRvZadmbyE'

        cs = get_cs('39c')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'MgkrYTt9G7u0IxJ1Uw8cKPBNp5DRvZadmbyE'

        cs = get_cs('4c6')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'MgkrYTt9G7u0IxJ1Uw8cKPBNp5DRvZadbyE'

        cs = get_cs('44f')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'MgkrYTt9G7u0IxJ1Uw8e4cKPBNp5DRvZadbyE'

        cs = get_cs('b25')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'MgkrYTt9G7u0IxJ1Uw8e4cKPBNp5DRvZLVadbyE'

        cs = get_cs('dd8')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'MgkrYTt9Gu0IxJ1Uw8e4cKPBNp5DRvZLVadbyE'

        cs = get_cs('bac')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == \
            'MgkrYTt9Gu0IxJ1Uw8e4cKPhH2sBNp5DRvZLVadbyE'

        cs = get_cs('64d')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == \
            'MgkrYTt9Gu0IxJ1Uw8e4cKPhH2sBNp5DRvZLVadbyE'

        cs = get_cs('25f')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == \
            'MgkrYTt9Gu06nAIxJ1Uw8e4cKPhH2sBNp5DRvZLVadbyE'

        cs = get_cs('35a')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == \
            'MgkrYTt9Gu06nAIx8e4cKPhH2sBNp5DRvZLVadbyE'

        cs = get_cs('b0c')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == \
            'MgkrYTt9Gu06nAIx8e3lSz4cKPhH2sBNp5DRvZLVadbyE'

        cs = get_cs('017')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == \
            'MgkrYTt9Gu06nAIx8e3lSz4cKPhH2sCXqQBNp5DRvZLVadbyE'

        cs = get_cs('68e')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == \
            'MgkrYTt9Gu06nAIx8e3lSz4cKPhH2sCXqQBFoNp5DRvZLVadbyE'

        cs = get_cs('895')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == \
            'MgkrYTt9Gu06nAIx8e3lSz42sCXqQBFoNp5DRvZLVadbyE'
    def test_expand_deletion_range(self):
        doc = Document(snapshot='HjpRFtZXW5')
        doc.HAS_EVENT_LOOP = False

        css_data = [
            ('si', 7, 'OeI', ['root'], 'c3c'),  # HjpRFtZ OeI XW5
            ('sd', 2, 5, ['c3c'], '950'),  # delete pRFtZ
            ('si', 2, 'Qx', ['950'], 'bf0'),  # Hj Qx OeIXW5
            ('sd', 2, 4, ['bf0'], '4c5'),  # delete QxOe
            ('si', 6, 'U6', ['4c5'], '61a'),  # HjIXW5 U6
            ('si', 3, 'AG', ['61a'], '1f0'),  # HjI AG XW5U6

            ('si', 3, 'qwEg', ['1f0'], '393'),  # HjI qwEg AGXW5U6
            ('si', 9, 'vsY', ['393'], '18d'),  # HjIqwEgAG vsY XW5U6
            ('si', 0, 'MiNV', ['18d'], '688'),  # MiNV HjIqwEgAGvsYXW5U6
            ('si', 20, 'L4n', ['688'], '796'),  # MiNVHjIqwEgAGvsYXW5U L4n 6
            ('si', 5, '9l', ['796'], 'b29'),  # MiNVH 9l jIqwEgAGvsYXW5UL4n6
            ('si', 1, 'k0Jf', ['b29'], 'e1a'),
            # M k0Jf iNVH9ljIqwEgAGvsYXW5UL4n6

            ('si', 8, 'd', ['e1a'], 'a23'),
            # Mk0JfiNV d H9ljIqwEgAGvsYXW5UL4n6

            ('sd', 3, 1, ['1f0'], '47a'),  # delete A
            ('sd', 0, 3, ['47a'], 'cc0'),  # delete HjI
            ('si', 4, 'K1DT', ['cc0'], 'd32'),  # GXW5 K1DT U6
            ('si', 5, 'b3oS', ['d32'], '175'),  # GXW5K b3oS 1DTU6
            ('si', 3, 'hm8z', ['175'], 'd28'),  # GXW hm8z 5Kb3oS1DTU6

            ('sd', 0, 5, ['1f0'], '997'),  # delete HjIAG
            ('si', 0, 'rBya', ['997'], '17a'),  # rBya XW5U6
            ('sd', 7, 1, ['17a'], '592'),  # delete U
            ('si', 8, 'cPu', ['592'], '893'),  # rByaXW56 cPu
            ('si', 1, 'C72', ['d28', '893'], 'b20'),
            # r C72 ByaXWhm8z5Kb3oS1DT6cPu

            ('sd', 37, 3, ['a23', 'b20'], '9e0'),  # delete 6cP
        ]

        self.css = build_changesets_from_tuples(css_data, doc)
        get_cs = self.get_cs

        for i in self.css[:13]:
            doc.receive_changeset(i)
        assert doc.get_snapshot() == 'Mk0JfiNVdH9ljIqwEgAGvsYXW5UL4n6'

        for i in self.css[13:18]:
            doc.receive_changeset(i)
        assert doc.get_snapshot() == 'Mk0JfiNVdqwEgGvsYXWhm8z5Kb3oS1DTUL4n6'

        cs = get_cs('997')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'Mk0JfiNVdvsYXWhm8z5Kb3oS1DTUL4n6'

        cs = get_cs('17a')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'Mk0JfiNVdvsYrByaXWhm8z5Kb3oS1DTUL4n6'

        cs = get_cs('592')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'Mk0JfiNVdvsYrByaXWhm8z5Kb3oS1DTL4n6'

        cs = get_cs('893')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'Mk0JfiNVdvsYrByaXWhm8z5Kb3oS1DTL4n6cPu'

        cs = get_cs('b20')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == \
            'Mk0JfiNVdvsYrC72ByaXWhm8z5Kb3oS1DTL4n6cPu'

        cs = get_cs('9e0')
        doc.receive_changeset(cs)
        assert doc.get_snapshot() == 'Mk0JfiNVdvsYrC72ByaXWhm8z5Kb3oS1DTL4nu'