123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500 |
- # -*- coding: utf-8 -*-
- """
- Tests for salt.utils.data
- """
- # Import Python libs
- from __future__ import absolute_import, print_function, unicode_literals
- import logging
- # Import Salt libs
- import salt.utils.data
- import salt.utils.stringutils
- from salt.ext import six
- # Import 3rd party libs
- from salt.ext.six.moves import ( # pylint: disable=import-error,redefined-builtin
- builtins,
- )
- from salt.utils.odict import OrderedDict
- from tests.support.mock import patch
- from tests.support.unit import LOREM_IPSUM, TestCase
- log = logging.getLogger(__name__)
- _b = lambda x: x.encode("utf-8")
- _s = lambda x: salt.utils.stringutils.to_str(x, normalize=True)
- # Some randomized data that will not decode
- BYTES = b"1\x814\x10"
- # This is an example of a unicode string with й constructed using two separate
- # code points. Do not modify it.
- EGGS = "\u044f\u0438\u0306\u0446\u0430"
- class DataTestCase(TestCase):
- test_data = [
- "unicode_str",
- _b("питон"),
- 123,
- 456.789,
- True,
- False,
- None,
- EGGS,
- BYTES,
- [123, 456.789, _b("спам"), True, False, None, EGGS, BYTES],
- (987, 654.321, _b("яйца"), EGGS, None, (True, EGGS, BYTES)),
- {
- _b("str_key"): _b("str_val"),
- None: True,
- 123: 456.789,
- EGGS: BYTES,
- _b("subdict"): {
- "unicode_key": EGGS,
- _b("tuple"): (123, "hello", _b("world"), True, EGGS, BYTES),
- _b("list"): [456, _b("спам"), False, EGGS, BYTES],
- },
- },
- OrderedDict([(_b("foo"), "bar"), (123, 456), (EGGS, BYTES)]),
- ]
- def test_sorted_ignorecase(self):
- test_list = ["foo", "Foo", "bar", "Bar"]
- expected_list = ["bar", "Bar", "foo", "Foo"]
- self.assertEqual(salt.utils.data.sorted_ignorecase(test_list), expected_list)
- def test_mysql_to_dict(self):
- test_mysql_output = [
- "+----+------+-----------+------+---------+------+-------+------------------+",
- "| Id | User | Host | db | Command | Time | State | Info |",
- "+----+------+-----------+------+---------+------+-------+------------------+",
- "| 7 | root | localhost | NULL | Query | 0 | init | show processlist |",
- "+----+------+-----------+------+---------+------+-------+------------------+",
- ]
- ret = salt.utils.data.mysql_to_dict(test_mysql_output, "Info")
- expected_dict = {
- "show processlist": {
- "Info": "show processlist",
- "db": "NULL",
- "State": "init",
- "Host": "localhost",
- "Command": "Query",
- "User": "root",
- "Time": 0,
- "Id": 7,
- }
- }
- self.assertDictEqual(ret, expected_dict)
- def test_subdict_match(self):
- test_two_level_dict = {"foo": {"bar": "baz"}}
- test_two_level_comb_dict = {"foo": {"bar": "baz:woz"}}
- test_two_level_dict_and_list = {
- "abc": ["def", "ghi", {"lorem": {"ipsum": [{"dolor": "sit"}]}}],
- }
- test_three_level_dict = {"a": {"b": {"c": "v"}}}
- self.assertTrue(
- salt.utils.data.subdict_match(test_two_level_dict, "foo:bar:baz")
- )
- # In test_two_level_comb_dict, 'foo:bar' corresponds to 'baz:woz', not
- # 'baz'. This match should return False.
- self.assertFalse(
- salt.utils.data.subdict_match(test_two_level_comb_dict, "foo:bar:baz")
- )
- # This tests matching with the delimiter in the value part (in other
- # words, that the path 'foo:bar' corresponds to the string 'baz:woz').
- self.assertTrue(
- salt.utils.data.subdict_match(test_two_level_comb_dict, "foo:bar:baz:woz")
- )
- # This would match if test_two_level_comb_dict['foo']['bar'] was equal
- # to 'baz:woz:wiz', or if there was more deep nesting. But it does not,
- # so this should return False.
- self.assertFalse(
- salt.utils.data.subdict_match(
- test_two_level_comb_dict, "foo:bar:baz:woz:wiz"
- )
- )
- # This tests for cases when a key path corresponds to a list. The
- # value part 'ghi' should be successfully matched as it is a member of
- # the list corresponding to key path 'abc'. It is somewhat a
- # duplication of a test within test_traverse_dict_and_list, but
- # salt.utils.data.subdict_match() does more than just invoke
- # salt.utils.traverse_list_and_dict() so this particular assertion is a
- # sanity check.
- self.assertTrue(
- salt.utils.data.subdict_match(test_two_level_dict_and_list, "abc:ghi")
- )
- # This tests the use case of a dict embedded in a list, embedded in a
- # list, embedded in a dict. This is a rather absurd case, but it
- # confirms that match recursion works properly.
- self.assertTrue(
- salt.utils.data.subdict_match(
- test_two_level_dict_and_list, "abc:lorem:ipsum:dolor:sit"
- )
- )
- # Test four level dict match for reference
- self.assertTrue(salt.utils.data.subdict_match(test_three_level_dict, "a:b:c:v"))
- # Test regression in 2015.8 where 'a:c:v' would match 'a:b:c:v'
- self.assertFalse(salt.utils.data.subdict_match(test_three_level_dict, "a:c:v"))
- # Test wildcard match
- self.assertTrue(salt.utils.data.subdict_match(test_three_level_dict, "a:*:c:v"))
- def test_subdict_match_with_wildcards(self):
- """
- Tests subdict matching when wildcards are used in the expression
- """
- data = {"a": {"b": {"ç": "d", "é": ["eff", "gee", "8ch"], "ĩ": {"j": "k"}}}}
- assert salt.utils.data.subdict_match(data, "*:*:*:*")
- assert salt.utils.data.subdict_match(data, "a:*:*:*")
- assert salt.utils.data.subdict_match(data, "a:b:*:*")
- assert salt.utils.data.subdict_match(data, "a:b:ç:*")
- assert salt.utils.data.subdict_match(data, "a:b:*:d")
- assert salt.utils.data.subdict_match(data, "a:*:ç:d")
- assert salt.utils.data.subdict_match(data, "*:b:ç:d")
- assert salt.utils.data.subdict_match(data, "*:*:ç:d")
- assert salt.utils.data.subdict_match(data, "*:*:*:d")
- assert salt.utils.data.subdict_match(data, "a:*:*:d")
- assert salt.utils.data.subdict_match(data, "a:b:*:ef*")
- assert salt.utils.data.subdict_match(data, "a:b:*:g*")
- assert salt.utils.data.subdict_match(data, "a:b:*:j:*")
- assert salt.utils.data.subdict_match(data, "a:b:*:j:k")
- assert salt.utils.data.subdict_match(data, "a:b:*:*:k")
- assert salt.utils.data.subdict_match(data, "a:b:*:*:*")
- def test_traverse_dict(self):
- test_two_level_dict = {"foo": {"bar": "baz"}}
- self.assertDictEqual(
- {"not_found": "nope"},
- salt.utils.data.traverse_dict(
- test_two_level_dict, "foo:bar:baz", {"not_found": "nope"}
- ),
- )
- self.assertEqual(
- "baz",
- salt.utils.data.traverse_dict(
- test_two_level_dict, "foo:bar", {"not_found": "not_found"}
- ),
- )
- def test_traverse_dict_and_list(self):
- test_two_level_dict = {"foo": {"bar": "baz"}}
- test_two_level_dict_and_list = {
- "foo": ["bar", "baz", {"lorem": {"ipsum": [{"dolor": "sit"}]}}]
- }
- # Check traversing too far: salt.utils.data.traverse_dict_and_list() returns
- # the value corresponding to a given key path, and baz is a value
- # corresponding to the key path foo:bar.
- self.assertDictEqual(
- {"not_found": "nope"},
- salt.utils.data.traverse_dict_and_list(
- test_two_level_dict, "foo:bar:baz", {"not_found": "nope"}
- ),
- )
- # Now check to ensure that foo:bar corresponds to baz
- self.assertEqual(
- "baz",
- salt.utils.data.traverse_dict_and_list(
- test_two_level_dict, "foo:bar", {"not_found": "not_found"}
- ),
- )
- # Check traversing too far
- self.assertDictEqual(
- {"not_found": "nope"},
- salt.utils.data.traverse_dict_and_list(
- test_two_level_dict_and_list, "foo:bar", {"not_found": "nope"}
- ),
- )
- # Check index 1 (2nd element) of list corresponding to path 'foo'
- self.assertEqual(
- "baz",
- salt.utils.data.traverse_dict_and_list(
- test_two_level_dict_and_list, "foo:1", {"not_found": "not_found"}
- ),
- )
- # Traverse a couple times into dicts embedded in lists
- self.assertEqual(
- "sit",
- salt.utils.data.traverse_dict_and_list(
- test_two_level_dict_and_list,
- "foo:lorem:ipsum:dolor",
- {"not_found": "not_found"},
- ),
- )
- # Traverse and match integer key in a nested dict
- # https://github.com/saltstack/salt/issues/56444
- self.assertEqual(
- "it worked",
- salt.utils.data.traverse_dict_and_list(
- {"foo": {1234: "it worked"}}, "foo:1234", "it didn't work",
- ),
- )
- # Make sure that we properly return the default value when the initial
- # attempt fails and YAML-loading the target key doesn't change its
- # value.
- self.assertEqual(
- "default",
- salt.utils.data.traverse_dict_and_list(
- {"foo": {"baz": "didn't work"}}, "foo:bar", "default",
- ),
- )
- def test_compare_dicts(self):
- ret = salt.utils.data.compare_dicts(old={"foo": "bar"}, new={"foo": "bar"})
- self.assertEqual(ret, {})
- ret = salt.utils.data.compare_dicts(old={"foo": "bar"}, new={"foo": "woz"})
- expected_ret = {"foo": {"new": "woz", "old": "bar"}}
- self.assertDictEqual(ret, expected_ret)
- def test_compare_lists_no_change(self):
- ret = salt.utils.data.compare_lists(
- old=[1, 2, 3, "a", "b", "c"], new=[1, 2, 3, "a", "b", "c"]
- )
- expected = {}
- self.assertDictEqual(ret, expected)
- def test_compare_lists_changes(self):
- ret = salt.utils.data.compare_lists(
- old=[1, 2, 3, "a", "b", "c"], new=[1, 2, 4, "x", "y", "z"]
- )
- expected = {"new": [4, "x", "y", "z"], "old": [3, "a", "b", "c"]}
- self.assertDictEqual(ret, expected)
- def test_compare_lists_changes_new(self):
- ret = salt.utils.data.compare_lists(old=[1, 2, 3], new=[1, 2, 3, "x", "y", "z"])
- expected = {"new": ["x", "y", "z"]}
- self.assertDictEqual(ret, expected)
- def test_compare_lists_changes_old(self):
- ret = salt.utils.data.compare_lists(old=[1, 2, 3, "a", "b", "c"], new=[1, 2, 3])
- expected = {"old": ["a", "b", "c"]}
- self.assertDictEqual(ret, expected)
- def test_decode(self):
- """
- Companion to test_decode_to_str, they should both be kept up-to-date
- with one another.
- NOTE: This uses the lambda "_b" defined above in the global scope,
- which encodes a string to a bytestring, assuming utf-8.
- """
- expected = [
- "unicode_str",
- "питон",
- 123,
- 456.789,
- True,
- False,
- None,
- "яйца",
- BYTES,
- [123, 456.789, "спам", True, False, None, "яйца", BYTES],
- (987, 654.321, "яйца", "яйца", None, (True, "яйца", BYTES)),
- {
- "str_key": "str_val",
- None: True,
- 123: 456.789,
- "яйца": BYTES,
- "subdict": {
- "unicode_key": "яйца",
- "tuple": (123, "hello", "world", True, "яйца", BYTES),
- "list": [456, "спам", False, "яйца", BYTES],
- },
- },
- OrderedDict([("foo", "bar"), (123, 456), ("яйца", BYTES)]),
- ]
- ret = salt.utils.data.decode(
- self.test_data,
- keep=True,
- normalize=True,
- preserve_dict_class=True,
- preserve_tuples=True,
- )
- self.assertEqual(ret, expected)
- # The binary data in the data structure should fail to decode, even
- # using the fallback, and raise an exception.
- self.assertRaises(
- UnicodeDecodeError,
- salt.utils.data.decode,
- self.test_data,
- keep=False,
- normalize=True,
- preserve_dict_class=True,
- preserve_tuples=True,
- )
- # Now munge the expected data so that we get what we would expect if we
- # disable preservation of dict class and tuples
- expected[10] = [987, 654.321, "яйца", "яйца", None, [True, "яйца", BYTES]]
- expected[11]["subdict"]["tuple"] = [123, "hello", "world", True, "яйца", BYTES]
- expected[12] = {"foo": "bar", 123: 456, "яйца": BYTES}
- ret = salt.utils.data.decode(
- self.test_data,
- keep=True,
- normalize=True,
- preserve_dict_class=False,
- preserve_tuples=False,
- )
- self.assertEqual(ret, expected)
- # Now test single non-string, non-data-structure items, these should
- # return the same value when passed to this function
- for item in (123, 4.56, True, False, None):
- log.debug("Testing decode of %s", item)
- self.assertEqual(salt.utils.data.decode(item), item)
- # Test single strings (not in a data structure)
- self.assertEqual(salt.utils.data.decode("foo"), "foo")
- self.assertEqual(salt.utils.data.decode(_b("bar")), "bar")
- self.assertEqual(salt.utils.data.decode(EGGS, normalize=True), "яйца")
- self.assertEqual(salt.utils.data.decode(EGGS, normalize=False), EGGS)
- # Test binary blob
- self.assertEqual(salt.utils.data.decode(BYTES, keep=True), BYTES)
- self.assertRaises(UnicodeDecodeError, salt.utils.data.decode, BYTES, keep=False)
- def test_circular_refs_dicts(self):
- test_dict = {"key": "value", "type": "test1"}
- test_dict["self"] = test_dict
- ret = salt.utils.data._remove_circular_refs(ob=test_dict)
- self.assertDictEqual(ret, {"key": "value", "type": "test1", "self": None})
- def test_circular_refs_lists(self):
- test_list = {
- "foo": [],
- }
- test_list["foo"].append((test_list,))
- ret = salt.utils.data._remove_circular_refs(ob=test_list)
- self.assertDictEqual(ret, {"foo": [(None,)]})
- def test_circular_refs_tuple(self):
- test_dup = {"foo": "string 1", "bar": "string 1", "ham": 1, "spam": 1}
- ret = salt.utils.data._remove_circular_refs(ob=test_dup)
- self.assertDictEqual(
- ret, {"foo": "string 1", "bar": "string 1", "ham": 1, "spam": 1}
- )
- def test_decode_to_str(self):
- """
- Companion to test_decode, they should both be kept up-to-date with one
- another.
- NOTE: This uses the lambda "_s" defined above in the global scope,
- which converts the string/bytestring to a str type.
- """
- expected = [
- _s("unicode_str"),
- _s("питон"),
- 123,
- 456.789,
- True,
- False,
- None,
- _s("яйца"),
- BYTES,
- [123, 456.789, _s("спам"), True, False, None, _s("яйца"), BYTES],
- (987, 654.321, _s("яйца"), _s("яйца"), None, (True, _s("яйца"), BYTES)),
- {
- _s("str_key"): _s("str_val"),
- None: True,
- 123: 456.789,
- _s("яйца"): BYTES,
- _s("subdict"): {
- _s("unicode_key"): _s("яйца"),
- _s("tuple"): (
- 123,
- _s("hello"),
- _s("world"),
- True,
- _s("яйца"),
- BYTES,
- ),
- _s("list"): [456, _s("спам"), False, _s("яйца"), BYTES],
- },
- },
- OrderedDict([(_s("foo"), _s("bar")), (123, 456), (_s("яйца"), BYTES)]),
- ]
- ret = salt.utils.data.decode(
- self.test_data,
- keep=True,
- normalize=True,
- preserve_dict_class=True,
- preserve_tuples=True,
- to_str=True,
- )
- self.assertEqual(ret, expected)
- if six.PY3:
- # The binary data in the data structure should fail to decode, even
- # using the fallback, and raise an exception.
- self.assertRaises(
- UnicodeDecodeError,
- salt.utils.data.decode,
- self.test_data,
- keep=False,
- normalize=True,
- preserve_dict_class=True,
- preserve_tuples=True,
- to_str=True,
- )
- # Now munge the expected data so that we get what we would expect if we
- # disable preservation of dict class and tuples
- expected[10] = [
- 987,
- 654.321,
- _s("яйца"),
- _s("яйца"),
- None,
- [True, _s("яйца"), BYTES],
- ]
- expected[11][_s("subdict")][_s("tuple")] = [
- 123,
- _s("hello"),
- _s("world"),
- True,
- _s("яйца"),
- BYTES,
- ]
- expected[12] = {_s("foo"): _s("bar"), 123: 456, _s("яйца"): BYTES}
- ret = salt.utils.data.decode(
- self.test_data,
- keep=True,
- normalize=True,
- preserve_dict_class=False,
- preserve_tuples=False,
- to_str=True,
- )
- self.assertEqual(ret, expected)
- # Now test single non-string, non-data-structure items, these should
- # return the same value when passed to this function
- for item in (123, 4.56, True, False, None):
- log.debug("Testing decode of %s", item)
- self.assertEqual(salt.utils.data.decode(item, to_str=True), item)
- # Test single strings (not in a data structure)
- self.assertEqual(salt.utils.data.decode("foo", to_str=True), _s("foo"))
- self.assertEqual(salt.utils.data.decode(_b("bar"), to_str=True), _s("bar"))
- # Test binary blob
- self.assertEqual(salt.utils.data.decode(BYTES, keep=True, to_str=True), BYTES)
- if six.PY3:
- self.assertRaises(
- UnicodeDecodeError,
- salt.utils.data.decode,
- BYTES,
- keep=False,
- to_str=True,
- )
- def test_decode_fallback(self):
- """
- Test fallback to utf-8
- """
- with patch.object(builtins, "__salt_system_encoding__", "ascii"):
- self.assertEqual(salt.utils.data.decode(_b("яйца")), "яйца")
- def test_encode(self):
- """
- NOTE: This uses the lambda "_b" defined above in the global scope,
- which encodes a string to a bytestring, assuming utf-8.
- """
- expected = [
- _b("unicode_str"),
- _b("питон"),
- 123,
- 456.789,
- True,
- False,
- None,
- _b(EGGS),
- BYTES,
- [123, 456.789, _b("спам"), True, False, None, _b(EGGS), BYTES],
- (987, 654.321, _b("яйца"), _b(EGGS), None, (True, _b(EGGS), BYTES)),
- {
- _b("str_key"): _b("str_val"),
- None: True,
- 123: 456.789,
- _b(EGGS): BYTES,
- _b("subdict"): {
- _b("unicode_key"): _b(EGGS),
- _b("tuple"): (123, _b("hello"), _b("world"), True, _b(EGGS), BYTES),
- _b("list"): [456, _b("спам"), False, _b(EGGS), BYTES],
- },
- },
- OrderedDict([(_b("foo"), _b("bar")), (123, 456), (_b(EGGS), BYTES)]),
- ]
- # Both keep=True and keep=False should work because the BYTES data is
- # already bytes.
- ret = salt.utils.data.encode(
- self.test_data, keep=True, preserve_dict_class=True, preserve_tuples=True
- )
- self.assertEqual(ret, expected)
- ret = salt.utils.data.encode(
- self.test_data, keep=False, preserve_dict_class=True, preserve_tuples=True
- )
- self.assertEqual(ret, expected)
- # Now munge the expected data so that we get what we would expect if we
- # disable preservation of dict class and tuples
- expected[10] = [
- 987,
- 654.321,
- _b("яйца"),
- _b(EGGS),
- None,
- [True, _b(EGGS), BYTES],
- ]
- expected[11][_b("subdict")][_b("tuple")] = [
- 123,
- _b("hello"),
- _b("world"),
- True,
- _b(EGGS),
- BYTES,
- ]
- expected[12] = {_b("foo"): _b("bar"), 123: 456, _b(EGGS): BYTES}
- ret = salt.utils.data.encode(
- self.test_data, keep=True, preserve_dict_class=False, preserve_tuples=False
- )
- self.assertEqual(ret, expected)
- ret = salt.utils.data.encode(
- self.test_data, keep=False, preserve_dict_class=False, preserve_tuples=False
- )
- self.assertEqual(ret, expected)
- # Now test single non-string, non-data-structure items, these should
- # return the same value when passed to this function
- for item in (123, 4.56, True, False, None):
- log.debug("Testing encode of %s", item)
- self.assertEqual(salt.utils.data.encode(item), item)
- # Test single strings (not in a data structure)
- self.assertEqual(salt.utils.data.encode("foo"), _b("foo"))
- self.assertEqual(salt.utils.data.encode(_b("bar")), _b("bar"))
- # Test binary blob, nothing should happen even when keep=False since
- # the data is already bytes
- self.assertEqual(salt.utils.data.encode(BYTES, keep=True), BYTES)
- self.assertEqual(salt.utils.data.encode(BYTES, keep=False), BYTES)
- def test_encode_keep(self):
- """
- Whereas we tested the keep argument in test_decode, it is much easier
- to do a more comprehensive test of keep in its own function where we
- can force the encoding.
- """
- unicode_str = "питон"
- encoding = "ascii"
- # Test single string
- self.assertEqual(
- salt.utils.data.encode(unicode_str, encoding, keep=True), unicode_str
- )
- self.assertRaises(
- UnicodeEncodeError,
- salt.utils.data.encode,
- unicode_str,
- encoding,
- keep=False,
- )
- data = [
- unicode_str,
- [b"foo", [unicode_str], {b"key": unicode_str}, (unicode_str,)],
- {
- b"list": [b"foo", unicode_str],
- b"dict": {b"key": unicode_str},
- b"tuple": (b"foo", unicode_str),
- },
- ([b"foo", unicode_str], {b"key": unicode_str}, (unicode_str,)),
- ]
- # Since everything was a bytestring aside from the bogus data, the
- # return data should be identical. We don't need to test recursive
- # decoding, that has already been tested in test_encode.
- self.assertEqual(
- salt.utils.data.encode(data, encoding, keep=True, preserve_tuples=True),
- data,
- )
- self.assertRaises(
- UnicodeEncodeError,
- salt.utils.data.encode,
- data,
- encoding,
- keep=False,
- preserve_tuples=True,
- )
- for index, _ in enumerate(data):
- self.assertEqual(
- salt.utils.data.encode(
- data[index], encoding, keep=True, preserve_tuples=True
- ),
- data[index],
- )
- self.assertRaises(
- UnicodeEncodeError,
- salt.utils.data.encode,
- data[index],
- encoding,
- keep=False,
- preserve_tuples=True,
- )
- def test_encode_fallback(self):
- """
- Test fallback to utf-8
- """
- with patch.object(builtins, "__salt_system_encoding__", "ascii"):
- self.assertEqual(salt.utils.data.encode("яйца"), _b("яйца"))
- with patch.object(builtins, "__salt_system_encoding__", "CP1252"):
- self.assertEqual(salt.utils.data.encode("Ψ"), _b("Ψ"))
- def test_repack_dict(self):
- list_of_one_element_dicts = [
- {"dict_key_1": "dict_val_1"},
- {"dict_key_2": "dict_val_2"},
- {"dict_key_3": "dict_val_3"},
- ]
- expected_ret = {
- "dict_key_1": "dict_val_1",
- "dict_key_2": "dict_val_2",
- "dict_key_3": "dict_val_3",
- }
- ret = salt.utils.data.repack_dictlist(list_of_one_element_dicts)
- self.assertDictEqual(ret, expected_ret)
- # Try with yaml
- yaml_key_val_pair = "- key1: val1"
- ret = salt.utils.data.repack_dictlist(yaml_key_val_pair)
- self.assertDictEqual(ret, {"key1": "val1"})
- # Make sure we handle non-yaml junk data
- ret = salt.utils.data.repack_dictlist(LOREM_IPSUM)
- self.assertDictEqual(ret, {})
- def test_stringify(self):
- self.assertRaises(TypeError, salt.utils.data.stringify, 9)
- self.assertEqual(
- salt.utils.data.stringify(
- ["one", "two", str("three"), 4, 5]
- ), # future lint: disable=blacklisted-function
- ["one", "two", "three", "4", "5"],
- )
- def test_json_query(self):
- # Raises exception if jmespath module is not found
- with patch("salt.utils.data.jmespath", None):
- self.assertRaisesRegex(
- RuntimeError, "requires jmespath", salt.utils.data.json_query, {}, "@"
- )
- # Test search
- user_groups = {
- "user1": {"groups": ["group1", "group2", "group3"]},
- "user2": {"groups": ["group1", "group2"]},
- "user3": {"groups": ["group3"]},
- }
- expression = "*.groups[0]"
- primary_groups = ["group1", "group1", "group3"]
- self.assertEqual(
- sorted(salt.utils.data.json_query(user_groups, expression)), primary_groups
- )
- class FilterFalseyTestCase(TestCase):
- """
- Test suite for salt.utils.data.filter_falsey
- """
- def test_nop(self):
- """
- Test cases where nothing will be done.
- """
- # Test with dictionary without recursion
- old_dict = {
- "foo": "bar",
- "bar": {"baz": {"qux": "quux"}},
- "baz": ["qux", {"foo": "bar"}],
- }
- new_dict = salt.utils.data.filter_falsey(old_dict)
- self.assertEqual(old_dict, new_dict)
- # Check returned type equality
- self.assertIs(type(old_dict), type(new_dict))
- # Test dictionary with recursion
- new_dict = salt.utils.data.filter_falsey(old_dict, recurse_depth=3)
- self.assertEqual(old_dict, new_dict)
- # Test with list
- old_list = ["foo", "bar"]
- new_list = salt.utils.data.filter_falsey(old_list)
- self.assertEqual(old_list, new_list)
- # Check returned type equality
- self.assertIs(type(old_list), type(new_list))
- # Test with set
- old_set = set(["foo", "bar"])
- new_set = salt.utils.data.filter_falsey(old_set)
- self.assertEqual(old_set, new_set)
- # Check returned type equality
- self.assertIs(type(old_set), type(new_set))
- # Test with OrderedDict
- old_dict = OrderedDict(
- [
- ("foo", "bar"),
- ("bar", OrderedDict([("qux", "quux")])),
- ("baz", ["qux", OrderedDict([("foo", "bar")])]),
- ]
- )
- new_dict = salt.utils.data.filter_falsey(old_dict)
- self.assertEqual(old_dict, new_dict)
- self.assertIs(type(old_dict), type(new_dict))
- # Test excluding int
- old_list = [0]
- new_list = salt.utils.data.filter_falsey(old_list, ignore_types=[type(0)])
- self.assertEqual(old_list, new_list)
- # Test excluding str (or unicode) (or both)
- old_list = [""]
- new_list = salt.utils.data.filter_falsey(old_list, ignore_types=[type("")])
- self.assertEqual(old_list, new_list)
- # Test excluding list
- old_list = [[]]
- new_list = salt.utils.data.filter_falsey(old_list, ignore_types=[type([])])
- self.assertEqual(old_list, new_list)
- # Test excluding dict
- old_list = [{}]
- new_list = salt.utils.data.filter_falsey(old_list, ignore_types=[type({})])
- self.assertEqual(old_list, new_list)
- def test_filter_dict_no_recurse(self):
- """
- Test filtering a dictionary without recursing.
- This will only filter out key-values where the values are falsey.
- """
- old_dict = {
- "foo": None,
- "bar": {"baz": {"qux": None, "quux": "", "foo": []}},
- "baz": ["qux"],
- "qux": {},
- "quux": [],
- }
- new_dict = salt.utils.data.filter_falsey(old_dict)
- expect_dict = {
- "bar": {"baz": {"qux": None, "quux": "", "foo": []}},
- "baz": ["qux"],
- }
- self.assertEqual(expect_dict, new_dict)
- self.assertIs(type(expect_dict), type(new_dict))
- def test_filter_dict_recurse(self):
- """
- Test filtering a dictionary with recursing.
- This will filter out any key-values where the values are falsey or when
- the values *become* falsey after filtering their contents (in case they
- are lists or dicts).
- """
- old_dict = {
- "foo": None,
- "bar": {"baz": {"qux": None, "quux": "", "foo": []}},
- "baz": ["qux"],
- "qux": {},
- "quux": [],
- }
- new_dict = salt.utils.data.filter_falsey(old_dict, recurse_depth=3)
- expect_dict = {"baz": ["qux"]}
- self.assertEqual(expect_dict, new_dict)
- self.assertIs(type(expect_dict), type(new_dict))
- def test_filter_list_no_recurse(self):
- """
- Test filtering a list without recursing.
- This will only filter out items which are falsey.
- """
- old_list = ["foo", None, [], {}, 0, ""]
- new_list = salt.utils.data.filter_falsey(old_list)
- expect_list = ["foo"]
- self.assertEqual(expect_list, new_list)
- self.assertIs(type(expect_list), type(new_list))
- # Ensure nested values are *not* filtered out.
- old_list = [
- "foo",
- ["foo"],
- ["foo", None],
- {"foo": 0},
- {"foo": "bar", "baz": []},
- [{"foo": ""}],
- ]
- new_list = salt.utils.data.filter_falsey(old_list)
- self.assertEqual(old_list, new_list)
- self.assertIs(type(old_list), type(new_list))
- def test_filter_list_recurse(self):
- """
- Test filtering a list with recursing.
- This will filter out any items which are falsey, or which become falsey
- after filtering their contents (in case they are lists or dicts).
- """
- old_list = [
- "foo",
- ["foo"],
- ["foo", None],
- {"foo": 0},
- {"foo": "bar", "baz": []},
- [{"foo": ""}],
- ]
- new_list = salt.utils.data.filter_falsey(old_list, recurse_depth=3)
- expect_list = ["foo", ["foo"], ["foo"], {"foo": "bar"}]
- self.assertEqual(expect_list, new_list)
- self.assertIs(type(expect_list), type(new_list))
- def test_filter_set_no_recurse(self):
- """
- Test filtering a set without recursing.
- Note that a set cannot contain unhashable types, so recursion is not possible.
- """
- old_set = set(["foo", None, 0, ""])
- new_set = salt.utils.data.filter_falsey(old_set)
- expect_set = set(["foo"])
- self.assertEqual(expect_set, new_set)
- self.assertIs(type(expect_set), type(new_set))
- def test_filter_ordereddict_no_recurse(self):
- """
- Test filtering an OrderedDict without recursing.
- """
- old_dict = OrderedDict(
- [
- ("foo", None),
- (
- "bar",
- OrderedDict(
- [
- (
- "baz",
- OrderedDict([("qux", None), ("quux", ""), ("foo", [])]),
- )
- ]
- ),
- ),
- ("baz", ["qux"]),
- ("qux", {}),
- ("quux", []),
- ]
- )
- new_dict = salt.utils.data.filter_falsey(old_dict)
- expect_dict = OrderedDict(
- [
- (
- "bar",
- OrderedDict(
- [
- (
- "baz",
- OrderedDict([("qux", None), ("quux", ""), ("foo", [])]),
- )
- ]
- ),
- ),
- ("baz", ["qux"]),
- ]
- )
- self.assertEqual(expect_dict, new_dict)
- self.assertIs(type(expect_dict), type(new_dict))
- def test_filter_ordereddict_recurse(self):
- """
- Test filtering an OrderedDict with recursing.
- """
- old_dict = OrderedDict(
- [
- ("foo", None),
- (
- "bar",
- OrderedDict(
- [
- (
- "baz",
- OrderedDict([("qux", None), ("quux", ""), ("foo", [])]),
- )
- ]
- ),
- ),
- ("baz", ["qux"]),
- ("qux", {}),
- ("quux", []),
- ]
- )
- new_dict = salt.utils.data.filter_falsey(old_dict, recurse_depth=3)
- expect_dict = OrderedDict([("baz", ["qux"])])
- self.assertEqual(expect_dict, new_dict)
- self.assertIs(type(expect_dict), type(new_dict))
- def test_filter_list_recurse_limit(self):
- """
- Test filtering a list with recursing, but with a limited depth.
- Note that the top-level is always processed, so a recursion depth of 2
- means that two *additional* levels are processed.
- """
- old_list = [None, [None, [None, [None]]]]
- new_list = salt.utils.data.filter_falsey(old_list, recurse_depth=2)
- self.assertEqual([[[[None]]]], new_list)
- def test_filter_dict_recurse_limit(self):
- """
- Test filtering a dict with recursing, but with a limited depth.
- Note that the top-level is always processed, so a recursion depth of 2
- means that two *additional* levels are processed.
- """
- old_dict = {
- "one": None,
- "foo": {"two": None, "bar": {"three": None, "baz": {"four": None}}},
- }
- new_dict = salt.utils.data.filter_falsey(old_dict, recurse_depth=2)
- self.assertEqual({"foo": {"bar": {"baz": {"four": None}}}}, new_dict)
- def test_filter_exclude_types(self):
- """
- Test filtering a list recursively, but also ignoring (i.e. not filtering)
- out certain types that can be falsey.
- """
- # Ignore int, unicode
- old_list = [
- "foo",
- ["foo"],
- ["foo", None],
- {"foo": 0},
- {"foo": "bar", "baz": []},
- [{"foo": ""}],
- ]
- new_list = salt.utils.data.filter_falsey(
- old_list, recurse_depth=3, ignore_types=[type(0), type("")]
- )
- self.assertEqual(
- ["foo", ["foo"], ["foo"], {"foo": 0}, {"foo": "bar"}, [{"foo": ""}]],
- new_list,
- )
- # Ignore list
- old_list = [
- "foo",
- ["foo"],
- ["foo", None],
- {"foo": 0},
- {"foo": "bar", "baz": []},
- [{"foo": ""}],
- ]
- new_list = salt.utils.data.filter_falsey(
- old_list, recurse_depth=3, ignore_types=[type([])]
- )
- self.assertEqual(
- ["foo", ["foo"], ["foo"], {"foo": "bar", "baz": []}, []], new_list
- )
- # Ignore dict
- old_list = [
- "foo",
- ["foo"],
- ["foo", None],
- {"foo": 0},
- {"foo": "bar", "baz": []},
- [{"foo": ""}],
- ]
- new_list = salt.utils.data.filter_falsey(
- old_list, recurse_depth=3, ignore_types=[type({})]
- )
- self.assertEqual(["foo", ["foo"], ["foo"], {}, {"foo": "bar"}, [{}]], new_list)
- # Ignore NoneType
- old_list = [
- "foo",
- ["foo"],
- ["foo", None],
- {"foo": 0},
- {"foo": "bar", "baz": []},
- [{"foo": ""}],
- ]
- new_list = salt.utils.data.filter_falsey(
- old_list, recurse_depth=3, ignore_types=[type(None)]
- )
- self.assertEqual(["foo", ["foo"], ["foo", None], {"foo": "bar"}], new_list)
- class FilterRecursiveDiff(TestCase):
- """
- Test suite for salt.utils.data.recursive_diff
- """
- def test_list_equality(self):
- """
- Test cases where equal lists are compared.
- """
- test_list = [0, 1, 2]
- self.assertEqual({}, salt.utils.data.recursive_diff(test_list, test_list))
- test_list = [[0], [1], [0, 1, 2]]
- self.assertEqual({}, salt.utils.data.recursive_diff(test_list, test_list))
- def test_dict_equality(self):
- """
- Test cases where equal dicts are compared.
- """
- test_dict = {"foo": "bar", "bar": {"baz": {"qux": "quux"}}, "frop": 0}
- self.assertEqual({}, salt.utils.data.recursive_diff(test_dict, test_dict))
- def test_ordereddict_equality(self):
- """
- Test cases where equal OrderedDicts are compared.
- """
- test_dict = OrderedDict(
- [
- ("foo", "bar"),
- ("bar", OrderedDict([("baz", OrderedDict([("qux", "quux")]))])),
- ("frop", 0),
- ]
- )
- self.assertEqual({}, salt.utils.data.recursive_diff(test_dict, test_dict))
- def test_mixed_equality(self):
- """
- Test cases where mixed nested lists and dicts are compared.
- """
- test_data = {
- "foo": "bar",
- "baz": [0, 1, 2],
- "bar": {"baz": [{"qux": "quux"}, {"froop", 0}]},
- }
- self.assertEqual({}, salt.utils.data.recursive_diff(test_data, test_data))
- def test_set_equality(self):
- """
- Test cases where equal sets are compared.
- """
- test_set = set([0, 1, 2, 3, "foo"])
- self.assertEqual({}, salt.utils.data.recursive_diff(test_set, test_set))
- # This is a bit of an oddity, as python seems to sort the sets in memory
- # so both sets end up with the same ordering (0..3).
- set_one = set([0, 1, 2, 3])
- set_two = set([3, 2, 1, 0])
- self.assertEqual({}, salt.utils.data.recursive_diff(set_one, set_two))
- def test_tuple_equality(self):
- """
- Test cases where equal tuples are compared.
- """
- test_tuple = (0, 1, 2, 3, "foo")
- self.assertEqual({}, salt.utils.data.recursive_diff(test_tuple, test_tuple))
- def test_list_inequality(self):
- """
- Test cases where two inequal lists are compared.
- """
- list_one = [0, 1, 2]
- list_two = ["foo", "bar", "baz"]
- expected_result = {"old": list_one, "new": list_two}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(list_one, list_two)
- )
- expected_result = {"new": list_one, "old": list_two}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(list_two, list_one)
- )
- list_one = [0, "foo", 1, "bar"]
- list_two = [1, "foo", 1, "qux"]
- expected_result = {"old": [0, "bar"], "new": [1, "qux"]}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(list_one, list_two)
- )
- expected_result = {"new": [0, "bar"], "old": [1, "qux"]}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(list_two, list_one)
- )
- list_one = [0, 1, [2, 3]]
- list_two = [0, 1, ["foo", "bar"]]
- expected_result = {"old": [[2, 3]], "new": [["foo", "bar"]]}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(list_one, list_two)
- )
- expected_result = {"new": [[2, 3]], "old": [["foo", "bar"]]}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(list_two, list_one)
- )
- def test_dict_inequality(self):
- """
- Test cases where two inequal dicts are compared.
- """
- dict_one = {"foo": 1, "bar": 2, "baz": 3}
- dict_two = {"foo": 2, 1: "bar", "baz": 3}
- expected_result = {"old": {"foo": 1, "bar": 2}, "new": {"foo": 2, 1: "bar"}}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(dict_one, dict_two)
- )
- expected_result = {"new": {"foo": 1, "bar": 2}, "old": {"foo": 2, 1: "bar"}}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(dict_two, dict_one)
- )
- dict_one = {"foo": {"bar": {"baz": 1}}}
- dict_two = {"foo": {"qux": {"baz": 1}}}
- expected_result = {"old": dict_one, "new": dict_two}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(dict_one, dict_two)
- )
- expected_result = {"new": dict_one, "old": dict_two}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(dict_two, dict_one)
- )
- def test_ordereddict_inequality(self):
- """
- Test cases where two inequal OrderedDicts are compared.
- """
- odict_one = OrderedDict([("foo", "bar"), ("bar", "baz")])
- odict_two = OrderedDict([("bar", "baz"), ("foo", "bar")])
- expected_result = {"old": odict_one, "new": odict_two}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(odict_one, odict_two)
- )
- def test_set_inequality(self):
- """
- Test cases where two inequal sets are compared.
- Tricky as the sets are compared zipped, so shuffled sets of equal values
- are considered different.
- """
- set_one = set([0, 1, 2, 4])
- set_two = set([0, 1, 3, 4])
- expected_result = {"old": set([2]), "new": set([3])}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(set_one, set_two)
- )
- expected_result = {"new": set([2]), "old": set([3])}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(set_two, set_one)
- )
- # It is unknown how different python versions will store sets in memory.
- # Python 2.7 seems to sort it (i.e. set_one below becomes {0, 1, 'foo', 'bar'}
- # However Python 3.6.8 stores it differently each run.
- # So just test for "not equal" here.
- set_one = set([0, "foo", 1, "bar"])
- set_two = set(["foo", 1, "bar", 2])
- expected_result = {}
- self.assertNotEqual(
- expected_result, salt.utils.data.recursive_diff(set_one, set_two)
- )
- def test_mixed_inequality(self):
- """
- Test cases where two mixed dicts/iterables that are different are compared.
- """
- dict_one = {"foo": [1, 2, 3]}
- dict_two = {"foo": [3, 2, 1]}
- expected_result = {"old": {"foo": [1, 3]}, "new": {"foo": [3, 1]}}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(dict_one, dict_two)
- )
- expected_result = {"new": {"foo": [1, 3]}, "old": {"foo": [3, 1]}}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(dict_two, dict_one)
- )
- list_one = [1, 2, {"foo": ["bar", {"foo": 1, "bar": 2}]}]
- list_two = [3, 4, {"foo": ["qux", {"foo": 1, "bar": 2}]}]
- expected_result = {
- "old": [1, 2, {"foo": ["bar"]}],
- "new": [3, 4, {"foo": ["qux"]}],
- }
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(list_one, list_two)
- )
- expected_result = {
- "new": [1, 2, {"foo": ["bar"]}],
- "old": [3, 4, {"foo": ["qux"]}],
- }
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(list_two, list_one)
- )
- mixed_one = {"foo": set([0, 1, 2]), "bar": [0, 1, 2]}
- mixed_two = {"foo": set([1, 2, 3]), "bar": [1, 2, 3]}
- expected_result = {
- "old": {"foo": set([0]), "bar": [0, 1, 2]},
- "new": {"foo": set([3]), "bar": [1, 2, 3]},
- }
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(mixed_one, mixed_two)
- )
- expected_result = {
- "new": {"foo": set([0]), "bar": [0, 1, 2]},
- "old": {"foo": set([3]), "bar": [1, 2, 3]},
- }
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(mixed_two, mixed_one)
- )
- def test_tuple_inequality(self):
- """
- Test cases where two tuples that are different are compared.
- """
- tuple_one = (1, 2, 3)
- tuple_two = (3, 2, 1)
- expected_result = {"old": (1, 3), "new": (3, 1)}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(tuple_one, tuple_two)
- )
- def test_list_vs_set(self):
- """
- Test case comparing a list with a set, will be compared unordered.
- """
- mixed_one = [1, 2, 3]
- mixed_two = set([3, 2, 1])
- expected_result = {}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(mixed_one, mixed_two)
- )
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(mixed_two, mixed_one)
- )
- def test_dict_vs_ordereddict(self):
- """
- Test case comparing a dict with an ordereddict, will be compared unordered.
- """
- test_dict = {"foo": "bar", "bar": "baz"}
- test_odict = OrderedDict([("foo", "bar"), ("bar", "baz")])
- self.assertEqual({}, salt.utils.data.recursive_diff(test_dict, test_odict))
- self.assertEqual({}, salt.utils.data.recursive_diff(test_odict, test_dict))
- test_odict2 = OrderedDict([("bar", "baz"), ("foo", "bar")])
- self.assertEqual({}, salt.utils.data.recursive_diff(test_dict, test_odict2))
- self.assertEqual({}, salt.utils.data.recursive_diff(test_odict2, test_dict))
- def test_list_ignore_ignored(self):
- """
- Test case comparing two lists with ignore-list supplied (which is not used
- when comparing lists).
- """
- list_one = [1, 2, 3]
- list_two = [3, 2, 1]
- expected_result = {"old": [1, 3], "new": [3, 1]}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(list_one, list_two, ignore_keys=[1, 3]),
- )
- def test_dict_ignore(self):
- """
- Test case comparing two dicts with ignore-list supplied.
- """
- dict_one = {"foo": 1, "bar": 2, "baz": 3}
- dict_two = {"foo": 3, "bar": 2, "baz": 1}
- expected_result = {"old": {"baz": 3}, "new": {"baz": 1}}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(dict_one, dict_two, ignore_keys=["foo"]),
- )
- def test_ordereddict_ignore(self):
- """
- Test case comparing two OrderedDicts with ignore-list supplied.
- """
- odict_one = OrderedDict([("foo", 1), ("bar", 2), ("baz", 3)])
- odict_two = OrderedDict([("baz", 1), ("bar", 2), ("foo", 3)])
- # The key 'foo' will be ignored, which means the key from the other OrderedDict
- # will always be considered "different" since OrderedDicts are compared ordered.
- expected_result = {
- "old": OrderedDict([("baz", 3)]),
- "new": OrderedDict([("baz", 1)]),
- }
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(odict_one, odict_two, ignore_keys=["foo"]),
- )
- def test_dict_vs_ordereddict_ignore(self):
- """
- Test case comparing a dict with an OrderedDict with ignore-list supplied.
- """
- dict_one = {"foo": 1, "bar": 2, "baz": 3}
- odict_two = OrderedDict([("foo", 3), ("bar", 2), ("baz", 1)])
- expected_result = {"old": {"baz": 3}, "new": OrderedDict([("baz", 1)])}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(dict_one, odict_two, ignore_keys=["foo"]),
- )
- def test_mixed_nested_ignore(self):
- """
- Test case comparing mixed, nested items with ignore-list supplied.
- """
- dict_one = {"foo": [1], "bar": {"foo": 1, "bar": 2}, "baz": 3}
- dict_two = {"foo": [2], "bar": {"foo": 3, "bar": 2}, "baz": 1}
- expected_result = {"old": {"baz": 3}, "new": {"baz": 1}}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(dict_one, dict_two, ignore_keys=["foo"]),
- )
- def test_ordered_dict_unequal_length(self):
- """
- Test case comparing two OrderedDicts of unequal length.
- """
- odict_one = OrderedDict([("foo", 1), ("bar", 2), ("baz", 3)])
- odict_two = OrderedDict([("foo", 1), ("bar", 2)])
- expected_result = {"old": OrderedDict([("baz", 3)]), "new": {}}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(odict_one, odict_two)
- )
- def test_list_unequal_length(self):
- """
- Test case comparing two lists of unequal length.
- """
- list_one = [1, 2, 3]
- list_two = [1, 2, 3, 4]
- expected_result = {"old": [], "new": [4]}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(list_one, list_two)
- )
- def test_set_unequal_length(self):
- """
- Test case comparing two sets of unequal length.
- This does not do anything special, as it is unordered.
- """
- set_one = set([1, 2, 3])
- set_two = set([4, 3, 2, 1])
- expected_result = {"old": set([]), "new": set([4])}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(set_one, set_two)
- )
- def test_tuple_unequal_length(self):
- """
- Test case comparing two tuples of unequal length.
- This should be the same as comparing two ordered lists.
- """
- tuple_one = (1, 2, 3)
- tuple_two = (1, 2, 3, 4)
- expected_result = {"old": (), "new": (4,)}
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(tuple_one, tuple_two)
- )
- def test_list_unordered(self):
- """
- Test case comparing two lists unordered.
- """
- list_one = [1, 2, 3, 4]
- list_two = [4, 3, 2]
- expected_result = {"old": [1], "new": []}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(list_one, list_two, ignore_order=True),
- )
- def test_mixed_nested_unordered(self):
- """
- Test case comparing nested dicts/lists unordered.
- """
- dict_one = {"foo": {"bar": [1, 2, 3]}, "bar": [{"foo": 4}, 0]}
- dict_two = {"foo": {"bar": [3, 2, 1]}, "bar": [0, {"foo": 4}]}
- expected_result = {}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(dict_one, dict_two, ignore_order=True),
- )
- expected_result = {
- "old": {"foo": {"bar": [1, 3]}, "bar": [{"foo": 4}, 0]},
- "new": {"foo": {"bar": [3, 1]}, "bar": [0, {"foo": 4}]},
- }
- self.assertEqual(
- expected_result, salt.utils.data.recursive_diff(dict_one, dict_two)
- )
- def test_ordered_dict_unordered(self):
- """
- Test case comparing OrderedDicts unordered.
- """
- odict_one = OrderedDict([("foo", 1), ("bar", 2), ("baz", 3)])
- odict_two = OrderedDict([("baz", 3), ("bar", 2), ("foo", 1)])
- expected_result = {}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(odict_one, odict_two, ignore_order=True),
- )
- def test_ignore_missing_keys_dict(self):
- """
- Test case ignoring missing keys on a comparison of dicts.
- """
- dict_one = {"foo": 1, "bar": 2, "baz": 3}
- dict_two = {"bar": 3}
- expected_result = {"old": {"bar": 2}, "new": {"bar": 3}}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(
- dict_one, dict_two, ignore_missing_keys=True
- ),
- )
- def test_ignore_missing_keys_ordered_dict(self):
- """
- Test case not ignoring missing keys on a comparison of OrderedDicts.
- """
- odict_one = OrderedDict([("foo", 1), ("bar", 2), ("baz", 3)])
- odict_two = OrderedDict([("bar", 3)])
- expected_result = {"old": odict_one, "new": odict_two}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(
- odict_one, odict_two, ignore_missing_keys=True
- ),
- )
- def test_ignore_missing_keys_recursive(self):
- """
- Test case ignoring missing keys on a comparison of nested dicts.
- """
- dict_one = {"foo": {"bar": 2, "baz": 3}}
- dict_two = {"foo": {"baz": 3}}
- expected_result = {}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(
- dict_one, dict_two, ignore_missing_keys=True
- ),
- )
- # Compare from dict-in-dict
- dict_two = {}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(
- dict_one, dict_two, ignore_missing_keys=True
- ),
- )
- # Compare from dict-in-list
- dict_one = {"foo": ["bar", {"baz": 3}]}
- dict_two = {"foo": ["bar", {}]}
- self.assertEqual(
- expected_result,
- salt.utils.data.recursive_diff(
- dict_one, dict_two, ignore_missing_keys=True
- ),
- )
|