def test_decide_merge_simple_list_insert_conflict_resolution(): # local and remote adds an entry each b = [1] l = [1, 2] r = [1, 3] strategies = Strategies({"/*": "use-local"}) decisions = decide_merge(b, l, r, strategies) assert apply_decisions(b, decisions) == l assert not any(d.conflict for d in decisions) strategies = Strategies({"/*": "use-remote"}) decisions = decide_merge(b, l, r, strategies) assert apply_decisions(b, decisions) == r assert not any(d.conflict for d in decisions) strategies = Strategies({"/*": "use-base"}) decisions = decide_merge(b, l, r, strategies) assert apply_decisions(b, decisions) == b assert not any(d.conflict for d in decisions) strategies = Strategies({"/": "clear-all"}) decisions = decide_merge(b, l, r, strategies) assert apply_decisions(b, decisions) == [] assert not any(d.conflict for d in decisions)
def test_decide_merge_list_conflicting_insertions_in_chunks(): # Next, test when insertions DO chunk together: b = [1, 9] l = [1, 2, 7, 9] r = [1, 3, 7, 9] # Check strategyless resolution strategies = Strategies({}) resolved = decide_merge(b, l, r, strategies) expected_partial = [1, 7, 9] assert apply_decisions(b, resolved) == expected_partial strategies = Strategies({"/*": "use-local"}) resolved = decide_merge(b, l, r, strategies) assert apply_decisions(b, resolved) == l assert not any(d.conflict for d in resolved) strategies = Strategies({"/*": "use-remote"}) resolved = decide_merge(b, l, r, strategies) assert apply_decisions(b, resolved) == r assert not any(d.conflict for d in resolved) strategies = Strategies({"/*": "use-base"}) resolved = decide_merge(b, l, r, strategies) assert apply_decisions(b, resolved) == expected_partial assert not any(d.conflict for d in resolved) strategies = Strategies({"/": "clear-all"}) resolved = decide_merge(b, l, r, strategies) assert apply_decisions(b, resolved) == [] assert not any(d.conflict for d in resolved)
def test_decide_merge_strategy_remove(): base = {"foo": [1, 2]} local = {"foo": [1, 4, 2]} remote = {"foo": [1, 3, 2]} strategies = Strategies({"/foo": "remove"}) decisions = decide_merge(base, local, remote, strategies) assert apply_decisions(base, decisions) == {"foo": [1, 2]} assert decisions[0].local_diff != [] assert decisions[0].remote_diff != [] strategies = Strategies({}) decisions = decide_merge(base, local, remote, strategies) assert apply_decisions(base, decisions) == {"foo": [1, 2]} assert decisions[0].local_diff != [] assert decisions[0].remote_diff != []
def test_decide_merge_strategy_clear_all(): base = {"foo": [1, 2]} local = {"foo": [1, 4, 2]} remote = {"foo": [1, 3, 2]} strategies = Strategies({"/foo": "clear-all"}) decisions = decide_merge(base, local, remote, strategies) assert apply_decisions(base, decisions) == {"foo": []} base = {"foo": [1, 2]} local = {"foo": [1, 4, 2]} remote = {"foo": [1, 2, 3]} strategies = Strategies({"/foo": "clear-all"}) decisions = decide_merge(base, local, remote, strategies) assert apply_decisions(base, decisions) == {"foo": [1, 4, 2, 3]}
def test_decide_merge_strategy_fail(reset_log): """Check that "fail" strategy results in proper exception raised.""" # One level dict base = {"foo": 1} local = {"foo": 2} remote = {"foo": 3} strategies = Strategies({"/foo": "fail"}) with pytest.raises(RuntimeError): conflicted_decisions = decide_merge(base, local, remote, strategies) # Nested dicts base = {"foo": {"bar": 1}} local = {"foo": {"bar": 2}} remote = {"foo": {"bar": 3}} strategies = Strategies({"/foo/bar": "fail"}) with pytest.raises(RuntimeError): decisions = decide_merge(base, local, remote, strategies)
def test_decide_merge_strategy_clear2(): base = {"foo": "1"} local = {"foo": "2"} remote = {"foo": "3"} strategies = Strategies({"/foo": "clear"}) decisions = decide_merge(base, local, remote, strategies) #assert decisions == [] assert apply_decisions(base, decisions) == {"foo": ""} assert not any([d.conflict for d in decisions])
def test_decide_merge_dict_transients(): # Setup transient difference in base and local, deletion in remote b = {'a': {'transient': 22}} l = {'a': {'transient': 242}} r = {} # Assert that generic merge gives conflict strategies = Strategies() decisions = decide_merge(b, l, r, strategies) assert apply_decisions(b, decisions) == b assert len(decisions) == 1 assert decisions[0].conflict # Supply transient list to autoresolve, and check that transient is ignored strategies = Strategies(transients=['/a/transient']) decisions = decide_merge(b, l, r, strategies) assert apply_decisions(b, decisions) == r assert not any(d.conflict for d in decisions)
def test_decide_merge_strategy_clear1(): """Check strategy "clear" in various cases.""" # One level dict, clearing item value (think foo==execution_count) base = {"foo": 1} local = {"foo": 2} remote = {"foo": 3} strategies = Strategies({"/foo": "clear"}) decisions = decide_merge(base, local, remote, strategies) assert apply_decisions(base, decisions) == {"foo": None} assert not any([d.conflict for d in decisions])
def test_decide_merge_list_conflicting_insertions_in_chunks__union(): # Next, test when insertions DO chunk together: b = [1, 9] l = [1, 2, 7, 9] r = [1, 3, 7, 9] strategies = Strategies({"/": "union"}) resolved = decide_merge(b, l, r, strategies) assert apply_decisions(b, resolved) == [1, 2, 3, 7, 9] assert not any(d.conflict for d in resolved)
def test_decide_merge_simple_list_insert_conflict_resolution__union(): # local and remote adds an entry each b = [1] l = [1, 2] r = [1, 3] strategies = Strategies({"/": "union"}) decisions = decide_merge(b, l, r, strategies) assert apply_decisions(b, decisions) == [1, 2, 3] assert not any(d.conflict for d in decisions)
def test_decide_merge_list_conflicting_insertions_separate_chunks__union(): # local and remote adds an equal entry plus a different entry each # First, test when insertions DO NOT chunk together: b = [1, 9] l = [1, 2, 9, 11] r = [1, 3, 9, 11] strategies = Strategies({"/": "union"}) resolved = decide_merge(b, l, r, strategies) assert apply_decisions(b, resolved) == [1, 2, 3, 9, 11] assert not any(d.conflict for d in resolved)
def test_decide_merge_dict_transients(): # Setup transient difference in base and local, deletion in remote b = {'a': {'transient': 22}} l = {'a': {'transient': 242}} r = {} # Assert that generic merge gives conflict strategies = Strategies() decisions = decide_merge(b, l, r, strategies) assert apply_decisions(b, decisions) == b assert len(decisions) == 1 assert decisions[0].conflict # Supply transient list to autoresolve, and check that transient is ignored strategies = Strategies(transients=[ '/a/transient' ]) decisions = decide_merge(b, l, r, strategies) assert apply_decisions(b, decisions) == r assert not any(d.conflict for d in decisions)
def test_decide_merge_list_conflicting_insertions_separate_chunks_v2(): # local and remote adds an equal entry plus a different entry each # First, test when insertions DO NOT chunk together: b = [1, 9] l = [1, 2, 9, 11] r = [1, 3, 9, 11] # Check strategyless resolution strategies = Strategies({}) resolved = decide_merge(b, l, r, strategies) expected_partial = [1, 9, 11] assert apply_decisions(b, resolved) == expected_partial assert len(resolved) == 2 assert resolved[0].conflict assert not resolved[1].conflict
def test_decide_merge_list_conflicting_insertions_separate_chunks_v1(): # local and remote adds an equal entry plus a different entry each # First, test when insertions DO NOT chunk together: b = [1, 9] l = [1, 2, 9, 11] r = [1, 3, 9, 11] # Check strategyless resolution strategies = Strategies({}) resolved = decide_merge(b, l, r, strategies) expected_partial = [1, 9, 11] assert apply_decisions(b, resolved) == expected_partial assert len(resolved) == 2 assert resolved[0].conflict assert not resolved[1].conflict strategies = Strategies({"/*": "use-local"}) resolved = decide_merge(b, l, r, strategies) assert apply_decisions(b, resolved) == l assert not any(d.conflict for d in resolved) strategies = Strategies({"/*": "use-remote"}) resolved = decide_merge(b, l, r, strategies) assert apply_decisions(b, resolved) == r assert not any(d.conflict for d in resolved) strategies = Strategies({"/*": "use-base"}) resolved = decide_merge(b, l, r, strategies) # Strategy is only applied to conflicted decisions: assert apply_decisions(b, resolved) == expected_partial assert not any(d.conflict for d in resolved) strategies = Strategies({"/": "clear-all"}) resolved = decide_merge(b, l, r, strategies) assert apply_decisions(b, resolved) == [] assert not any(d.conflict for d in resolved)
def test_decide_merge_strategy_use_foo_on_dict_items(): base = {"foo": 1} local = {"foo": 2} remote = {"foo": 3} strategies = Strategies({"/foo": "use-base"}) decisions = decide_merge(base, local, remote, strategies) assert not any([d.conflict for d in decisions]) assert apply_decisions(base, decisions) == {"foo": 1} strategies = Strategies({"/foo": "use-local"}) decisions = decide_merge(base, local, remote, strategies) assert not any([d.conflict for d in decisions]) assert apply_decisions(base, decisions) == {"foo": 2} strategies = Strategies({"/foo": "use-remote"}) decisions = decide_merge(base, local, remote, strategies) assert not any([d.conflict for d in decisions]) assert apply_decisions(base, decisions) == {"foo": 3} base = {"foo": {"bar": 1}} local = {"foo": {"bar": 2}} remote = {"foo": {"bar": 3}} strategies = Strategies({"/foo/bar": "use-base"}) decisions = decide_merge(base, local, remote, strategies) assert not any([d.conflict for d in decisions]) assert apply_decisions(base, decisions) == {"foo": {"bar": 1}} strategies = Strategies({"/foo/bar": "use-local"}) decisions = decide_merge(base, local, remote, strategies) assert not any([d.conflict for d in decisions]) assert apply_decisions(base, decisions) == {"foo": {"bar": 2}} strategies = Strategies({"/foo/bar": "use-remote"}) decisions = decide_merge(base, local, remote, strategies) assert not any([d.conflict for d in decisions]) assert apply_decisions(base, decisions) == {"foo": {"bar": 3}}