Пример #1
0
def test_conflict_with_custom_ops_update_and_head_with_nested_rules():
    r = {'r': {'foo': 'baa', 'spam': 'eg'}, 'p': {'foo': 'baa', 'spam': 'eg'}}
    h = {
        'r': {
            'foo': 'bab',
            'spam': 'egg'
        },
        'p': {
            'foo': 'bab',
            'spam': 'egg'
        }
    }
    u = {
        'r': {
            'foo': 'bac',
            'spam': 'eggs'
        },
        'p': {
            'foo': 'bac',
            'spam': 'eggs'
        }
    }

    custom_ops = {
        'r': DictMergerOps.FALLBACK_KEEP_UPDATE,
        'p': DictMergerOps.FALLBACK_KEEP_HEAD,
        'r.foo': DictMergerOps.FALLBACK_KEEP_HEAD,
        'p.spam': DictMergerOps.FALLBACK_KEEP_UPDATE
    }
    expected = {
        'r': {
            'foo': 'bab',
            'spam': 'eggs'
        },
        'p': {
            'foo': 'bab',
            'spam': 'eggs'
        }
    }

    m = SkipListsMerger(r,
                        h,
                        u,
                        DictMergerOps.FALLBACK_KEEP_HEAD,
                        custom_ops=custom_ops)
    with pytest.raises(MergeError) as excinfo:
        m.merge()

    assert m.merged_root == expected

    assert m.conflicts == excinfo.value.content
    assert len(m.conflicts) == 4
    assert Conflict(ConflictType.SET_FIELD, ('r', 'spam'),
                    'egg') in m.conflicts
    assert Conflict(ConflictType.SET_FIELD, ('p', 'spam'),
                    'egg') in m.conflicts
    assert Conflict(ConflictType.SET_FIELD, ('r', 'foo'), 'bac') in m.conflicts
    assert Conflict(ConflictType.SET_FIELD, ('p', 'foo'), 'bac') in m.conflicts
Пример #2
0
def test_to_json_with_add_back_to_head():
    conflict = Conflict('ADD_BACK_TO_HEAD', ['foo', 'bar'], {})
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == {
        '$type': 'ADD_BACK_TO_HEAD',
        'op': 'add',
        'path': '/foo/bar/-',
        'value': {}
    }
Пример #3
0
def test_to_json_when_path_has_integers():
    conflict = Conflict('REMOVE_FIELD', ['foo', 0, 'bar', 1], None)
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == {
        '$type': 'REMOVE_FIELD',
        'op': 'remove',
        'path': '/foo/0/bar/1',
        'value': None
    }
Пример #4
0
def test_to_json_with_set_field():
    conflict = Conflict('SET_FIELD', ['foo', 'bar'], {})
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == {
        '$type': 'SET_FIELD',
        'op': 'replace',
        'path': '/foo/bar',
        'value': {}
    }
Пример #5
0
def test_to_json_with_reorder():
    conflict = Conflict('REORDER', ['foo', 'bar'], {})
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == {
        '$type': 'REORDER',
        'op': 'replace',
        'path': '/foo/bar',
        'value': {}
    }
Пример #6
0
def test_to_json_with_remove_field():
    conflict = Conflict('REMOVE_FIELD', ['foo', 'bar'], None)
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == {
        '$type': 'REMOVE_FIELD',
        'op': 'remove',
        'path': '/foo/bar',
        'value': None
    }
Пример #7
0
def test_to_json_with_manual_merge():
    conflict = Conflict('MANUAL_MERGE', ['foo', 'bar'], {})
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == {
        '$type': 'MANUAL_MERGE',
        'op': 'add',
        'path': '/foo/bar/-',
        'value': {}
    }
