233 lines
12 KiB
Python
233 lines
12 KiB
Python
"""Tests for diff."""
|
|
import pytest
|
|
from copy import deepcopy
|
|
|
|
from jaydiff.diff import diff_full, diff_add, diff_del, diff_upd, diff_upd_add
|
|
|
|
|
|
# ── diff_add ──────────────────────────────────────────────────────────────
|
|
|
|
class TestJayDiffAdd:
|
|
def test_add_to_empty(self):
|
|
assert diff_add({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}) \
|
|
== {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
|
|
def test_no_new_keys(self):
|
|
assert diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) == {}
|
|
|
|
def test_old_has_extra_keys(self):
|
|
assert diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}) == {}
|
|
|
|
def test_one_new_key(self):
|
|
assert diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
{'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}) == {'d': 'icecream'}
|
|
|
|
def test_new_key_among_overlap(self):
|
|
assert diff_add({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) == {'b': 'fries'}
|
|
|
|
def test_nested_new_key(self):
|
|
assert diff_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}},
|
|
{'c': {'f': 'coffee'}}) == {'c': {'f': 'coffee'}}
|
|
|
|
def test_nested_no_new_keys(self):
|
|
assert diff_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}) == {}
|
|
|
|
|
|
# ── diff_del ──────────────────────────────────────────────────────────────
|
|
|
|
class TestJayDiffDel:
|
|
def test_one_deleted_key(self):
|
|
assert diff_del({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) == {'d': 'icecream'}
|
|
|
|
def test_no_deleted_keys_same_values(self):
|
|
assert diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'coke'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) == {}
|
|
|
|
def test_no_deleted_keys_different_values(self):
|
|
assert diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'coke'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}) == {}
|
|
|
|
def test_key_absent_from_new(self):
|
|
assert diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
{'a': 'hamburger', 'b': 'fries'}) == {'c': 'pepsi'}
|
|
|
|
def test_nested_deleted_key(self):
|
|
# 'c' is absent from _new → None signals "delete entire key"
|
|
assert diff_del({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hamburger', 'b': 'fries'}) == {'c': None}
|
|
|
|
def test_nested_partial_delete(self):
|
|
assert diff_del({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'c': {'e': 'coke'}}) == {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}
|
|
|
|
def test_nested_no_delete_different_value(self):
|
|
assert diff_del({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}) == {}
|
|
|
|
|
|
# ── diff_upd ──────────────────────────────────────────────────────────────
|
|
|
|
class TestJayDiffUpd:
|
|
def test_multiple_updates(self):
|
|
assert diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hotdog', 'b': 'potatoes'}) == {'a': 'hotdog', 'b': 'potatoes'}
|
|
|
|
def test_nested_update(self):
|
|
assert diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'c': {'e': 'pepsi'}}) == {'c': {'e': 'pepsi'}}
|
|
|
|
def test_one_update(self):
|
|
assert diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hotdog', 'b': 'fries'}) == {'a': 'hotdog'}
|
|
|
|
def test_no_update_new_key_ignored(self):
|
|
assert diff_upd({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
{'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}) == {'c': 'coke'}
|
|
|
|
def test_nested_no_update_new_subkey_ignored(self):
|
|
assert diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}},
|
|
{'c': {'f': 'coffee'}}) == {}
|
|
|
|
def test_nested_update_one_of_two(self):
|
|
assert diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}) \
|
|
== {'c': {'e': 'pepsi'}}
|
|
|
|
|
|
# ── diff_upd_add ──────────────────────────────────────────────────────────
|
|
|
|
class TestJayDiffUpdAdd:
|
|
def test_update_and_add(self):
|
|
assert diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hotdog', 'b': 'potatoes', 'd': 'icecream'}) \
|
|
== {'a': 'hotdog', 'b': 'potatoes', 'd': 'icecream'}
|
|
|
|
def test_nested_update_and_add(self):
|
|
assert diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}, 'b': 'potatoes'}) \
|
|
== {'b': 'potatoes', 'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}}
|
|
|
|
def test_update_only(self):
|
|
assert diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hotdog', 'b': 'fries'}) == {'a': 'hotdog'}
|
|
|
|
def test_nested_update_and_new_subkey(self):
|
|
assert diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}) \
|
|
== {'c': {'e': 'pepsi', 'h': 'cake'}}
|
|
|
|
def test_add_new_top_and_update(self):
|
|
assert diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
{'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}) \
|
|
== {'c': 'coke', 'd': 'icecream'}
|
|
|
|
def test_identical(self):
|
|
assert diff_upd_add({'a': 'hamburger', 'b': 'fries'},
|
|
{'a': 'hamburger', 'b': 'fries'}) == {}
|
|
|
|
|
|
# ── diff_full (combine_upd_add=False) ─────────────────────────────────────
|
|
|
|
class TestJayDiffFullSeparate:
|
|
F = False
|
|
|
|
def test_add_all(self):
|
|
assert diff_full({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, self.F) \
|
|
== {'add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}}
|
|
|
|
def test_update_one(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, self.F) \
|
|
== {'update': {'c': 'coke'}}
|
|
|
|
def test_delete_one(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, self.F) \
|
|
== {'delete': {'d': 'icecream'}}
|
|
|
|
def test_add_delete_update(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
{'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}, self.F) \
|
|
== {'add': {'d': 'icecream'}, 'delete': {'b': 'fries'}, 'update': {'c': 'coke'}}
|
|
|
|
def test_identical(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, self.F) == {}
|
|
|
|
def test_delete_nested(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hamburger', 'b': 'fries'}, self.F) \
|
|
== {'delete': {'c': None}}
|
|
|
|
def test_nested_partial_delete(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, self.F) \
|
|
== {'delete': {'c': {'e': 'coke'}}}
|
|
|
|
def test_update_and_delete(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hotdog', 'b': 'potatoes'}, self.F) \
|
|
== {'delete': {'c': None}, 'update': {'a': 'hotdog', 'b': 'potatoes'}}
|
|
|
|
def test_nested_add_delete_update(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hotdog', 'b': 'potatoes', 'd': 'icecream'}, self.F) \
|
|
== {'add': {'d': 'icecream'}, 'delete': {'c': None}, 'update': {'a': 'hotdog', 'b': 'potatoes'}}
|
|
|
|
|
|
# ── diff_full (combine_upd_add=True) ──────────────────────────────────────
|
|
|
|
class TestJayDiffFullCombined:
|
|
T = True
|
|
|
|
def test_add_all(self):
|
|
assert diff_full({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, self.T) \
|
|
== {'update_add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}}
|
|
|
|
def test_update_one(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, self.T) \
|
|
== {'update_add': {'c': 'coke'}}
|
|
|
|
def test_delete_one(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, self.T) \
|
|
== {'delete': {'d': 'icecream'}}
|
|
|
|
def test_delete_and_update_add(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
{'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}, self.T) \
|
|
== {'delete': {'b': 'fries'}, 'update_add': {'c': 'coke', 'd': 'icecream'}}
|
|
|
|
def test_identical(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, self.T) == {}
|
|
|
|
def test_delete_nested(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hamburger', 'b': 'fries'}, self.T) \
|
|
== {'delete': {'c': None}}
|
|
|
|
def test_update_and_delete_nested(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hotdog', 'b': 'potatoes'}, self.T) \
|
|
== {'delete': {'c': None}, 'update_add': {'a': 'hotdog', 'b': 'potatoes'}}
|
|
|
|
def test_nested_update_add_and_delete(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}, 'b': 'potatoes'}, self.T) \
|
|
== {'delete': {'a': 'hamburger', 'c': {'f': 'coffee'}},
|
|
'update_add': {'b': 'potatoes', 'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}}}
|
|
|
|
def test_nested_add_subkey(self):
|
|
assert diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
{'a': 'hamburger', 'b': 'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}, self.T) \
|
|
== {'update_add': {'c': {'e': 'pepsi', 'h': 'cake'}}}
|
|
|
|
|