test_data.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Tests for salt.utils.data
  4. '''
  5. # Import Python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import logging
  8. # Import Salt libs
  9. import salt.utils.data
  10. import salt.utils.stringutils
  11. from salt.utils.odict import OrderedDict
  12. from tests.support.unit import TestCase, LOREM_IPSUM
  13. from tests.support.mock import patch
  14. from salt.ext.six.moves import builtins # pylint: disable=import-error,redefined-builtin
  15. from salt.ext import six
  16. log = logging.getLogger(__name__)
  17. _b = lambda x: x.encode('utf-8')
  18. _s = lambda x: salt.utils.stringutils.to_str(x, normalize=True)
  19. # Some randomized data that will not decode
  20. BYTES = b'1\x814\x10'
  21. # This is an example of a unicode string with й constructed using two separate
  22. # code points. Do not modify it.
  23. EGGS = '\u044f\u0438\u0306\u0446\u0430'
  24. class DataTestCase(TestCase):
  25. test_data = [
  26. 'unicode_str',
  27. _b('питон'),
  28. 123,
  29. 456.789,
  30. True,
  31. False,
  32. None,
  33. EGGS,
  34. BYTES,
  35. [123, 456.789, _b('спам'), True, False, None, EGGS, BYTES],
  36. (987, 654.321, _b('яйца'), EGGS, None, (True, EGGS, BYTES)),
  37. {_b('str_key'): _b('str_val'),
  38. None: True,
  39. 123: 456.789,
  40. EGGS: BYTES,
  41. _b('subdict'): {'unicode_key': EGGS,
  42. _b('tuple'): (123, 'hello', _b('world'), True, EGGS, BYTES),
  43. _b('list'): [456, _b('спам'), False, EGGS, BYTES]}},
  44. OrderedDict([(_b('foo'), 'bar'), (123, 456), (EGGS, BYTES)])
  45. ]
  46. def test_sorted_ignorecase(self):
  47. test_list = ['foo', 'Foo', 'bar', 'Bar']
  48. expected_list = ['bar', 'Bar', 'foo', 'Foo']
  49. self.assertEqual(
  50. salt.utils.data.sorted_ignorecase(test_list), expected_list)
  51. def test_mysql_to_dict(self):
  52. test_mysql_output = ['+----+------+-----------+------+---------+------+-------+------------------+',
  53. '| Id | User | Host | db | Command | Time | State | Info |',
  54. '+----+------+-----------+------+---------+------+-------+------------------+',
  55. '| 7 | root | localhost | NULL | Query | 0 | init | show processlist |',
  56. '+----+------+-----------+------+---------+------+-------+------------------+']
  57. ret = salt.utils.data.mysql_to_dict(test_mysql_output, 'Info')
  58. expected_dict = {
  59. 'show processlist': {'Info': 'show processlist', 'db': 'NULL', 'State': 'init', 'Host': 'localhost',
  60. 'Command': 'Query', 'User': 'root', 'Time': 0, 'Id': 7}}
  61. self.assertDictEqual(ret, expected_dict)
  62. def test_subdict_match(self):
  63. test_two_level_dict = {'foo': {'bar': 'baz'}}
  64. test_two_level_comb_dict = {'foo': {'bar': 'baz:woz'}}
  65. test_two_level_dict_and_list = {
  66. 'abc': ['def', 'ghi', {'lorem': {'ipsum': [{'dolor': 'sit'}]}}],
  67. }
  68. test_three_level_dict = {'a': {'b': {'c': 'v'}}}
  69. self.assertTrue(
  70. salt.utils.data.subdict_match(
  71. test_two_level_dict, 'foo:bar:baz'
  72. )
  73. )
  74. # In test_two_level_comb_dict, 'foo:bar' corresponds to 'baz:woz', not
  75. # 'baz'. This match should return False.
  76. self.assertFalse(
  77. salt.utils.data.subdict_match(
  78. test_two_level_comb_dict, 'foo:bar:baz'
  79. )
  80. )
  81. # This tests matching with the delimiter in the value part (in other
  82. # words, that the path 'foo:bar' corresponds to the string 'baz:woz').
  83. self.assertTrue(
  84. salt.utils.data.subdict_match(
  85. test_two_level_comb_dict, 'foo:bar:baz:woz'
  86. )
  87. )
  88. # This would match if test_two_level_comb_dict['foo']['bar'] was equal
  89. # to 'baz:woz:wiz', or if there was more deep nesting. But it does not,
  90. # so this should return False.
  91. self.assertFalse(
  92. salt.utils.data.subdict_match(
  93. test_two_level_comb_dict, 'foo:bar:baz:woz:wiz'
  94. )
  95. )
  96. # This tests for cases when a key path corresponds to a list. The
  97. # value part 'ghi' should be successfully matched as it is a member of
  98. # the list corresponding to key path 'abc'. It is somewhat a
  99. # duplication of a test within test_traverse_dict_and_list, but
  100. # salt.utils.data.subdict_match() does more than just invoke
  101. # salt.utils.traverse_list_and_dict() so this particular assertion is a
  102. # sanity check.
  103. self.assertTrue(
  104. salt.utils.data.subdict_match(
  105. test_two_level_dict_and_list, 'abc:ghi'
  106. )
  107. )
  108. # This tests the use case of a dict embedded in a list, embedded in a
  109. # list, embedded in a dict. This is a rather absurd case, but it
  110. # confirms that match recursion works properly.
  111. self.assertTrue(
  112. salt.utils.data.subdict_match(
  113. test_two_level_dict_and_list, 'abc:lorem:ipsum:dolor:sit'
  114. )
  115. )
  116. # Test four level dict match for reference
  117. self.assertTrue(
  118. salt.utils.data.subdict_match(
  119. test_three_level_dict, 'a:b:c:v'
  120. )
  121. )
  122. self.assertFalse(
  123. # Test regression in 2015.8 where 'a:c:v' would match 'a:b:c:v'
  124. salt.utils.data.subdict_match(
  125. test_three_level_dict, 'a:c:v'
  126. )
  127. )
  128. # Test wildcard match
  129. self.assertTrue(
  130. salt.utils.data.subdict_match(
  131. test_three_level_dict, 'a:*:c:v'
  132. )
  133. )
  134. def test_subdict_match_with_wildcards(self):
  135. '''
  136. Tests subdict matching when wildcards are used in the expression
  137. '''
  138. data = {
  139. 'a': {
  140. 'b': {
  141. 'ç': 'd',
  142. 'é': ['eff', 'gee', '8ch'],
  143. 'ĩ': {'j': 'k'}
  144. }
  145. }
  146. }
  147. assert salt.utils.data.subdict_match(data, '*:*:*:*')
  148. assert salt.utils.data.subdict_match(data, 'a:*:*:*')
  149. assert salt.utils.data.subdict_match(data, 'a:b:*:*')
  150. assert salt.utils.data.subdict_match(data, 'a:b:ç:*')
  151. assert salt.utils.data.subdict_match(data, 'a:b:*:d')
  152. assert salt.utils.data.subdict_match(data, 'a:*:ç:d')
  153. assert salt.utils.data.subdict_match(data, '*:b:ç:d')
  154. assert salt.utils.data.subdict_match(data, '*:*:ç:d')
  155. assert salt.utils.data.subdict_match(data, '*:*:*:d')
  156. assert salt.utils.data.subdict_match(data, 'a:*:*:d')
  157. assert salt.utils.data.subdict_match(data, 'a:b:*:ef*')
  158. assert salt.utils.data.subdict_match(data, 'a:b:*:g*')
  159. assert salt.utils.data.subdict_match(data, 'a:b:*:j:*')
  160. assert salt.utils.data.subdict_match(data, 'a:b:*:j:k')
  161. assert salt.utils.data.subdict_match(data, 'a:b:*:*:k')
  162. assert salt.utils.data.subdict_match(data, 'a:b:*:*:*')
  163. def test_traverse_dict(self):
  164. test_two_level_dict = {'foo': {'bar': 'baz'}}
  165. self.assertDictEqual(
  166. {'not_found': 'nope'},
  167. salt.utils.data.traverse_dict(
  168. test_two_level_dict, 'foo:bar:baz', {'not_found': 'nope'}
  169. )
  170. )
  171. self.assertEqual(
  172. 'baz',
  173. salt.utils.data.traverse_dict(
  174. test_two_level_dict, 'foo:bar', {'not_found': 'not_found'}
  175. )
  176. )
  177. def test_traverse_dict_and_list(self):
  178. test_two_level_dict = {'foo': {'bar': 'baz'}}
  179. test_two_level_dict_and_list = {
  180. 'foo': ['bar', 'baz', {'lorem': {'ipsum': [{'dolor': 'sit'}]}}]
  181. }
  182. # Check traversing too far: salt.utils.data.traverse_dict_and_list() returns
  183. # the value corresponding to a given key path, and baz is a value
  184. # corresponding to the key path foo:bar.
  185. self.assertDictEqual(
  186. {'not_found': 'nope'},
  187. salt.utils.data.traverse_dict_and_list(
  188. test_two_level_dict, 'foo:bar:baz', {'not_found': 'nope'}
  189. )
  190. )
  191. # Now check to ensure that foo:bar corresponds to baz
  192. self.assertEqual(
  193. 'baz',
  194. salt.utils.data.traverse_dict_and_list(
  195. test_two_level_dict, 'foo:bar', {'not_found': 'not_found'}
  196. )
  197. )
  198. # Check traversing too far
  199. self.assertDictEqual(
  200. {'not_found': 'nope'},
  201. salt.utils.data.traverse_dict_and_list(
  202. test_two_level_dict_and_list, 'foo:bar', {'not_found': 'nope'}
  203. )
  204. )
  205. # Check index 1 (2nd element) of list corresponding to path 'foo'
  206. self.assertEqual(
  207. 'baz',
  208. salt.utils.data.traverse_dict_and_list(
  209. test_two_level_dict_and_list, 'foo:1', {'not_found': 'not_found'}
  210. )
  211. )
  212. # Traverse a couple times into dicts embedded in lists
  213. self.assertEqual(
  214. 'sit',
  215. salt.utils.data.traverse_dict_and_list(
  216. test_two_level_dict_and_list,
  217. 'foo:lorem:ipsum:dolor',
  218. {'not_found': 'not_found'}
  219. )
  220. )
  221. def test_compare_dicts(self):
  222. ret = salt.utils.data.compare_dicts(old={'foo': 'bar'}, new={'foo': 'bar'})
  223. self.assertEqual(ret, {})
  224. ret = salt.utils.data.compare_dicts(old={'foo': 'bar'}, new={'foo': 'woz'})
  225. expected_ret = {'foo': {'new': 'woz', 'old': 'bar'}}
  226. self.assertDictEqual(ret, expected_ret)
  227. def test_decode(self):
  228. '''
  229. Companion to test_decode_to_str, they should both be kept up-to-date
  230. with one another.
  231. NOTE: This uses the lambda "_b" defined above in the global scope,
  232. which encodes a string to a bytestring, assuming utf-8.
  233. '''
  234. expected = [
  235. 'unicode_str',
  236. 'питон',
  237. 123,
  238. 456.789,
  239. True,
  240. False,
  241. None,
  242. 'яйца',
  243. BYTES,
  244. [123, 456.789, 'спам', True, False, None, 'яйца', BYTES],
  245. (987, 654.321, 'яйца', 'яйца', None, (True, 'яйца', BYTES)),
  246. {'str_key': 'str_val',
  247. None: True,
  248. 123: 456.789,
  249. 'яйца': BYTES,
  250. 'subdict': {'unicode_key': 'яйца',
  251. 'tuple': (123, 'hello', 'world', True, 'яйца', BYTES),
  252. 'list': [456, 'спам', False, 'яйца', BYTES]}},
  253. OrderedDict([('foo', 'bar'), (123, 456), ('яйца', BYTES)])
  254. ]
  255. ret = salt.utils.data.decode(
  256. self.test_data,
  257. keep=True,
  258. normalize=True,
  259. preserve_dict_class=True,
  260. preserve_tuples=True)
  261. self.assertEqual(ret, expected)
  262. # The binary data in the data structure should fail to decode, even
  263. # using the fallback, and raise an exception.
  264. self.assertRaises(
  265. UnicodeDecodeError,
  266. salt.utils.data.decode,
  267. self.test_data,
  268. keep=False,
  269. normalize=True,
  270. preserve_dict_class=True,
  271. preserve_tuples=True)
  272. # Now munge the expected data so that we get what we would expect if we
  273. # disable preservation of dict class and tuples
  274. expected[10] = [987, 654.321, 'яйца', 'яйца', None, [True, 'яйца', BYTES]]
  275. expected[11]['subdict']['tuple'] = [123, 'hello', 'world', True, 'яйца', BYTES]
  276. expected[12] = {'foo': 'bar', 123: 456, 'яйца': BYTES}
  277. ret = salt.utils.data.decode(
  278. self.test_data,
  279. keep=True,
  280. normalize=True,
  281. preserve_dict_class=False,
  282. preserve_tuples=False)
  283. self.assertEqual(ret, expected)
  284. # Now test single non-string, non-data-structure items, these should
  285. # return the same value when passed to this function
  286. for item in (123, 4.56, True, False, None):
  287. log.debug('Testing decode of %s', item)
  288. self.assertEqual(salt.utils.data.decode(item), item)
  289. # Test single strings (not in a data structure)
  290. self.assertEqual(salt.utils.data.decode('foo'), 'foo')
  291. self.assertEqual(salt.utils.data.decode(_b('bar')), 'bar')
  292. self.assertEqual(salt.utils.data.decode(EGGS, normalize=True), 'яйца')
  293. self.assertEqual(salt.utils.data.decode(EGGS, normalize=False), EGGS)
  294. # Test binary blob
  295. self.assertEqual(salt.utils.data.decode(BYTES, keep=True), BYTES)
  296. self.assertRaises(
  297. UnicodeDecodeError,
  298. salt.utils.data.decode,
  299. BYTES,
  300. keep=False)
  301. def test_decode_to_str(self):
  302. '''
  303. Companion to test_decode, they should both be kept up-to-date with one
  304. another.
  305. NOTE: This uses the lambda "_s" defined above in the global scope,
  306. which converts the string/bytestring to a str type.
  307. '''
  308. expected = [
  309. _s('unicode_str'),
  310. _s('питон'),
  311. 123,
  312. 456.789,
  313. True,
  314. False,
  315. None,
  316. _s('яйца'),
  317. BYTES,
  318. [123, 456.789, _s('спам'), True, False, None, _s('яйца'), BYTES],
  319. (987, 654.321, _s('яйца'), _s('яйца'), None, (True, _s('яйца'), BYTES)),
  320. {_s('str_key'): _s('str_val'),
  321. None: True,
  322. 123: 456.789,
  323. _s('яйца'): BYTES,
  324. _s('subdict'): {
  325. _s('unicode_key'): _s('яйца'),
  326. _s('tuple'): (123, _s('hello'), _s('world'), True, _s('яйца'), BYTES),
  327. _s('list'): [456, _s('спам'), False, _s('яйца'), BYTES]}},
  328. OrderedDict([(_s('foo'), _s('bar')), (123, 456), (_s('яйца'), BYTES)])
  329. ]
  330. ret = salt.utils.data.decode(
  331. self.test_data,
  332. keep=True,
  333. normalize=True,
  334. preserve_dict_class=True,
  335. preserve_tuples=True,
  336. to_str=True)
  337. self.assertEqual(ret, expected)
  338. if six.PY3:
  339. # The binary data in the data structure should fail to decode, even
  340. # using the fallback, and raise an exception.
  341. self.assertRaises(
  342. UnicodeDecodeError,
  343. salt.utils.data.decode,
  344. self.test_data,
  345. keep=False,
  346. normalize=True,
  347. preserve_dict_class=True,
  348. preserve_tuples=True,
  349. to_str=True)
  350. # Now munge the expected data so that we get what we would expect if we
  351. # disable preservation of dict class and tuples
  352. expected[10] = [987, 654.321, _s('яйца'), _s('яйца'), None, [True, _s('яйца'), BYTES]]
  353. expected[11][_s('subdict')][_s('tuple')] = [123, _s('hello'), _s('world'), True, _s('яйца'), BYTES]
  354. expected[12] = {_s('foo'): _s('bar'), 123: 456, _s('яйца'): BYTES}
  355. ret = salt.utils.data.decode(
  356. self.test_data,
  357. keep=True,
  358. normalize=True,
  359. preserve_dict_class=False,
  360. preserve_tuples=False,
  361. to_str=True)
  362. self.assertEqual(ret, expected)
  363. # Now test single non-string, non-data-structure items, these should
  364. # return the same value when passed to this function
  365. for item in (123, 4.56, True, False, None):
  366. log.debug('Testing decode of %s', item)
  367. self.assertEqual(salt.utils.data.decode(item, to_str=True), item)
  368. # Test single strings (not in a data structure)
  369. self.assertEqual(salt.utils.data.decode('foo', to_str=True), _s('foo'))
  370. self.assertEqual(salt.utils.data.decode(_b('bar'), to_str=True), _s('bar'))
  371. # Test binary blob
  372. self.assertEqual(
  373. salt.utils.data.decode(BYTES, keep=True, to_str=True),
  374. BYTES
  375. )
  376. if six.PY3:
  377. self.assertRaises(
  378. UnicodeDecodeError,
  379. salt.utils.data.decode,
  380. BYTES,
  381. keep=False,
  382. to_str=True)
  383. def test_decode_fallback(self):
  384. '''
  385. Test fallback to utf-8
  386. '''
  387. with patch.object(builtins, '__salt_system_encoding__', 'ascii'):
  388. self.assertEqual(salt.utils.data.decode(_b('яйца')), 'яйца')
  389. def test_encode(self):
  390. '''
  391. NOTE: This uses the lambda "_b" defined above in the global scope,
  392. which encodes a string to a bytestring, assuming utf-8.
  393. '''
  394. expected = [
  395. _b('unicode_str'),
  396. _b('питон'),
  397. 123,
  398. 456.789,
  399. True,
  400. False,
  401. None,
  402. _b(EGGS),
  403. BYTES,
  404. [123, 456.789, _b('спам'), True, False, None, _b(EGGS), BYTES],
  405. (987, 654.321, _b('яйца'), _b(EGGS), None, (True, _b(EGGS), BYTES)),
  406. {_b('str_key'): _b('str_val'),
  407. None: True,
  408. 123: 456.789,
  409. _b(EGGS): BYTES,
  410. _b('subdict'): {_b('unicode_key'): _b(EGGS),
  411. _b('tuple'): (123, _b('hello'), _b('world'), True, _b(EGGS), BYTES),
  412. _b('list'): [456, _b('спам'), False, _b(EGGS), BYTES]}},
  413. OrderedDict([(_b('foo'), _b('bar')), (123, 456), (_b(EGGS), BYTES)])
  414. ]
  415. # Both keep=True and keep=False should work because the BYTES data is
  416. # already bytes.
  417. ret = salt.utils.data.encode(
  418. self.test_data,
  419. keep=True,
  420. preserve_dict_class=True,
  421. preserve_tuples=True)
  422. self.assertEqual(ret, expected)
  423. ret = salt.utils.data.encode(
  424. self.test_data,
  425. keep=False,
  426. preserve_dict_class=True,
  427. preserve_tuples=True)
  428. self.assertEqual(ret, expected)
  429. # Now munge the expected data so that we get what we would expect if we
  430. # disable preservation of dict class and tuples
  431. expected[10] = [987, 654.321, _b('яйца'), _b(EGGS), None, [True, _b(EGGS), BYTES]]
  432. expected[11][_b('subdict')][_b('tuple')] = [
  433. 123, _b('hello'), _b('world'), True, _b(EGGS), BYTES
  434. ]
  435. expected[12] = {_b('foo'): _b('bar'), 123: 456, _b(EGGS): BYTES}
  436. ret = salt.utils.data.encode(
  437. self.test_data,
  438. keep=True,
  439. preserve_dict_class=False,
  440. preserve_tuples=False)
  441. self.assertEqual(ret, expected)
  442. ret = salt.utils.data.encode(
  443. self.test_data,
  444. keep=False,
  445. preserve_dict_class=False,
  446. preserve_tuples=False)
  447. self.assertEqual(ret, expected)
  448. # Now test single non-string, non-data-structure items, these should
  449. # return the same value when passed to this function
  450. for item in (123, 4.56, True, False, None):
  451. log.debug('Testing encode of %s', item)
  452. self.assertEqual(salt.utils.data.encode(item), item)
  453. # Test single strings (not in a data structure)
  454. self.assertEqual(salt.utils.data.encode('foo'), _b('foo'))
  455. self.assertEqual(salt.utils.data.encode(_b('bar')), _b('bar'))
  456. # Test binary blob, nothing should happen even when keep=False since
  457. # the data is already bytes
  458. self.assertEqual(salt.utils.data.encode(BYTES, keep=True), BYTES)
  459. self.assertEqual(salt.utils.data.encode(BYTES, keep=False), BYTES)
  460. def test_encode_keep(self):
  461. '''
  462. Whereas we tested the keep argument in test_decode, it is much easier
  463. to do a more comprehensive test of keep in its own function where we
  464. can force the encoding.
  465. '''
  466. unicode_str = 'питон'
  467. encoding = 'ascii'
  468. # Test single string
  469. self.assertEqual(
  470. salt.utils.data.encode(unicode_str, encoding, keep=True),
  471. unicode_str)
  472. self.assertRaises(
  473. UnicodeEncodeError,
  474. salt.utils.data.encode,
  475. unicode_str,
  476. encoding,
  477. keep=False)
  478. data = [
  479. unicode_str,
  480. [b'foo', [unicode_str], {b'key': unicode_str}, (unicode_str,)],
  481. {b'list': [b'foo', unicode_str],
  482. b'dict': {b'key': unicode_str},
  483. b'tuple': (b'foo', unicode_str)},
  484. ([b'foo', unicode_str], {b'key': unicode_str}, (unicode_str,))
  485. ]
  486. # Since everything was a bytestring aside from the bogus data, the
  487. # return data should be identical. We don't need to test recursive
  488. # decoding, that has already been tested in test_encode.
  489. self.assertEqual(
  490. salt.utils.data.encode(data, encoding,
  491. keep=True, preserve_tuples=True),
  492. data
  493. )
  494. self.assertRaises(
  495. UnicodeEncodeError,
  496. salt.utils.data.encode,
  497. data,
  498. encoding,
  499. keep=False,
  500. preserve_tuples=True)
  501. for index, item in enumerate(data):
  502. self.assertEqual(
  503. salt.utils.data.encode(data[index], encoding,
  504. keep=True, preserve_tuples=True),
  505. data[index]
  506. )
  507. self.assertRaises(
  508. UnicodeEncodeError,
  509. salt.utils.data.encode,
  510. data[index],
  511. encoding,
  512. keep=False,
  513. preserve_tuples=True)
  514. def test_encode_fallback(self):
  515. '''
  516. Test fallback to utf-8
  517. '''
  518. with patch.object(builtins, '__salt_system_encoding__', 'ascii'):
  519. self.assertEqual(salt.utils.data.encode('яйца'), _b('яйца'))
  520. with patch.object(builtins, '__salt_system_encoding__', 'CP1252'):
  521. self.assertEqual(salt.utils.data.encode('Ψ'), _b('Ψ'))
  522. def test_repack_dict(self):
  523. list_of_one_element_dicts = [{'dict_key_1': 'dict_val_1'},
  524. {'dict_key_2': 'dict_val_2'},
  525. {'dict_key_3': 'dict_val_3'}]
  526. expected_ret = {'dict_key_1': 'dict_val_1',
  527. 'dict_key_2': 'dict_val_2',
  528. 'dict_key_3': 'dict_val_3'}
  529. ret = salt.utils.data.repack_dictlist(list_of_one_element_dicts)
  530. self.assertDictEqual(ret, expected_ret)
  531. # Try with yaml
  532. yaml_key_val_pair = '- key1: val1'
  533. ret = salt.utils.data.repack_dictlist(yaml_key_val_pair)
  534. self.assertDictEqual(ret, {'key1': 'val1'})
  535. # Make sure we handle non-yaml junk data
  536. ret = salt.utils.data.repack_dictlist(LOREM_IPSUM)
  537. self.assertDictEqual(ret, {})
  538. def test_stringify(self):
  539. self.assertRaises(TypeError, salt.utils.data.stringify, 9)
  540. self.assertEqual(
  541. salt.utils.data.stringify(['one', 'two', str('three'), 4, 5]), # future lint: disable=blacklisted-function
  542. ['one', 'two', 'three', '4', '5']
  543. )