def check_diff_sequence_and_patch(a, b): d = diff_sequence_difflib(a, b) assert is_valid_diff(d) assert patch(a, d) == b d = diff_sequence_difflib(b, a) assert is_valid_diff(d) assert patch(b, d) == a
def check_diff_and_patch(a, b): "Check that patch(a, diff(a,b)) reproduces b." d = shallow_diff(a, b) assert is_valid_diff(d) assert patch(a, d) == b d = deep_diff(a, b) assert is_valid_diff(d) assert patch(a, d) == b
def pick_merge_decision(base, dec): if dec.action is None or dec.action == "base": di = None elif dec.action == "local" or dec.action == "either": di = dec.local_diff elif dec.action == "remote": di = dec.remote_diff elif dec.action == "custom": di = dec.custom_diff else: raise ValueError("Unknown action {}".format(dec.action)) if di is not None: # Parse common path keys = [k for k in dec.common_path.split("/") if k != ""] sub = base for k in keys: if isinstance(sub, list): k = int(k) sub = sub[k] # "/cells" -> sub = base[cells], sub is a list # patch # Add patch entries base_diff = di for k in reversed(keys): if is_int(k): k = int(k) base_diff = op_patch(k, base_diff) # Apply patch base = patch(base, base_diff) return base
def test_diff_sequence_bruteforce(): examples = [ ([], []), ([1], [1]), ([1, 2], [1, 2]), ([2, 1], [1, 2]), ([1, 2, 3], [1, 2]), ([2, 1, 3], [1, 2]), ([1, 2], [1, 2, 3]), ([2, 1], [1, 2, 3]), ([1, 2], [1, 2, 1, 2]), ([1, 2, 1, 2], [1, 2]), ([1, 2, 3, 4, 1, 2], [3, 4, 2, 3]), (list("abcab"), list("ayb")), (list("xaxcxabc"), list("abcy")), ] for a, b in examples: G = bruteforce_compare_grid(a, b) assert all(bool(G[i][j]) == (a[i] == b[j]) for i in range(len(a)) for j in range(len(b))) R = bruteforce_llcs_grid(G) for i in range(len(a)): for j in range(len(b)): assert R[i+1][j+1] >= R[i][j] assert R[i+1][j] >= R[i][j] assert R[i][j+1] >= R[i][j] assert R[i+1][j+1] - R[i][j] <= 1 assert R[i+1][j] - R[i][j] <= 1 assert R[i][j+1] - R[i][j] <= 1 llcs = R[len(a)][len(b)] A_indices, B_indices = bruteforce_lcs_indices(a, b, G, R) assert len(A_indices) == len(B_indices) assert len(A_indices) == llcs assert all(a[A_indices[r]] == b[B_indices[r]] for r in range(llcs)) d = diff_from_lcs(a, b, A_indices, B_indices) assert is_valid_diff(d) assert patch(a, d) == b # Test combined function (repeats the above pieces) assert patch(a, diff_sequence_bruteforce(a, b)) == b
def test_patch_dict(): # Test +, single item insertion assert patch({}, [op_add("d", 4)]) == {"d": 4} assert patch({"a": 1}, [op_add("d", 4)]) == {"a": 1, "d": 4} #assert patch({"d": 1}, [op_add("d", 4)]) == {"d": 4} # currently triggers assert, raise exception or allow? # Test -, single item deletion assert patch({"a": 1}, [op_remove("a")]) == {} assert patch({"a": 1, "b": 2}, [op_remove("a")]) == {"b": 2} # Test :, single item replace assert patch({"a": 1, "b": 2}, [op_replace("a", 3)]) == {"a": 3, "b": 2} assert patch({"a": 1, "b": 2}, [op_replace("a", 3), op_replace("b", 5)]) == {"a": 3, "b": 5} # Test !, item patch subdiff = [op_patch(0, [op_patch(0, [op_replace(0, "H")])]), op_patch(1, [op_patch(0, [op_remove(0), op_add(0, "W")])])] assert patch({"a": ["hello", "world"], "b": 3}, [op_patch("a", subdiff)]) == {"a": ["Hello", "World"], "b": 3}
def test_patch_dict(): # Test +, single item insertion assert patch({}, [["+", "d", 4]]) == {"d": 4} assert patch({"a": 1}, [["+", "d", 4]]) == {"a": 1, "d": 4} #assert patch({"d": 1}, [["+", "d", 4]]) == {"d": 4} # currently triggers assert, raise exception or allow? # Test -, single item deletion assert patch({"a": 1}, [["-", "a"]]) == {} assert patch({"a": 1, "b": 2}, [["-", "a"]]) == {"b": 2} # Test :, single item replace assert patch({"a": 1, "b": 2}, [[":", "a", 3]]) == {"a": 3, "b": 2} assert patch({"a": 1, "b": 2}, [[":", "a", 3], [":", "b", 5]]) == {"a": 3, "b": 5} # Test !, item patch subdiff = [["!", 0, [[":", 0, "H"]]], ["!", 1, [["-", 0], ["+", 0, "W"]]]] assert patch({"a": ["hello", "world"], "b": 3}, [["!", "a", subdiff]]) == {"a": ["Hello", "World"], "b": 3}
def test_patch_dict(): # Test +, single item insertion assert patch({}, [make_op(Diff.ADD, "d", 4)]) == {"d": 4} assert patch({"a": 1}, [make_op(Diff.ADD, "d", 4)]) == {"a": 1, "d": 4} #assert patch({"d": 1}, [make_op(Diff.ADD, "d", 4)]) == {"d": 4} # currently triggers assert, raise exception or allow? # Test -, single item deletion assert patch({"a": 1}, [make_op(Diff.REMOVE, "a")]) == {} assert patch({"a": 1, "b": 2}, [make_op(Diff.REMOVE, "a")]) == {"b": 2} # Test :, single item replace assert patch({"a": 1, "b": 2}, [make_op(Diff.REPLACE, "a", 3)]) == {"a": 3, "b": 2} assert patch({"a": 1, "b": 2}, [make_op(Diff.REPLACE, "a", 3), make_op(Diff.REPLACE, "b", 5)]) == {"a": 3, "b": 5} # Test !, item patch subdiff = [make_op(Diff.PATCH, 0, [make_op(Diff.REPLACE, 0, "H")]), make_op(Diff.PATCH, 1, [make_op(Diff.REMOVE, 0), make_op(Diff.ADD, 0, "W")])] assert patch({"a": ["hello", "world"], "b": 3}, [make_op(Diff.PATCH, "a", subdiff)]) == {"a": ["Hello", "World"], "b": 3}
def test_patch_list(): # Test +, single item insertion assert patch([], [make_op(Diff.ADD, 0, 3)]) == [3] assert patch([], [make_op(Diff.ADD, 0, 3), make_op(Diff.ADD, 0, 4)]) == [3, 4] assert patch([], [make_op(Diff.ADD, 0, 3), make_op(Diff.ADD, 0, 4), make_op(Diff.ADD, 0, 5)]) == [3, 4, 5] # Test -, single item deletion assert patch([3], [make_op(Diff.REMOVE, 0)]) == [] assert patch([5, 6, 7], [make_op(Diff.REMOVE, 0)]) == [6, 7] assert patch([5, 6, 7], [make_op(Diff.REMOVE, 1)]) == [5, 7] assert patch([5, 6, 7], [make_op(Diff.REMOVE, 2)]) == [5, 6] assert patch([5, 6, 7], [make_op(Diff.REMOVE, 0), make_op(Diff.REMOVE, 2)]) == [6] # Test :, single item replace pass # Test !, item patch assert patch(["hello", "world"], [make_op(Diff.PATCH, 0, [make_op(Diff.REPLACE, 0, "H")]), make_op(Diff.PATCH, 1, [make_op(Diff.REMOVE, 0), make_op(Diff.ADD, 0, "W")])]) == ["Hello", "World"] # Test ++, sequence insertion assert patch([], [make_op(Diff.ADDRANGE, 0, [3, 4]), make_op(Diff.ADD, 0, 5), make_op(Diff.ADDRANGE, 0, [6, 7])]) == [3, 4, 5, 6, 7] # Test --, sequence deletion assert patch([5, 6, 7, 8], [make_op(Diff.REMOVERANGE, 0, 2)]) == [7, 8] assert patch([5, 6, 7, 8], [make_op(Diff.REMOVERANGE, 1, 2)]) == [5, 8] assert patch([5, 6, 7, 8], [make_op(Diff.REMOVERANGE, 2, 2)]) == [5, 6]
def test_diff_and_patch_cells_of_notebooks(any_nb_pair): "Test diff/patch on the cells of any pair of notebooks in the test suite." nba, nbb = any_nb_pair a = nba["cells"] b = nbb["cells"] assert patch(a, diff_cells(a, b)) == b
def test_patch_list(): # Test +, single item insertion assert patch([], [op_add(0, 3)]) == [3] assert patch([], [op_add(0, 3), op_add(0, 4)]) == [3, 4] assert patch([], [op_add(0, 3), op_add(0, 4), op_add(0, 5)]) == [3, 4, 5] # Test -, single item deletion assert patch([3], [op_remove(0)]) == [] assert patch([5, 6, 7], [op_remove(0)]) == [6, 7] assert patch([5, 6, 7], [op_remove(1)]) == [5, 7] assert patch([5, 6, 7], [op_remove(2)]) == [5, 6] assert patch([5, 6, 7], [op_remove(0), op_remove(2)]) == [6] # Test :, single item replace pass # Test !, item patch assert patch(["hello", "world"], [op_patch(0, [op_patch(0, [op_replace(0, "H")])]), op_patch(1, [op_patch(0, [op_remove(0), op_add(0, "W")])])]) == ["Hello", "World"] # Test ++, sequence insertion assert patch([], [op_addrange(0, [3, 4]), op_add(0, 5), op_addrange(0, [6, 7])]) == [3, 4, 5, 6, 7] # Test --, sequence deletion assert patch([5, 6, 7, 8], [op_removerange(0, 2)]) == [7, 8] assert patch([5, 6, 7, 8], [op_removerange(1, 2)]) == [5, 8] assert patch([5, 6, 7, 8], [op_removerange(2, 2)]) == [5, 6]
def test_patch_str(): # Test +, single item insertion assert patch("42", [op_patch(0, [op_add(0, "3"), op_remove(1)])]) == "34" # Test -, single item deletion assert patch("3", [op_patch(0, [op_remove(0)])]) == "" assert patch("42", [op_patch(0, [op_remove(0)])]) == "2" assert patch("425", [op_patch(0, [op_remove(0)])]) == "25" assert patch("425", [op_patch(0, [op_remove(1)])]) == "45" assert patch("425", [op_patch(0, [op_remove(2)])]) == "42" # Test :, single item replace assert patch("52", [op_patch(0, [op_replace(0, "4")])]) == "42" assert patch("41", [op_patch(0, [op_replace(1, "2")])]) == "42" assert patch("42", [op_patch(0, [op_replace(0, "3"), op_replace(1, "5")])]) == "35" assert patch("hello", [op_patch(0, [op_replace(0, "H")])]) == "Hello" # Replace by delete-then-insert assert patch("world", [op_patch(0, [op_remove(0), op_add(0, "W")])]) == "World" # Test !, item patch (doesn't make sense for str) pass # Test ++, sequence insertion assert patch("", [op_patch(0, [op_addrange(0, "34"), op_add(0, "5"), op_addrange(0, "67")])]) == "34567" # Test --, sequence deletion assert patch("abcd", [op_patch(0, [op_removerange(0, 2)])]) == "cd" assert patch("abcd", [op_patch(0, [op_removerange(1, 2)])]) == "ad" assert patch("abcd", [op_patch(0, [op_removerange(2, 2)])]) == "ab"
def test_patch_str(): # Test +, single item insertion assert patch("42", [["+", 0, "3"], ["-", 1]]) == "34" # Test -, single item deletion assert patch("3", [["-", 0]]) == "" assert patch("42", [["-", 0]]) == "2" assert patch("425", [["-", 0]]) == "25" assert patch("425", [["-", 1]]) == "45" assert patch("425", [["-", 2]]) == "42" # Test :, single item replace assert patch("52", [[":", 0, "4"]]) == "42" assert patch("41", [[":", 1, "2"]]) == "42" assert patch("42", [[":", 0, "3"], [":", 1, "5"]]) == "35" assert patch("hello", [[":", 0, "H"]]) == "Hello" # Replace by delete-then-insert assert patch("world", [["-", 0], ["+", 0, "W"]]) == "World" # Test !, item patch (doesn't make sense for str) pass # Test ++, sequence insertion assert patch("", [["++", 0, "34"], ["+", 0, "5"], ["++", 0, "67"]]) == "34567" # Test --, sequence deletion assert patch("abcd", [["--", 0, 2]]) == "cd" assert patch("abcd", [["--", 1, 2]]) == "ad" assert patch("abcd", [["--", 2, 2]]) == "ab" # Test ::, sequence replace assert patch("abc", [["::", 0, "fg"]]) == "fgc" assert patch("abc", [["::", 1, "fg"]]) == "afg" assert patch("abc", [["::", 0, "fgh"]]) == "fgh"
def test_patch_str(): # Test +, single item insertion assert patch("42", [make_op(Diff.ADD, 0, "3"), make_op(Diff.REMOVE, 1)]) == "34" # Test -, single item deletion assert patch("3", [make_op(Diff.REMOVE, 0)]) == "" assert patch("42", [make_op(Diff.REMOVE, 0)]) == "2" assert patch("425", [make_op(Diff.REMOVE, 0)]) == "25" assert patch("425", [make_op(Diff.REMOVE, 1)]) == "45" assert patch("425", [make_op(Diff.REMOVE, 2)]) == "42" # Test :, single item replace assert patch("52", [make_op(Diff.REPLACE, 0, "4")]) == "42" assert patch("41", [make_op(Diff.REPLACE, 1, "2")]) == "42" assert patch("42", [make_op(Diff.REPLACE, 0, "3"), make_op(Diff.REPLACE, 1, "5")]) == "35" assert patch("hello", [make_op(Diff.REPLACE, 0, "H")]) == "Hello" # Replace by delete-then-insert assert patch("world", [make_op(Diff.REMOVE, 0), make_op(Diff.ADD, 0, "W")]) == "World" # Test !, item patch (doesn't make sense for str) pass # Test ++, sequence insertion assert patch("", [make_op(Diff.ADDRANGE, 0, "34"), make_op(Diff.ADD, 0, "5"), make_op(Diff.ADDRANGE, 0, "67")]) == "34567" # Test --, sequence deletion assert patch("abcd", [make_op(Diff.REMOVERANGE, 0, 2)]) == "cd" assert patch("abcd", [make_op(Diff.REMOVERANGE, 1, 2)]) == "ad" assert patch("abcd", [make_op(Diff.REMOVERANGE, 2, 2)]) == "ab"
def test_patch_list(): # Test +, single item insertion assert patch([], [op_add(0, 3)]) == [3] assert patch([], [op_add(0, 3), op_add(0, 4)]) == [3, 4] assert patch([], [op_add(0, 3), op_add(0, 4), op_add(0, 5)]) == [3, 4, 5] # Test -, single item deletion assert patch([3], [op_remove(0)]) == [] assert patch([5, 6, 7], [op_remove(0)]) == [6, 7] assert patch([5, 6, 7], [op_remove(1)]) == [5, 7] assert patch([5, 6, 7], [op_remove(2)]) == [5, 6] assert patch([5, 6, 7], [op_remove(0), op_remove(2)]) == [6] # Test :, single item replace pass # Test !, item patch assert patch(["hello", "world"], [op_patch(0, [op_patch(0, [op_replace(0, "H")])]), op_patch(1, [op_patch(0, [op_remove(0), op_add(0, "W")])])]) == ["Hello", "World"] # Test ++, sequence insertion assert patch([], [op_addrange( 0, [3, 4]), op_add(0, 5), op_addrange( 0, [6, 7])]) == [3, 4, 5, 6, 7] # Test --, sequence deletion assert patch([5, 6, 7, 8], [op_removerange(0, 2)]) == [7, 8] assert patch([5, 6, 7, 8], [op_removerange(1, 2)]) == [5, 8] assert patch([5, 6, 7, 8], [op_removerange(2, 2)]) == [5, 6]
def test_patch_str(): # Test +, single item insertion assert patch("42", [op_patch(0, [op_add(0, "3"), op_remove(1)])]) == "34" # Test -, single item deletion assert patch("3", [op_patch(0, [op_remove(0)])]) == "" assert patch("42", [op_patch(0, [op_remove(0)])]) == "2" assert patch("425", [op_patch(0, [op_remove(0)])]) == "25" assert patch("425", [op_patch(0, [op_remove(1)])]) == "45" assert patch("425", [op_patch(0, [op_remove(2)])]) == "42" # Test :, single item replace assert patch("52", [op_patch(0, [op_replace(0, "4")])]) == "42" assert patch("41", [op_patch(0, [op_replace(1, "2")])]) == "42" assert patch("42", [op_patch(0, [op_replace(0, "3"), op_replace(1, "5")])]) == "35" assert patch("hello", [op_patch(0, [op_replace(0, "H")])]) == "Hello" # Replace by delete-then-insert assert patch("world", [op_patch(0, [op_remove(0), op_add(0, "W")])]) == "World" # Test !, item patch (doesn't make sense for str) pass # Test ++, sequence insertion assert patch("", [op_patch(0, [op_addrange( 0, "34"), op_add(0, "5"), op_addrange( 0, "67")])]) == "34567" # Test --, sequence deletion assert patch("abcd", [op_patch(0, [op_removerange(0, 2)])]) == "cd" assert patch("abcd", [op_patch(0, [op_removerange(1, 2)])]) == "ad" assert patch("abcd", [op_patch(0, [op_removerange(2, 2)])]) == "ab"
def check_diff_and_patch(a, b): "Check that patch(a, diff(a,b)) reproduces b." d = diff(a, b) assert is_valid_diff(d) assert patch(a, d) == b
def test_patch_list(): # Test +, single item insertion assert patch([], [["+", 0, 3]]) == [3] assert patch([], [["+", 0, 3], ["+", 0, 4]]) == [3, 4] assert patch([], [["+", 0, 3], ["+", 0, 4], ["+", 0, 5]]) == [3, 4, 5] # Test -, single item deletion assert patch([3], [["-", 0]]) == [] assert patch([5, 6, 7], [["-", 0]]) == [6, 7] assert patch([5, 6, 7], [["-", 1]]) == [5, 7] assert patch([5, 6, 7], [["-", 2]]) == [5, 6] assert patch([5, 6, 7], [["-", 0], ["-", 2]]) == [6] # Test :, single item replace pass # Test !, item patch assert patch(["hello", "world"], [["!", 0, [[":", 0, "H"]]], ["!", 1, [["-", 0], ["+", 0, "W"]]]]) == ["Hello", "World"] # Test ++, sequence insertion assert patch([], [["++", 0, [3,4]], ["+", 0, 5], ["++", 0, [6,7]]]) == [3, 4, 5, 6, 7] # Test --, sequence deletion assert patch([5, 6, 7, 8], [["--", 0, 2]]) == [7, 8] assert patch([5, 6, 7, 8], [["--", 1, 2]]) == [5, 8] assert patch([5, 6, 7, 8], [["--", 2, 2]]) == [5, 6] # Test ::, sequence replace assert patch(["a", "b", "c"], [["::", 0, ["f", "g"]]]) == ["f", "g", "c"] assert patch(["a", "b", "c"], [["::", 1, ["f", "g"]]]) == ["a", "f", "g"] assert patch(["a", "b", "c"], [["::", 0, ["f", "g", "h"]]]) == ["f", "g", "h"]