test_json.py 6.5 KB

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