Пример #8
0
def test_conflict_with_custom_ops_update():
    r = {'r': {'foo': 'baa', 'spam': 'eg'}, 'p': {'foo': 'baa', 'spam': 'eg'}}
    h = {
        'r': {
            'foo': 'bab',
            'spam': 'egg'
        },
        'p': {
            'foo': 'bab',
            'spam': 'egg'
        }
    }
    u = {
        'r': {
            'foo': 'bac',
            'spam': 'eggs'
        },
        'p': {
            'foo': 'bac',
            'spam': 'eggs'
        }
    }

    # set different strategies compare to the default one
    custom_ops = {
        'r': DictMergerOps.FALLBACK_KEEP_UPDATE,
        'p': DictMergerOps.FALLBACK_KEEP_UPDATE
    }
    expected = {
        'r': {
            'foo': 'bac',
            'spam': 'eggs'
        },
        'p': {
            'foo': 'bac',
            'spam': 'eggs'
        }
    }

    m = SkipListsMerger(r,
                        h,
                        u,
                        DictMergerOps.FALLBACK_KEEP_HEAD,
                        custom_ops=custom_ops)

    with pytest.raises(MergeError) as excinfo:
        m.merge()

    assert m.merged_root == expected
    assert m.conflicts == excinfo.value.content
    assert len(m.conflicts) == 4
    assert Conflict(ConflictType.SET_FIELD, ('p', 'foo'), 'bab') in m.conflicts
    assert Conflict(ConflictType.SET_FIELD, ('p', 'foo'), 'bab') in m.conflicts
    assert Conflict(ConflictType.SET_FIELD, ('p', 'foo'), 'bab') in m.conflicts
    assert Conflict(ConflictType.SET_FIELD, ('p', 'foo'), 'bab') in m.conflicts
Пример #9
0
def test_to_json_when_path_has_integers():
    conflict = Conflict('REMOVE_FIELD', ('foo', 0, 'bar', 1), None)
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == [
        {
            '$type': 'REMOVE_FIELD',
            'op': 'remove',
            'path': '/foo/0/bar/1',
            'value': None
        }
    ]
Пример #10
0
def test_to_json_with_remove_field():
    conflict = Conflict('REMOVE_FIELD', ('foo', 'bar'), None)
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == [
        {
            '$type': 'REMOVE_FIELD',
            'op': 'remove',
            'path': '/foo/bar',
            'value': None
        }
    ]
Пример #11
0
def test_to_json_with_add_back_to_head():
    conflict = Conflict('ADD_BACK_TO_HEAD', ('foo', 'bar'), {})
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == [
        {
            '$type': 'ADD_BACK_TO_HEAD',
            'op': 'add',
            'path': '/foo/bar/-',
            'value': {}
        }
    ]
Пример #12
0
def test_to_json_with_set_field():
    conflict = Conflict('SET_FIELD', ('foo', 'bar'), {})
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == [
        {
            '$type': 'SET_FIELD',
            'op': 'replace',
            'path': '/foo/bar',
            'value': {}
        }
    ]
Пример #13
0
def test_to_json_with_reorder():
    conflict = Conflict('REORDER', ('foo', 'bar'), {})
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == [
        {
            '$type': 'REORDER',
            'op': 'replace',
            'path': '/foo/bar',
            'value': {}
        }
    ]
Пример #14
0
def test_base_values_exceptions():
    m = SkipListsMerger(1, 3, 2, DictMergerOps.FALLBACK_KEEP_HEAD)
    with pytest.raises(MergeError):
        m.merge()
    assert m.conflicts[0] == Conflict(ConflictType.SET_FIELD, (), 2)
    assert m.merged_root == 3

    m = SkipListsMerger(1, 3, 2, DictMergerOps.FALLBACK_KEEP_UPDATE)
    with pytest.raises(MergeError):
        m.merge()
    assert m.conflicts[0] == Conflict(ConflictType.SET_FIELD, (), 3)
    assert m.merged_root == 2
Пример #15
0
def test_simple_remove_conflict():
    r = {'foo1': 'bar', 'foo2': 'bar'}
    h = {'foo1': 'baz', 'foo2': 'baz'}
    u = {}

    m = SkipListsMerger(r, h, u, DictMergerOps.FALLBACK_KEEP_HEAD)
    with pytest.raises(MergeError) as excinfo:
        m.merge()

    assert m.merged_root == {'foo1': 'baz', 'foo2': 'baz'}
    assert m.conflicts == excinfo.value.content
    assert len(m.conflicts) == 2
    assert Conflict(ConflictType.REMOVE_FIELD, ('foo1', ), None) in m.conflicts
    assert Conflict(ConflictType.REMOVE_FIELD, ('foo2', ), None) in m.conflicts
