def test_initial_dependency(self): doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False assert doc.get_open_changeset() == None assert doc.get_ordered_changesets() == [doc.get_root_changeset()] assert doc.get_dependencies() == [doc.get_root_changeset()]
def test_delete_overlaping_ranges_revered(self): """ Same opperations as previous test, but order of branches is reversed (B now before A) """ s = '0123456789' doc = Document(snapshot=s) doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() # construct branch A, which deletes all but the first three # and last three characters. A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=4, val=2)) A0.set_id('1A') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('sd', [], offset=3, val=2)) doc.receive_changeset(A1) A2 = Changeset(doc.get_id(), 'u1', [A1]) A2.add_op(Op('sd', [], offset=2, val=2)) doc.receive_changeset(A2) assert doc.get_snapshot() == '0189' # Branch B has common parent with A. It deletes all but '89' # User saw '0123456789' and deleted '3456' B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('sd', [], offset=3, val=4) B0.add_op(opB0) B0.set_id('0B') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index > b_index assert doc.get_snapshot() == '0189' # User saw '012789' and deleted '27' B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('sd', [], offset=2, val=2) B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == '0189' # Delete Range not known by branch A B2 = Changeset(doc.get_id(), 'u2', [B1]) opB2 = Op('sd', [], offset=1, val=2) B2.add_op(opB2) B2.set_id('B2') doc.receive_changeset(B2) assert doc.get_snapshot() == '09' # combine these braches again C = Changeset(doc.get_id(), 'u2', [A2, B2]) C.add_op(Op('si', [], offset=1, val='12345678')) doc.receive_changeset(C) assert doc.get_snapshot() == '0123456789'
def test_linear(self): doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() cs0 = Changeset(doc.get_id(), "dummyuser", [root]) doc.add_to_known_changesets(cs0) doc.insert_changeset_into_ordered_list(cs0) doc.update_unaccounted_changesets(cs0) assert root.get_unaccounted_changesets() == [] assert cs0.get_unaccounted_changesets() == [] cs1 = Changeset(doc.get_id(), "user1", [cs0]) doc.add_to_known_changesets(cs1) doc.insert_changeset_into_ordered_list(cs1) doc.update_unaccounted_changesets(cs1) assert root.get_unaccounted_changesets() == [] assert cs0.get_unaccounted_changesets() == [] assert cs1.get_unaccounted_changesets() == [] cs2 = Changeset(doc.get_id(), "user1", [cs1]) doc.add_to_known_changesets(cs2) doc.insert_changeset_into_ordered_list(cs2) doc.update_unaccounted_changesets(cs2) assert root.get_unaccounted_changesets() == [] assert cs0.get_unaccounted_changesets() == [] assert cs1.get_unaccounted_changesets() == [] assert cs2.get_unaccounted_changesets() == []
def test_delete_overlaping_ranges2_reversed(self): """ Same opperations as previous test, but order of branches is reversed (B now before A) """ s = '0123456789TARGET' doc = Document(snapshot=s) doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() # branch deletes the '234567' in three ops. A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=4, val=2)) A0.set_id('1A0') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('sd', [], offset=3, val=2)) A1.set_id('A1') doc.receive_changeset(A1) A2 = Changeset(doc.get_id(), 'u1', [A1]) A2.add_op(Op('sd', [], offset=2, val=2)) A2.set_id('A2') doc.receive_changeset(A2) assert doc.get_snapshot() == '0189TARGET' # Branch B has common parent with A. It deletes all but # 'TARGET' in three ops. # User Saw '0123456789TARGET', deleted '234', which branch A # already did. B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('sd', [], offset=2, val=3) B0.add_op(opB0) B0.set_id('0B0') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index > b_index assert doc.get_snapshot() == '0189TARGET' # User Saw '0156789TARGET', deleted '567', which branch A # already did. B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('sd', [], offset=2, val=3) B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == '0189TARGET' # User Saw '0189TARGET', deleted '0189', which branch A has # NOT done. B2 = Changeset(doc.get_id(), 'u2', [B1]) opB2 = Op('sd', [], offset=0, val=4) B2.add_op(opB2) B2.set_id('B2') doc.receive_changeset(B2) assert doc.get_snapshot() == 'TARGET'
def test_missing_changesets(self): doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False assert doc.missing_changesets == set([]) assert doc.pending_new_changesets == [] root = doc.get_root_changeset() A = Changeset(doc.get_id(), "dummyuser", [root]) doc.receive_changeset(A) assert doc.missing_changesets == set([]) assert doc.pending_new_changesets == [] # Just one Changeset gets put in pending list B = Changeset(doc.get_id(), "user1", ["C"]) B.set_id("B") doc.receive_changeset(B) assert doc.get_ordered_changesets() == [root, A] assert doc.missing_changesets == set(["C"]) assert doc.pending_new_changesets == [B] C = Changeset(doc.get_id(), "user1", [A]) C.set_id("C") doc.receive_changeset(C) assert doc.missing_changesets == set([]) assert doc.pending_new_changesets == [] assert B.get_parents() == [C] assert doc.get_ordered_changesets() == [root, A, C, B] # Now a string of changesets put on pending list D = Changeset(doc.get_id(), "user1", ["G"]) D.set_id("D") doc.receive_changeset(D) assert doc.missing_changesets == set(["G"]) assert doc.pending_new_changesets == [D] assert doc.get_ordered_changesets() == [root, A, C, B] E = Changeset(doc.get_id(), "user1", ["D"]) E.set_id("E") doc.receive_changeset(E) assert E.get_parents() == [D] assert doc.missing_changesets == set(["G"]) assert doc.pending_new_changesets == [D, E] assert doc.get_ordered_changesets() == [root, A, C, B] F = Changeset(doc.get_id(), "user1", ["E"]) F.set_id("F") doc.receive_changeset(F) assert doc.missing_changesets ==set( ["G"]) assert doc.pending_new_changesets == [D, E, F] assert doc.get_ordered_changesets() == [root, A, C, B] G = Changeset(doc.get_id(), "user1", ["C"]) G.set_id("G") doc.receive_changeset(G) assert doc.missing_changesets == set([]) assert doc.pending_new_changesets == [] assert doc.get_ordered_changesets() == [root, A, C, B, G, D, E, F] assert doc.get_ordered_changesets() == doc.tree_to_list()
def test_two_deletes_in_first_branch_reverse(self): """ Same opperations as previous test, but order of branches is reversed (B now before A) """ s = 'ab123cd456gh789ik' doc = Document(snapshot=s) doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=7, val=2)) A0.set_id('1A') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('sd', [], offset=10, val=3)) doc.receive_changeset(A1) A2 = Changeset(doc.get_id(), 'u1', [A1]) A2.add_op(Op('si', [], offset=7, val='ef')) doc.receive_changeset(A2) assert doc.get_snapshot() == 'ab123cdef6ghik' # Branch B has common parent with A. First it deletes a # partialy overlaping range in A B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('sd', [], offset=8, val=2) B0.add_op(opB0) B0.set_id('0B') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index > b_index assert doc.get_snapshot() == 'ab123cdefghik' # Delete range partially overlaping range in A B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('sd', [], offset=10, val=2) B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == 'ab123cdefghik' # Delete Range unaffected by branch A B2 = Changeset(doc.get_id(), 'u2', [B1]) opB2 = Op('sd', [], offset=2, val=3) B2.add_op(opB2) B2.set_id('B2') doc.receive_changeset(B2) assert doc.get_snapshot() == 'abcdefghik' # combine these braches again C = Changeset(doc.get_id(), 'u2', [A2, B2]) C.add_op(Op('si', [], offset=9, val='j')) doc.receive_changeset(C) assert doc.get_snapshot() == 'abcdefghijk'
def test_two_deletes_in_first_branch(self): """ 01234567890123456 (helpful index of characters in doc)""" s = 'ab123cd456gh789ik' doc = Document(snapshot=s) doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() # construct branch A, which has two string deletes, then # adds text A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=7, val=2)) A0.set_id('A') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('sd', [], offset=10, val=3)) doc.receive_changeset(A1) A2 = Changeset(doc.get_id(), 'u1', [A1]) A2.add_op(Op('si', [], offset=7, val='ef')) doc.receive_changeset(A2) assert doc.get_snapshot() == 'ab123cdef6ghik' # Branch B has common parent with A. First it deletes a # partialy overlaping range in A B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('sd', [], offset=8, val=2) B0.add_op(opB0) B0.set_id('B') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index < b_index assert doc.get_snapshot() == 'ab123cdefghik' # Delete range partially overlaping range in A B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('sd', [], offset=10, val=2) B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == 'ab123cdefghik' # Delete Range unaffected by branch A B2 = Changeset(doc.get_id(), 'u2', [B1]) opB2 = Op('sd', [], offset=2, val=3) B2.add_op(opB2) B2.set_id('B2') doc.receive_changeset(B2) assert doc.get_snapshot() == 'abcdefghik' # combine these braches again C = Changeset(doc.get_id(), 'u2', [A2, B2]) C.add_op(Op('si', [], offset=9, val='j')) doc.receive_changeset(C) assert doc.get_snapshot() == 'abcdefghijk'
def test_one_delete_in_first_branch(self): """ There is one delete in the first branch, multiple in branch B, then each has more string inserts. """ doc = Document(snapshot='123abcde789') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() # construct branch A, which begins with a string delete, then # adds text A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=3, val=5)) A0.set_id('A') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('si', [], offset=3, val='456')) doc.receive_changeset(A1) assert doc.get_snapshot() == '123456789' # Branch B has common parent with A. B has three deletes, some of which # overlap the delete in branch A B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('sd', [], offset=4, val=2) B0.add_op(opB0) B0.set_id('B') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index < b_index assert doc.get_snapshot() == '123456789' # Partially overlaping delete B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('sd', [], offset=6, val=2) B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == '1234569' # Delete Range unaffected by branch A B2 = Changeset(doc.get_id(), 'u2', [B1]) opB2 = Op('sd', [], offset=1, val=1) B2.add_op(opB2) B2.set_id('B2') doc.receive_changeset(B2) assert doc.get_snapshot() == '134569' # combine these braches again C = Changeset(doc.get_id(), 'u2', [A1, B2]) C.add_op(Op('si', [], offset=1, val='2')) C.add_op(Op('si', [], offset=6, val='78')) doc.receive_changeset(C) assert doc.get_snapshot() == '123456789'
def test_overlaping_deletes_then_string_insert_reversed(self): """ Same test as the previous one, except the order of the branches is reversed. """ s = 'ZZZZZZZAAAAAAAAAAAAAAAAAAAAAAAAAXXXXX' doc = Document(snapshot=s) doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=0, val=32)) A0.add_op(Op('si', [], offset=0, val='T')) A0.set_id('2') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('si', [], offset=1, val="h")) A1.add_op(Op('si', [], offset=2, val="e")) A1.add_op(Op('si', [], offset=3, val=" ")) A1.set_id('A1') doc.receive_changeset(A1) A2 = Changeset(doc.get_id(), 'u1', [A1]) A2.add_op(Op('si', [], offset=4, val="Q")) A2.add_op(Op('si', [], offset=5, val="u")) A2.add_op(Op('si', [], offset=6, val="i")) A2.set_id('A2') doc.receive_changeset(A2) A3 = Changeset(doc.get_id(), 'u1', [A2]) A3.add_op(Op('si', [], offset=7, val="c")) A3.add_op(Op('si', [], offset=8, val="k")) A3.add_op(Op('si', [], offset=9, val=" ")) A3.set_id('A3') doc.receive_changeset(A3) assert doc.get_snapshot() == 'The Quick XXXXX' B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('sd', [], offset=7, val=30) B0.add_op(opB0) B0.set_id('1') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index > b_index assert doc.get_snapshot() == 'The Quick ' B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('si', [], offset=7, val='Brown Fox.') B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == 'Brown Fox.The Quick '
def test_multiple_css_with_same_multiple_dependencies(self): """ A -- B -- D--F -- G \ \/ / \ /\ / - C--E- Both F and E depend on D and C """ doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() A = Changeset(doc.get_id(), "user0", [root]) A.set_id('a') doc.receive_changeset(A) assert doc.get_ordered_changesets() == [root, A] assert doc.get_ordered_changesets() == doc.tree_to_list() B = Changeset(doc.get_id(), "user1", [A]) B.set_id('b') doc.receive_changeset(B) assert doc.get_ordered_changesets() == [root, A, B] assert doc.get_ordered_changesets() == doc.tree_to_list() C = Changeset(doc.get_id(), "user3", [B]) C.set_id('c') doc.receive_changeset(C) assert doc.get_ordered_changesets() == [root, A, B, C] assert doc.get_ordered_changesets() == doc.tree_to_list() D = Changeset(doc.get_id(), "user4", [B]) D.set_id('d') doc.receive_changeset(D) assert doc.get_ordered_changesets() == [root, A, B, C, D] assert doc.get_ordered_changesets() == doc.tree_to_list() E = Changeset(doc.get_id(), "user5", [C, D]) E.set_id('e') doc.receive_changeset(E) assert doc.get_ordered_changesets() == [root, A, B, C, D, E] assert doc.get_ordered_changesets() == doc.tree_to_list() F = Changeset(doc.get_id(), "user6", [C, D]) F.set_id('f') doc.receive_changeset(F) assert set(doc.get_dependencies()) == set([E,F]) assert doc.get_ordered_changesets() == [root, A,B,C,D,E,F] assert doc.get_ordered_changesets() == doc.tree_to_list() G = Changeset(doc.get_id(), "user5", [E,F]) doc.receive_changeset(G) assert doc.get_dependencies() == [G] assert doc.get_ordered_changesets() == [root, A, B, C, D, E, F, G] assert doc.get_ordered_changesets() == doc.tree_to_list()
def test_sequential_changeset(self): doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() cs0 = Changeset(doc.get_id(), "dummyuser", [root]) rid = root.get_id() assert doc.receive_changeset(cs0) assert rid == doc.get_root_changeset().get_id() assert root.get_children() == [cs0] assert doc.get_dependencies() == [cs0] assert doc.get_ordered_changesets() == [root, cs0] cs1 = Changeset(doc.get_id(), "user1", [cs0]) assert doc.receive_changeset(cs1) assert doc.get_ordered_changesets() == [root, cs0, cs1] assert doc.get_dependencies() == [cs1] cs2 = Changeset(doc.get_id(), "user1", [cs1]) assert doc.receive_changeset(cs2) assert doc.get_ordered_changesets() == [root, cs0, cs1, cs2] assert doc.get_dependencies() == [cs2] assert doc.get_ordered_changesets() == doc.tree_to_list()
def test_one_delete_in_first_branch_reversed(self): """ Same opperations as previous test, but order of branches is reversed (B now before A) """ doc = Document(snapshot='123abcde789') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=3, val=5)) A0.set_id('1A') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('si', [], offset=3, val='456')) doc.receive_changeset(A1) B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('sd', [], offset=4, val=2) B0.add_op(opB0) B0.set_id('0B') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index > b_index assert doc.get_snapshot() == '123456789' B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('sd', [], offset=6, val=2) B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == '1234569' B2 = Changeset(doc.get_id(), 'u2', [B1]) opB2 = Op('sd', [], offset=1, val=1) B2.add_op(opB2) B2.set_id('B2') doc.receive_changeset(B2) assert doc.get_snapshot() == '134569' # combine these braches again C = Changeset(doc.get_id(), 'u2', [A1, B2]) C.add_op(Op('si', [], offset=1, val='2')) C.add_op(Op('si', [], offset=6, val='78')) doc.receive_changeset(C) assert doc.get_snapshot() == '123456789'
def test_multiple_dependencies(self): """ -- B ---- E / / root -- A -- D \ / -- C -- """ doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() B = Changeset(doc.get_id(), "user0", [root]) B.set_id('b') doc.receive_changeset(B) A = Changeset(doc.get_id(), "user1", [root]) A.set_id('a') doc.receive_changeset(A) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [A] C = Changeset(doc.get_id(), "user2", [root]) C.set_id('c') doc.receive_changeset(C) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [A] assert C.get_unaccounted_changesets() == [A,B] # test_multiple_dependencies_common_base D = Changeset(doc.get_id(), "user0", [C,A]) D.set_id('d') doc.receive_changeset(D) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [A] assert C.get_unaccounted_changesets() == [A,B] assert D.get_unaccounted_changesets() == [B] E = Changeset(doc.get_id(), 'user1', [B, D]) E.set_id('e') doc.receive_changeset(E) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [A] assert C.get_unaccounted_changesets() == [A,B] assert D.get_unaccounted_changesets() == [B] assert E.get_unaccounted_changesets() == []
def setup_method(self, method): doc = Document(snapshot='0123') doc.HAS_EVENT_LOOP = False self.doc = doc root = doc.get_root_changeset() # A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('si', [], offset=1, val='ab')) self.A0 = A0 B0 = Changeset(doc.get_id(), 'u2', [root]) B0.add_op(Op('si', [], offset=1, val='cd')) self.B0 = B0 A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('sd', [], offset=2, val=2)) self.A1 = A1
def test_multiple_dependencies(self): """ -- B ---- E / / root -- A -- D \ / -- C -- """ doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() B = Changeset(doc.get_id(), "user0", [root]) B.set_id('b') doc.receive_changeset(B) A = Changeset(doc.get_id(), "user1", [root]) A.set_id('a') doc.receive_changeset(A) assert set(doc.get_dependencies()) == set([B,A]) assert doc.get_ordered_changesets() == [root, A, B] C = Changeset(doc.get_id(), "user2", [root]) C.set_id('c') doc.receive_changeset(C) assert set(doc.get_dependencies()) == set([B,A,C]) assert doc.get_ordered_changesets() == [root, A, B, C] assert doc.get_ordered_changesets() == doc.tree_to_list() # test_multiple_dependencies_common_base D = Changeset(doc.get_id(), "user0", [C,A]) D.set_id('d') doc.receive_changeset(D) assert set(doc.get_dependencies()) == set([B,D]) assert doc.get_ordered_changesets() == [root, A, B, C, D] assert doc.get_ordered_changesets() == doc.tree_to_list() E = Changeset(doc.get_id(), 'user1', [B, D]) E.set_id('e') doc.receive_changeset(E) assert doc.get_dependencies() == [E] assert doc.get_ordered_changesets() == [root, A, B, C, D, E] assert doc.get_ordered_changesets() == doc.tree_to_list()
def setup_method(self, method): doc = Document(snapshot='0123') doc.HAS_EVENT_LOOP = False self.doc = doc root = doc.get_root_changeset() # A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('si', [], offset=1, val='ab')) self.A0 = A0 B0 = Changeset(doc.get_id(), 'u2', [root]) B0.add_op(Op('si', [], offset=1, val='cd')) self.B0 = B0 # instead of deleting range, A will delete character one at a time. A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('sd', [], offset=2, val=1)) A1.add_op(Op('sd', [], offset=2, val=1)) self.A1 = A1
def test_delete_in_second_branch(self): """ """ doc = Document(snapshot='abcdefghij') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() # construct branch A, which begins with a string delete A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=5, val=5)) A0.set_id('2A') doc.receive_changeset(A0) assert doc.get_snapshot() == 'abcde' # Branch B has common parent with A. It inserts strings at the end # which should not be deleted. B0 = Changeset(doc.get_id(), 'u2', [root]) for i in xrange(10): op = Op('si', [], offset=10 + i, val=str(i)) B0.add_op(op) B0.set_id('1B') doc.receive_changeset(B0) assert doc.get_snapshot() == 'abcde0123456789'
def test_complex_tree(self): """ Some complex tree. C -- G -- H -------- K / / \ A -- B -- D -- F -- J -- L -- M-- \ / E --- I Should be: A B C G D E I F H K J L M """ doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() A = Changeset(doc.get_id(), "user0", [root]) A.set_id('A') doc.receive_changeset(A) assert doc.get_ordered_changesets() == [root, A] assert doc.get_ordered_changesets() == doc.tree_to_list() B = Changeset(doc.get_id(),"user1",[A]) B.set_id('b') doc.receive_changeset(B) assert doc.get_ordered_changesets() == [root,A,B] assert doc.get_ordered_changesets() == doc.tree_to_list() C = Changeset(doc.get_id(),"user3",[B]) C.set_id('c') doc.receive_changeset(C) assert doc.get_ordered_changesets() == [root,A,B,C] assert doc.get_ordered_changesets() == doc.tree_to_list() D = Changeset(doc.get_id(),"user4",[B]) D.set_id('d') doc.receive_changeset(D) assert doc.get_ordered_changesets() == [root,A,B,C,D] assert doc.get_ordered_changesets() == doc.tree_to_list() E = Changeset(doc.get_id(),"user5",[D]) E.set_id('e') doc.receive_changeset(E) assert doc.get_ordered_changesets() == [root,A,B,C,D,E] assert doc.get_ordered_changesets() == doc.tree_to_list() F = Changeset(doc.get_id(),"user6",[D]) F.set_id('f') doc.receive_changeset(F) assert doc.get_ordered_changesets() == [root,A,B,C,D,E,F] assert doc.get_ordered_changesets() == doc.tree_to_list() G = Changeset(doc.get_id(),"user5",[C]) G.set_id('g') doc.receive_changeset(G) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,F] assert doc.get_ordered_changesets() == doc.tree_to_list() H = Changeset(doc.get_id(),"user5",[G,F]) H.set_id('h') doc.receive_changeset(H) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,F,H] assert doc.get_ordered_changesets() == doc.tree_to_list() I = Changeset(doc.get_id(),"user6",[E]) I.set_id('i') doc.receive_changeset(I) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,I,F,H] assert doc.get_ordered_changesets() == doc.tree_to_list() J = Changeset(doc.get_id(),"user5",[I,F]) J.set_id('j') doc.receive_changeset(J) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,I,F,H,J] assert doc.get_ordered_changesets() == doc.tree_to_list() K = Changeset(doc.get_id(),"user5",[H]) K.set_id('k') doc.receive_changeset(K) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,I,F,H,K,J] assert doc.get_ordered_changesets() == doc.tree_to_list() L = Changeset(doc.get_id(),"user5",[J]) L.set_id('l') doc.receive_changeset(L) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,I,F,H,K,J,L] assert doc.get_ordered_changesets() == doc.tree_to_list() M = Changeset(doc.get_id(),"user5",[K,L]) M.set_id('m') doc.receive_changeset(M) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,I,F,H,K,J,L,M] assert doc.get_ordered_changesets() == doc.tree_to_list()
class TestArraysInTwoBranches: def setup_method(self, method): s1 = ['ABCD', 'EFGH', 'IJKL', 'MNOP', 'QRST', 'UVWX', 'YZ'] self.doc1 = Document(snapshot=s1) self.doc1.HAS_EVENT_LOOP = False self.root1 = self.doc1.get_root_changeset() def test_one_delete_in_first_branch(self): """ There is one delete in the first branch, multiple in branch B, then each has more string inserts. """ doc = self.doc1 root = self.root1 # construct branch A, which begins with a string delete, then # adds text A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('ad', [], offset=3, val=2)) A0.set_id('A') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) v1 = ['0123', '4567'] A1.add_op(Op('ai', [], offset=3, val=v1)) doc.receive_changeset(A1) result = ['ABCD', 'EFGH', 'IJKL', '0123', '4567', 'UVWX', 'YZ'] assert doc.get_snapshot() == result # Branch B has common parent with A. B has three deletes, some of which # overlap the delete in branch A B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('ad', [], offset=2, val=2) B0.add_op(opB0) B0.set_id('B') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index < b_index assert opB0.t_offset == 2 assert opB0.t_val == 1 result = ['ABCD', 'EFGH', '0123', '4567', 'UVWX', 'YZ'] assert doc.get_snapshot() == result # Partially overlaping delete B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('ad', [], offset=2, val=1) B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) result = ['ABCD', 'EFGH', '0123', '4567', 'UVWX', 'YZ'] assert doc.get_snapshot() == result assert opB1.t_val == 0 assert opB1.is_noop() # Delete Range unaffected by branch A B2 = Changeset(doc.get_id(), 'u2', [B1]) opB2 = Op('ad', [], offset=1, val=1) B2.add_op(opB2) B2.set_id('B2') doc.receive_changeset(B2) result = ['ABCD', '0123', '4567', 'UVWX', 'YZ'] assert doc.get_snapshot() == result assert opB2.t_offset == 1 assert opB2.t_val == 1 # Insert before the Delete Range B3 = Changeset(doc.get_id(), 'u2', [B2]) vB3 = ['BBBBB', 'CCCCC'] opB3 = Op('ai', [], offset=1, val=vB3) B3.add_op(opB3) B3.set_id('B3') doc.receive_changeset(B3) result = ['ABCD', '0123', '4567', 'BBBBB', 'CCCCC', 'UVWX', 'YZ'] assert doc.get_snapshot() == result # Insert After the Delete Range B4 = Changeset(doc.get_id(), 'u2', [B3]) vB4 = ['DDDDD', 'EEEEE'] opB4 = Op('ai', [], offset=3, val=vB4) B4.add_op(opB4) B4.set_id('B4') doc.receive_changeset(B4) result = ['ABCD', '0123', '4567', 'BBBBB', 'CCCCC', 'DDDDD', 'EEEEE', 'UVWX', 'YZ'] assert doc.get_snapshot() == result def test_one_delete_in_first_branch_reversed(self): """ Same test as above, except branch B gets applied before branch A. """ doc = self.doc1 root = self.root1 # construct branch A, which begins with a string delete, then # adds text A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('ad', [], offset=3, val=2)) A0.set_id('1A') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) v1 = ['0123', '4567'] A1.add_op(Op('ai', [], offset=3, val=v1)) doc.receive_changeset(A1) result = ['ABCD', 'EFGH', 'IJKL', '0123', '4567', 'UVWX', 'YZ'] assert doc.get_snapshot() == result # Branch B has common parent with A. B has three deletes, some of which # overlap the delete in branch A B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('ad', [], offset=2, val=2) B0.add_op(opB0) B0.set_id('0B') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index > b_index result = ['ABCD', 'EFGH', '0123', '4567', 'UVWX', 'YZ'] assert doc.get_snapshot() == result # Partially overlaping delete B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('ad', [], offset=2, val=1) B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) result = ['ABCD', 'EFGH', '0123', '4567', 'UVWX', 'YZ'] assert doc.get_snapshot() == result # Delete Range unaffected by branch A B2 = Changeset(doc.get_id(), 'u2', [B1]) opB2 = Op('ad', [], offset=1, val=1) B2.add_op(opB2) B2.set_id('B2') doc.receive_changeset(B2) result = ['ABCD', '0123', '4567', 'UVWX', 'YZ'] assert doc.get_snapshot() == result B3 = Changeset(doc.get_id(), 'u2', [B2]) vB3 = ['BBBBB', 'CCCCC'] opB3 = Op('ai', [], offset=1, val=vB3) B3.add_op(opB3) B3.set_id('B3') doc.receive_changeset(B3) result = ['ABCD', 'BBBBB', 'CCCCC', '0123', '4567', 'UVWX', 'YZ'] assert doc.get_snapshot() == result B4 = Changeset(doc.get_id(), 'u2', [B3]) vB4 = ['DDDDD', 'EEEEE'] opB4 = Op('ai', [], offset=3, val=vB4) B4.add_op(opB4) B4.set_id('B4') doc.receive_changeset(B4) result = ['ABCD', 'BBBBB', 'CCCCC', 'DDDDD', 'EEEEE', '0123', '4567', 'UVWX', 'YZ'] assert doc.get_snapshot() == result def test_consecutive_inserts(self): doc = self.doc1 root = self.root1 # Branch A A0 = Changeset(doc.get_id(), 'u1', [root]) vA0 = ['1', '2'] A0.add_op(Op('ai', [], offset=2, val=vA0)) A0.set_id('A') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) vA1 = ['3', '4'] A1.add_op(Op('ai', [], offset=4, val=vA1)) doc.receive_changeset(A1) A2 = Changeset(doc.get_id(), 'u1', [A1]) vA2 = ['8', '9'] A2.add_op(Op('ai', [], offset=9, val=vA2)) doc.receive_changeset(A2) A3 = Changeset(doc.get_id(), 'u1', [A2]) vA3 = ['0'] A3.add_op(Op('ai', [], offset=11, val=vA3)) doc.receive_changeset(A3) result = ['ABCD', 'EFGH', '1', '2', '3', '4', 'IJKL', 'MNOP', 'QRST', '8', '9', '0', 'UVWX', 'YZ'] assert doc.get_snapshot() == result # Now B has a series of inserts B0 = Changeset(doc.get_id(), 'u1', [root]) vB0 = ['1b', '2b'] B0.add_op(Op('ai', [], offset=1, val=vB0)) B0.set_id('B') doc.receive_changeset(B0) result = ['ABCD', '1b', '2b', 'EFGH', '1', '2', '3', '4', 'IJKL', 'MNOP', 'QRST', '8', '9', '0', 'UVWX', 'YZ'] assert doc.get_snapshot() == result B1 = Changeset(doc.get_id(), 'u1', [B0]) vB1 = ['3b', '4b'] B1.add_op(Op('ai', [], offset=5, val=vB1)) doc.receive_changeset(B1) result = ['ABCD', '1b', '2b', 'EFGH', '1', '2', '3', '4', 'IJKL', '3b', '4b', 'MNOP', 'QRST', '8', '9', '0', 'UVWX', 'YZ'] assert doc.get_snapshot() == result B2 = Changeset(doc.get_id(), 'u1', [B1]) vB2 = ['8b', '9b', '0b'] B2.add_op(Op('ai', [], offset=7, val=vB2)) doc.receive_changeset(B2) result = ['ABCD', '1b', '2b', 'EFGH', '1', '2', '3', '4', 'IJKL', '3b', '4b', '8b', '9b', '0b', 'MNOP', 'QRST', '8', '9', '0', 'UVWX', 'YZ'] assert doc.get_snapshot() == result B3 = Changeset(doc.get_id(), 'u1', [B2]) vB3 = ['BBBB'] B3.add_op(Op('ai', [], offset=12, val=vB3)) doc.receive_changeset(B3) result = ['ABCD', '1b', '2b', 'EFGH', '1', '2', '3', '4', 'IJKL', '3b', '4b', '8b', '9b', '0b', 'MNOP', 'QRST', '8', '9', '0', 'BBBB', 'UVWX', 'YZ'] assert doc.get_snapshot() == result def test_consecutive_inserts_reversed(self): """ Same as the previous test except branch B gets applied before branch A. """ doc = self.doc1 root = self.root1 # Branch A A0 = Changeset(doc.get_id(), 'u1', [root]) vA0 = ['1', '2'] A0.add_op(Op('ai', [], offset=2, val=vA0)) A0.set_id('1A') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) vA1 = ['3', '4'] A1.add_op(Op('ai', [], offset=4, val=vA1)) doc.receive_changeset(A1) A2 = Changeset(doc.get_id(), 'u1', [A1]) vA2 = ['8', '9'] A2.add_op(Op('ai', [], offset=9, val=vA2)) doc.receive_changeset(A2) A3 = Changeset(doc.get_id(), 'u1', [A2]) vA3 = ['0'] A3.add_op(Op('ai', [], offset=11, val=vA3)) doc.receive_changeset(A3) result = ['ABCD', 'EFGH', '1', '2', '3', '4', 'IJKL', 'MNOP', 'QRST', '8', '9', '0', 'UVWX', 'YZ'] assert doc.get_snapshot() == result # Now B has a series of inserts B0 = Changeset(doc.get_id(), 'u1', [root]) vB0 = ['1b', '2b'] B0.add_op(Op('ai', [], offset=1, val=vB0)) B0.set_id('0B') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index > b_index result = ['ABCD', '1b', '2b', 'EFGH', '1', '2', '3', '4', 'IJKL', 'MNOP', 'QRST', '8', '9', '0', 'UVWX', 'YZ'] assert doc.get_snapshot() == result B1 = Changeset(doc.get_id(), 'u1', [B0]) vB1 = ['3b', '4b'] B1.add_op(Op('ai', [], offset=5, val=vB1)) doc.receive_changeset(B1) result = ['ABCD', '1b', '2b', 'EFGH', '1', '2', '3', '4', 'IJKL', '3b', '4b', 'MNOP', 'QRST', '8', '9', '0', 'UVWX', 'YZ'] assert doc.get_snapshot() == result B2 = Changeset(doc.get_id(), 'u1', [B1]) vB2 = ['8b', '9b', '0b'] B2.add_op(Op('ai', [], offset=7, val=vB2)) doc.receive_changeset(B2) result = ['ABCD', '1b', '2b', 'EFGH', '1', '2', '3', '4', 'IJKL', '3b', '4b', '8b', '9b', '0b', 'MNOP', 'QRST', '8', '9', '0', 'UVWX', 'YZ'] assert doc.get_snapshot() == result B3 = Changeset(doc.get_id(), 'u1', [B2]) vB3 = ['BBBB'] B3.add_op(Op('ai', [], offset=12, val=vB3)) doc.receive_changeset(B3) result = ['ABCD', '1b', '2b', 'EFGH', '1', '2', '3', '4', 'IJKL', '3b', '4b', '8b', '9b', '0b', 'MNOP', 'QRST', 'BBBB', '8', '9', '0', 'UVWX', 'YZ'] assert doc.get_snapshot() == result
def test_partial_overlaping_deletes(self): """ At the same time, two users delete the same text, then insert different text. The union of the deletion ranges should be deleted and the two sets of inserted text should appear in full, side by side. Note: This test is fairly redundant. Just don't want to delete an old test. """ doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() # create a common parrent for two divergent branches common_parent = Changeset(doc.get_id(), 'u1', [root]) common_parent.add_op(Op('si', [], offset=0, val='12345678')) doc.receive_changeset(common_parent) assert doc.get_snapshot() == '12345678' # construct branch A, which begins with a string delete, then # inserts 'abcde' in three changesets. A0 = Changeset(doc.get_id(), 'u1', [common_parent]) A0.add_op(Op('sd', [], offset=5, val=3)) A0.add_op(Op('si', [], offset=5, val='abc')) A0.set_id('A') doc.receive_changeset(A0) assert doc.get_snapshot() == '12345abc' A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('si', [], offset=8, val='d')) doc.receive_changeset(A1) A2 = Changeset(doc.get_id(), 'u1', [A1]) A2.add_op(Op('si', [], offset=9, val='e')) doc.receive_changeset(A2) assert doc.get_snapshot() == '12345abcde' # Branch B has common parent with A. Insert some text at the # end, delete the same range branch A deleted, then insert # more text B0 = Changeset(doc.get_id(), 'u2', [common_parent]) B0.add_op(Op('si', [], offset=8, val='f')) B0.set_id('B') doc.receive_changeset(B0) assert doc.get_snapshot() == '12345abcdef' # CS with overlapping delete range B1 = Changeset(doc.get_id(), 'u2', [B0]) B1.add_op(Op('sd', [], offset=0, val=8)) B1.add_op(Op('si', [], offset=1, val='g')) B1.add_op(Op('si', [], offset=2, val='hi')) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == 'abcdefghi' B2 = Changeset(doc.get_id(), 'u2', [B1]) B2.add_op(Op('si', [], offset=4, val='jkl')) B2.set_id('B2') doc.receive_changeset(B2) assert doc.get_snapshot() == 'abcdefghijkl' # combine these braches again C = Changeset(doc.get_id(), 'u2', [A2, B2]) C.add_op(Op('si', [], offset=6, val=' XYZ ')) doc.receive_changeset(C) assert doc.get_snapshot() == 'abcdef XYZ ghijkl'
def test_overlaping_deletes_then_string_insert(self): """ Both branches delete all the A's from the document. Additionally, one branch deletes all the Z's, the other all the X's. Then one inserts 'The Quick ', the other branch 'Brown Fox.' Each uses several ops to achieve this. NOTE: This example is slightly convoluted and hard to follow. The test is only here because it was a reproducable failure that had no solution at the time. """ s = 'ZZZZZZZAAAAAAAAAAAAAAAAAAAAAAAAAXXXXX' doc = Document(snapshot=s) doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=0, val=32)) A0.add_op(Op('si', [], offset=0, val='T')) A0.set_id('A0') doc.receive_changeset(A0) A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('si', [], offset=1, val="h")) A1.add_op(Op('si', [], offset=2, val="e")) A1.add_op(Op('si', [], offset=3, val=" ")) A1.set_id('A1') doc.receive_changeset(A1) A2 = Changeset(doc.get_id(), 'u1', [A1]) A2.add_op(Op('si', [], offset=4, val="Q")) A2.add_op(Op('si', [], offset=5, val="u")) A2.add_op(Op('si', [], offset=6, val="i")) A2.set_id('A2') doc.receive_changeset(A2) A3 = Changeset(doc.get_id(), 'u1', [A2]) A3.add_op(Op('si', [], offset=7, val="c")) A3.add_op(Op('si', [], offset=8, val="k")) A3.add_op(Op('si', [], offset=9, val=" ")) A3.set_id('A3') doc.receive_changeset(A3) assert doc.get_snapshot() == 'The Quick XXXXX' # Branch B has common parent with A. It saw the original document and # deleted everything but the Y's B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('sd', [], offset=7, val=30) B0.add_op(opB0) B0.set_id('B0') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index < b_index assert doc.get_snapshot() == 'The Quick ' # User B saw only the Y's and inserted text at the end. B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('si', [], offset=7, val='Brown Fox.') B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == 'The Quick Brown Fox.'
def test_complex_tree(self): """ Some complex tree. C -- G -- H -------- K / / \ A -- B -- D -- F -- J -- L -- M-- \ / E --- I Should be: A B C G H K D E I J L M """ doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() A = Changeset(doc.get_id(), "user0", [root]) A.set_id('A') doc.receive_changeset(A) B = Changeset(doc.get_id(),"user1",[A]) B.set_id('b') doc.receive_changeset(B) C = Changeset(doc.get_id(),"user3",[B]) C.set_id('c') doc.receive_changeset(C) D = Changeset(doc.get_id(),"user4",[B]) D.set_id('d') doc.receive_changeset(D) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [] assert C.get_unaccounted_changesets() == [] assert D.get_unaccounted_changesets() == [C] E = Changeset(doc.get_id(),"user5",[D]) E.set_id('e') doc.receive_changeset(E) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [] assert C.get_unaccounted_changesets() == [] assert D.get_unaccounted_changesets() == [C] assert E.get_unaccounted_changesets() == [C] F = Changeset(doc.get_id(),"user6",[D]) F.set_id('f') doc.receive_changeset(F) assert doc.get_ordered_changesets() == [root,A,B,C,D,E,F] assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [] assert C.get_unaccounted_changesets() == [] assert D.get_unaccounted_changesets() == [C] assert E.get_unaccounted_changesets() == [C] assert F.get_unaccounted_changesets() == [C,E] G = Changeset(doc.get_id(),"user5",[C]) G.set_id('g') doc.receive_changeset(G) # just a reminder of order now assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,F] assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [] assert C.get_unaccounted_changesets() == [] assert D.get_unaccounted_changesets() == [C,G] assert E.get_unaccounted_changesets() == [C,G] assert F.get_unaccounted_changesets() == [C,G,E] H = Changeset(doc.get_id(),"user5",[G,F]) H.set_id('h') doc.receive_changeset(H) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,F,H] assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [] assert C.get_unaccounted_changesets() == [] assert D.get_unaccounted_changesets() == [C,G] assert E.get_unaccounted_changesets() == [C,G] assert F.get_unaccounted_changesets() == [C,G,E] assert G.get_unaccounted_changesets() == [] assert H.get_unaccounted_changesets() == [E] I = Changeset(doc.get_id(),"user6",[E]) I.set_id('i') doc.receive_changeset(I) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,I,F,H] assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [] assert C.get_unaccounted_changesets() == [] assert D.get_unaccounted_changesets() == [C,G] assert E.get_unaccounted_changesets() == [C,G] assert F.get_unaccounted_changesets() == [C,G,E,I] assert G.get_unaccounted_changesets() == [] assert H.get_unaccounted_changesets() == [E,I] assert I.get_unaccounted_changesets() == [C,G] J = Changeset(doc.get_id(),"user5",[I,F]) J.set_id('j') doc.receive_changeset(J) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,I,F,H,J] assert D.get_unaccounted_changesets() == [C,G] assert E.get_unaccounted_changesets() == [C,G] assert F.get_unaccounted_changesets() == [C,G,E,I] assert G.get_unaccounted_changesets() == [] assert H.get_unaccounted_changesets() == [E,I] assert I.get_unaccounted_changesets() == [C,G] assert J.get_unaccounted_changesets() == [C,G,H] K = Changeset(doc.get_id(),"user5",[H]) K.set_id('k') doc.receive_changeset(K) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,I,F,H,K,J] assert D.get_unaccounted_changesets() == [C,G] assert E.get_unaccounted_changesets() == [C,G] assert F.get_unaccounted_changesets() == [C,G,E,I] assert G.get_unaccounted_changesets() == [] assert H.get_unaccounted_changesets() == [E,I] assert I.get_unaccounted_changesets() == [C,G] assert J.get_unaccounted_changesets() == [C,G,H,K] assert K.get_unaccounted_changesets() == [E,I] L = Changeset(doc.get_id(),"user5",[J]) L.set_id('l') doc.receive_changeset(L) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,I,F,H,K,J,L] assert D.get_unaccounted_changesets() == [C,G] assert E.get_unaccounted_changesets() == [C,G] assert F.get_unaccounted_changesets() == [C,G,E,I] assert G.get_unaccounted_changesets() == [] assert H.get_unaccounted_changesets() == [E,I] assert I.get_unaccounted_changesets() == [C,G] assert J.get_unaccounted_changesets() == [C,G,H,K] assert K.get_unaccounted_changesets() == [E,I] assert L.get_unaccounted_changesets() == [C,G,H,K] M = Changeset(doc.get_id(),"user5",[K,L]) M.set_id('m') doc.receive_changeset(M) assert doc.get_ordered_changesets() == [root,A,B,C,G,D,E,I,F,H,K,J,L,M] assert D.get_unaccounted_changesets() == [C,G] assert E.get_unaccounted_changesets() == [C,G] assert F.get_unaccounted_changesets() == [C,G,E,I] assert G.get_unaccounted_changesets() == [] assert H.get_unaccounted_changesets() == [E,I] assert I.get_unaccounted_changesets() == [C,G] assert J.get_unaccounted_changesets() == [C,G,H,K] assert K.get_unaccounted_changesets() == [E,I] assert L.get_unaccounted_changesets() == [C,G,H,K] assert M.get_unaccounted_changesets() == []
def test_delete_overlaping_ranges(self): """ Branch A and B independently delete the same characters in the middle of the string using different combinations of opperations. Then they perform other string operations that need to keep synced. """ s = '0123456789' doc = Document(snapshot=s) doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() # construct branch A, which deletes all but the first three # and last three characters. A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=4, val=2)) A0.set_id('A') doc.receive_changeset(A0) assert doc.get_snapshot() == '01236789' A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('sd', [], offset=3, val=2)) doc.receive_changeset(A1) assert doc.get_snapshot() == '012789' A2 = Changeset(doc.get_id(), 'u1', [A1]) A2.add_op(Op('sd', [], offset=2, val=2)) doc.receive_changeset(A2) assert doc.get_snapshot() == '0189' # Branch B has common parent with A. It deletes all but '89' # User saw '0123456789' and deleted '3456', which was already # deleted in branch A. B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('sd', [], offset=3, val=4) B0.add_op(opB0) B0.set_id('B') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index < b_index assert doc.get_snapshot() == '0189' # User saw '012789' and deleted '27', which was already # deleted in branch A. B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('sd', [], offset=2, val=2) B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == '0189' # Delete Range not known by branch A B2 = Changeset(doc.get_id(), 'u2', [B1]) opB2 = Op('sd', [], offset=1, val=2) B2.add_op(opB2) B2.set_id('B2') doc.receive_changeset(B2) assert doc.get_snapshot() == '09' # combine these braches again C = Changeset(doc.get_id(), 'u2', [A2, B2]) C.add_op(Op('si', [], offset=1, val='12345678')) doc.receive_changeset(C) assert doc.get_snapshot() == '0123456789'
def test_delete_overlaping_ranges2(self): """ Branch A and B independently delete the same characters in the middle of the string using different combinations of opperations. Then they perform other string operations that need to keep synced. """ s = '0123456789TARGET' doc = Document(snapshot=s) doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() # branch deletes the '234567' in three ops. A0 = Changeset(doc.get_id(), 'u1', [root]) A0.add_op(Op('sd', [], offset=4, val=2)) A0.set_id('A0') doc.receive_changeset(A0) assert doc.get_snapshot() == '01236789TARGET' A1 = Changeset(doc.get_id(), 'u1', [A0]) A1.add_op(Op('sd', [], offset=3, val=2)) A1.set_id('A1') doc.receive_changeset(A1) assert doc.get_snapshot() == '012789TARGET' A2 = Changeset(doc.get_id(), 'u1', [A1]) A2.add_op(Op('sd', [], offset=2, val=2)) A2.set_id('A2') doc.receive_changeset(A2) assert doc.get_snapshot() == '0189TARGET' # Branch B has common parent with A. It deletes all but # 'TARGET' in three ops. # User Saw '0123456789TARGET', deleted '234', which branch A # already did. B0 = Changeset(doc.get_id(), 'u2', [root]) opB0 = Op('sd', [], offset=2, val=3) B0.add_op(opB0) B0.set_id('B0') doc.receive_changeset(B0) a_index = doc.get_ordered_changesets().index(A0) b_index = doc.get_ordered_changesets().index(B0) assert a_index < b_index assert doc.get_snapshot() == '0189TARGET' # User Saw '0156789TARGET', deleted '567', which branch A # already did. B1 = Changeset(doc.get_id(), 'u2', [B0]) opB1 = Op('sd', [], offset=2, val=3) B1.add_op(opB1) B1.set_id('B1') doc.receive_changeset(B1) assert doc.get_snapshot() == '0189TARGET' # User Saw '0189TARGET', deleted '0189', which branch A has # NOT done. B2 = Changeset(doc.get_id(), 'u2', [B1]) opB2 = Op('sd', [], offset=0, val=4) B2.add_op(opB2) B2.set_id('B2') doc.receive_changeset(B2) assert doc.get_snapshot() == 'TARGET'
def test_multiple_css_with_same_multiple_dependencies(self): """ A1 D1 / / A -- B -- D--F -- G \ \/ / \ /\ / - C--E- Both F and E depend on D and C """ doc = Document(snapshot='') doc.HAS_EVENT_LOOP = False root = doc.get_root_changeset() A = Changeset(doc.get_id(), "user0", [root]) A.set_id('a') doc.receive_changeset(A) B = Changeset(doc.get_id(), "user1", [A]) B.set_id('b') doc.receive_changeset(B) C = Changeset(doc.get_id(), "user3", [B]) C.set_id('c') doc.receive_changeset(C) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [] assert C.get_unaccounted_changesets() == [] D = Changeset(doc.get_id(), "user4", [B]) D.set_id('d') doc.receive_changeset(D) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [] assert C.get_unaccounted_changesets() == [] assert D.get_unaccounted_changesets() == [C] E = Changeset(doc.get_id(), "user5", [C, D]) E.set_id('e') doc.receive_changeset(E) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [] assert C.get_unaccounted_changesets() == [] assert D.get_unaccounted_changesets() == [C] assert E.get_unaccounted_changesets() == [] F = Changeset(doc.get_id(), "user6", [C, D]) F.set_id('f') doc.receive_changeset(F) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [] assert C.get_unaccounted_changesets() == [] assert D.get_unaccounted_changesets() == [C] assert E.get_unaccounted_changesets() == [] assert F.get_unaccounted_changesets() == [E] A1 = Changeset(doc.get_id(), "user5", [A]) A1.set_id('1a') doc.receive_changeset(A1) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [A1] assert C.get_unaccounted_changesets() == [A1] assert D.get_unaccounted_changesets() == [A1,C] assert E.get_unaccounted_changesets() == [A1] assert F.get_unaccounted_changesets() == [A1,E] assert A1.get_unaccounted_changesets() == [] D1 = Changeset(doc.get_id(), "user5", [D]) D1.set_id('1d') doc.receive_changeset(D1) assert doc.get_ordered_changesets() == [root, A,A1,B,C,D,D1,E,F] assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [A1] assert C.get_unaccounted_changesets() == [A1] assert D.get_unaccounted_changesets() == [A1,C] assert E.get_unaccounted_changesets() == [A1,D1] assert F.get_unaccounted_changesets() == [A1,D1,E] assert A1.get_unaccounted_changesets() == [] assert D1.get_unaccounted_changesets() == [A1,C] G = Changeset(doc.get_id(), "user5", [E,F]) doc.receive_changeset(G) assert A.get_unaccounted_changesets() == [] assert B.get_unaccounted_changesets() == [A1] assert C.get_unaccounted_changesets() == [A1] assert D.get_unaccounted_changesets() == [A1,C] assert E.get_unaccounted_changesets() == [A1,D1] assert F.get_unaccounted_changesets() == [A1,D1,E] assert A1.get_unaccounted_changesets() == [] assert D1.get_unaccounted_changesets() == [A1,C] assert G.get_unaccounted_changesets() == [A1,D1]