"""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'}}}