Пример #16
0
def _process_add_back_to_head(conflict, merged):
    """Process ADD_BACK_TO_HEAD conflicts differently than other conflicts.

    Replace all ADD_BACK_TO_HEAD conflicts to became REMOVE_FIELD conflicts
    also adds value from conflict back to merged_root
    REMOVE_FIELD conflict now points to proper element on list.
    """
    conflict_type, conflict_location, conflict_content = conflict
    if conflict_location[0] == "authors":
        position, merged["authors"] = _insert_to_list(conflict_content,
                                                      merged["authors"])
        insert_path = ("authors", position)
        new_conflict = Conflict("REMOVE_FIELD", insert_path, None)
        return new_conflict, merged
    else:
        insert_path, merged = _additem(conflict_content, merged,
                                       conflict_location)
        new_conflict = Conflict("REMOVE_FIELD", insert_path, None)
        return new_conflict, merged
Пример #17
0
def test_to_json_with_manual_merge():
    body = [None, {'foo1': 'bar1'}, {'foo2': 'bar2'}]
    conflict = Conflict('MANUAL_MERGE', ('foo', 'bar'), body)
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == [{
        '$type': 'MANUAL_MERGE',
        'op': 'add',
        'path': '/foo/bar/-',
        'value': {
            'foo1': 'bar1'
        }
    }, {
        '$type': 'MANUAL_MERGE',
        'op': 'add',
        'path': '/foo/bar/-',
        'value': {
            'foo2': 'bar2'
        }
    }]
Пример #18
0
def assert_ordered_conflicts(conflicts, expected_conflicts):
    # expected conflict is a Conflict class instance
    expected_conflict = [
        json.loads(Conflict(c[0], c[1], c[2]).to_json())
        for c in expected_conflicts
    ]

    # order the lists to check if they match
    conflicts = sorted(conflicts, key=lambda c: c['path'])
    expected_conflict = sorted(expected_conflict, key=lambda c: c['path'])

    assert conflicts == expected_conflict
Пример #19
0
def test_custom_fallback():
    r = {'r': {'foo': 'baa'}}
    h = {'r': {'foo': 'bab'}}
    u = {'r': {'foo': 'bac'}}

    m = SkipListsMerger(r, h, u, DictMergerOps.FALLBACK_KEEP_HEAD)
    with pytest.raises(MergeError) as excinfo:
        m.merge()

    assert m.merged_root == {'r': {'foo': 'bab'}}
    assert m.conflicts == excinfo.value.content
    assert len(m.conflicts) == 1
    assert Conflict(ConflictType.SET_FIELD, ('r', 'foo'), 'bac') in m.conflicts
Пример #20
0
def test_to_json_with_manual_merge():
    body = [
        None,
        {'foo1': 'bar1'},
        {'foo2': 'bar2'}
    ]
    conflict = Conflict('MANUAL_MERGE', ('foo', 'bar'), body)
    conflict_json = conflict.to_json()
    assert json.loads(conflict_json) == [
        {
            '$type': 'MANUAL_MERGE',
            'op': 'add',
            'path': '/foo/bar/-',
            'value': {'foo1': 'bar1'}
        },
        {
            '$type': 'MANUAL_MERGE',
            'op': 'add',
            'path': '/foo/bar/-',
            'value': {'foo2': 'bar2'}
        }
    ]
Пример #21
0
def _process_author_manual_merge_conflict(conflict, merged):
    """Process author `MANUAL_MERGE` conflict.

    Conflict object is an tuple containing:
    (conflict_type, conflict_location, conflict_data)
    where `conflict_data` is a tuple of: (ROOT, HEAD, UPDATE).
    """
    _, _, (root, head, update) = conflict
    if head and head not in merged["authors"]:
        position, merged["authors"] = _insert_to_list(head, merged["authors"])
        new_conflict = Conflict("SET_FIELD", ("authors", position), update)
        return new_conflict, merged, head
    return None, merged, head
