test_json.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Tests for salt.utils.json
  4. '''
  5. # Import Python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import textwrap
  8. # Import Salt Testing libs
  9. from tests.support.helpers import with_tempfile
  10. from tests.support.mock import patch, MagicMock, NO_MOCK, NO_MOCK_REASON
  11. from tests.support.unit import TestCase, LOREM_IPSUM, skipIf
  12. # Import Salt libs
  13. import salt.utils.files
  14. import salt.utils.json
  15. import salt.utils.platform
  16. import salt.utils.stringutils
  17. from salt.ext import six
  18. class JSONTestCase(TestCase):
  19. data = {
  20. 'спам': 'яйца',
  21. 'list': [1, 2, 'three'],
  22. 'dict': {'subdict': {'спам': 'яйца'}},
  23. 'True': False,
  24. 'float': 1.5,
  25. 'None': None,
  26. }
  27. serialized = salt.utils.stringutils.to_str(
  28. '{"None": null, "True": false, "dict": {"subdict": {"спам": "яйца"}}, "float": 1.5, "list": [1, 2, "three"], "спам": "яйца"}'
  29. )
  30. serialized_indent4 = salt.utils.stringutils.to_str(textwrap.dedent('''\
  31. {
  32. "None": null,
  33. "True": false,
  34. "dict": {
  35. "subdict": {
  36. "спам": "яйца"
  37. }
  38. },
  39. "float": 1.5,
  40. "list": [
  41. 1,
  42. 2,
  43. "three"
  44. ],
  45. "спам": "яйца"
  46. }'''))
  47. def test_find_json(self):
  48. test_sample_json = '''
  49. {
  50. "glossary": {
  51. "title": "example glossary",
  52. "GlossDiv": {
  53. "title": "S",
  54. "GlossList": {
  55. "GlossEntry": {
  56. "ID": "SGML",
  57. "SortAs": "SGML",
  58. "GlossTerm": "Standard Generalized Markup Language",
  59. "Acronym": "SGML",
  60. "Abbrev": "ISO 8879:1986",
  61. "GlossDef": {
  62. "para": "A meta-markup language, used to create markup languages such as DocBook.",
  63. "GlossSeeAlso": ["GML", "XML"]
  64. },
  65. "GlossSee": "markup"
  66. }
  67. }
  68. }
  69. }
  70. }
  71. '''
  72. expected_ret = {'glossary': {'GlossDiv': {'GlossList': {'GlossEntry': {
  73. 'GlossDef': {'GlossSeeAlso': ['GML', 'XML'],
  74. 'para': 'A meta-markup language, used to create markup languages such as DocBook.'},
  75. 'GlossSee': 'markup', 'Acronym': 'SGML', 'GlossTerm': 'Standard Generalized Markup Language',
  76. 'SortAs': 'SGML',
  77. 'Abbrev': 'ISO 8879:1986', 'ID': 'SGML'}}, 'title': 'S'}, 'title': 'example glossary'}}
  78. # First test the valid JSON
  79. ret = salt.utils.json.find_json(test_sample_json)
  80. self.assertDictEqual(ret, expected_ret)
  81. # Now pre-pend some garbage and re-test
  82. garbage_prepend_json = '{0}{1}'.format(LOREM_IPSUM, test_sample_json)
  83. ret = salt.utils.json.find_json(garbage_prepend_json)
  84. self.assertDictEqual(ret, expected_ret)
  85. # Test to see if a ValueError is raised if no JSON is passed in
  86. self.assertRaises(ValueError, salt.utils.json.find_json, LOREM_IPSUM)
  87. @skipIf(salt.utils.platform.is_windows(), 'skip until we figure out what to do about decoding unicode on windows')
  88. @skipIf(not six.PY2, 'Test only needed on Python 2')
  89. @skipIf(NO_MOCK, NO_MOCK_REASON)
  90. def test_find_json_unicode_splitlines(self):
  91. '''
  92. Tests a case in salt-ssh where a unicode string is split into a list of
  93. str types by .splitlines().
  94. '''
  95. raw = '{"foo": "öäü"}'
  96. mock_split = MagicMock(return_value=[raw.encode('utf8')])
  97. with patch.object(salt.utils.json, '__split', mock_split):
  98. ret = salt.utils.json.find_json(raw)
  99. self.assertEqual(ret, {'foo': 'öäü'})
  100. def test_dumps_loads(self):
  101. '''
  102. Test dumping to and loading from a string
  103. '''
  104. # Dump with no indentation
  105. ret = salt.utils.json.dumps(self.data, sort_keys=True)
  106. # Make sure the result is as expected
  107. self.assertEqual(ret, self.serialized)
  108. # Loading it should be equal to the original data
  109. self.assertEqual(salt.utils.json.loads(ret), self.data)
  110. # Dump with 4 spaces of indentation
  111. ret = salt.utils.json.dumps(self.data, sort_keys=True, indent=4)
  112. # Make sure the result is as expected. Note that in Python 2, dumping
  113. # results in trailing whitespace on lines ending in a comma. So, for a
  114. # proper comparison, we will have to run rstrip on each line of the
  115. # return and then stitch it back together.
  116. ret = str('\n').join([x.rstrip() for x in ret.splitlines()]) # future lint: disable=blacklisted-function
  117. self.assertEqual(ret, self.serialized_indent4)
  118. # Loading it should be equal to the original data
  119. self.assertEqual(salt.utils.json.loads(ret), self.data)
  120. @with_tempfile()
  121. def test_dump_load(self, json_out):
  122. '''
  123. Test dumping to and loading from a file handle
  124. '''
  125. with salt.utils.files.fopen(json_out, 'wb') as fp_:
  126. fp_.write(salt.utils.stringutils.to_bytes(salt.utils.json.dumps(self.data)))
  127. with salt.utils.files.fopen(json_out, 'rb') as fp_:
  128. ret = salt.utils.json.loads(salt.utils.stringutils.to_unicode(fp_.read()))
  129. # Loading should be equal to the original data
  130. self.assertEqual(ret, self.data)