Пример #22
0
def test_simple_conflicts_keep_head():
    r = {}
    h = {'foo': 'bar'}
    u = {'foo': 'baz'}

    m = SkipListsMerger(r, h, u, DictMergerOps.FALLBACK_KEEP_HEAD)
    with pytest.raises(MergeError) as excinfo:
        m.merge()

    assert m.merged_root == {'foo': 'bar'}
    assert m.conflicts == excinfo.value.content
    assert len(m.conflicts) == 1
    assert Conflict(ConflictType.SET_FIELD, ('foo', ), 'baz') in m.conflicts
Пример #23
0
def test_merge_list_with_string():
    r = 'somerandomvalue'
    h = [1, 2, 3]
    u = 'a given string'

    m = Merger(r, h, u, DictMergerOps.FALLBACK_KEEP_HEAD,
               UnifierOps.KEEP_ONLY_UPDATE_ENTITIES)
    with pytest.raises(MergeError) as excinfo:
        m.merge()

    assert m.merged_root == [1, 2, 3]
    assert len(excinfo.value.content) == 1
    assert excinfo.value.content[0] == Conflict(ConflictType.SET_FIELD, (),
                                                'a given string')
Пример #24
0
def test_one_list_delete_touched_in_head_raises_conflict():
    r = {'r': {'x': 1, 'l': [1, 2, 3]}}
    h = {'r': {'x': 1, 'l': [4, 3, 2, 1]}}
    u = {'r': {'x': 2}}

    m = SkipListsMerger(r, h, u, DictMergerOps.FALLBACK_KEEP_HEAD)
    with pytest.raises(MergeError) as excinfo:
        m.merge()

    assert m.merged_root == {'r': {'x': 2, 'l': [4, 3, 2, 1]}}
    assert len(m.skipped_lists) == 0
    assert m.conflicts == excinfo.value.content
    assert len(m.conflicts) == 1
    assert Conflict(ConflictType.REMOVE_FIELD, ('r', 'l'), None) in m.conflicts
Пример #25
0
def update_conflicts_list(conflict, conflict_list):
    """Updates positions in provided conflict_list for conflict which will be added

    Args:
        conflict(Conflict): New conflict
        conflict_list(list): List of conflicts where positions should be updated
    """
    new_type, new_path, new_content = conflict
    for idx, processed_conflict in enumerate(conflict_list):
        path = processed_conflict[1]
        if path[0] == new_path[0] and len(path) > 1 and len(
                new_path) > 1 and path[1] >= new_path[1]:
            path = list(path)
            path[1] += 1
            path = tuple(path)
            conflict_list[idx] = Conflict(processed_conflict[0], path,
                                          processed_conflict[2])
    return conflict_list
def test_is_to_delete_true_longer_path():
    c = Conflict('SET_FIELD', ('figures', 0, 'key'), 'figure1.png')
    to_delete = 'figures.key'
    assert is_to_delete(c, to_delete) is True
Пример #27
0
def _deserialize_conflict(conflict_type, path, body):
    if conflict_type == ConflictType.MANUAL_MERGE:
        body = tuple(body)
    return Conflict(conflict_type, tuple(path), body)
def test_conflict_to_list():
    c = Conflict('SET_FIELD', ('figures', 0, 'key'), 'figure1.png')
    assert conflict_to_list(c) == ['figures', 'key']
def test_is_to_delete_false():
    c = Conflict('SET_FIELD', ('figures', 0, 'key'), 'figure1.png')
    to_delete = 'authors'
    assert is_to_delete(c, to_delete) is False
def test_is_to_delete_wrong_path():
    c = Conflict('SET_FIELD', ('figures', 0, 'key'), 'figure1.png')
    to_delete = 'figures.keys'
    assert is_to_delete(c, to_delete) is False
def test_is_to_delete_manual_merge():
    c = Conflict('MANUAL_MERGE', ('figures', 0, 'key'), 'figure1.png')
    to_delete = 'figures'
    assert is_to_delete(c, to_delete) is False