test_settings.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. """
  2. Copyright (c) Contributors to the Open 3D Engine Project.
  3. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. SPDX-License-Identifier: Apache-2.0 OR MIT
  5. """
  6. import unittest.mock as mock
  7. import unittest
  8. import pytest
  9. import ly_test_tools.o3de.settings
  10. pytestmark = pytest.mark.SUITE_smoke
  11. class MockDocumentInput(object):
  12. def __init__(self, lines):
  13. self._lines = lines
  14. def __iter__(self):
  15. return (line for line in self._lines)
  16. def close(self):
  17. pass
  18. class TestReplaceLineInFile(unittest.TestCase):
  19. def setUp(self):
  20. self.file_name = 'file1'
  21. self.search_for = 'search_for'
  22. self.replace_with = 'replace_with'
  23. self.mock_file_content = [
  24. "Setting1=Foo",
  25. ";Setting2=Bar",
  26. "Setting3=Baz ",
  27. "Setting4="]
  28. @mock.patch('fileinput.input')
  29. @mock.patch('os.path.isfile')
  30. @mock.patch('logging.Logger.warning')
  31. def test_ReplaceLineInFile_FileInUse_NoRaise(self, mock_log_warning, mock_path_isfile, mock_input):
  32. mock_path_isfile.return_value = True
  33. mock_input.side_effect = PermissionError()
  34. try:
  35. with mock.patch('__builtin__.open'):
  36. ly_test_tools.o3de.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
  37. except ImportError:
  38. with mock.patch('builtins.open'):
  39. ly_test_tools.o3de.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
  40. mock_log_warning.assert_called_once()
  41. @mock.patch('fileinput.input')
  42. @mock.patch('os.path.isfile')
  43. @mock.patch('logging.Logger.error')
  44. def test_ReplaceLineInFile_Error_Raises(self, mock_log_error, mock_path_isfile, mock_input):
  45. mock_path_isfile.return_value = True
  46. mock_input.side_effect = NotImplementedError()
  47. with pytest.raises(NotImplementedError):
  48. try:
  49. with mock.patch('__builtin__.open'):
  50. ly_test_tools.o3de.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
  51. except ImportError:
  52. with mock.patch('builtins.open'):
  53. ly_test_tools.o3de.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
  54. @mock.patch('fileinput.input')
  55. @mock.patch('os.path.isfile')
  56. def test_ReplaceLineInFile_FileFound_NoRaise(self, mock_path_isfile, mock_input):
  57. mock_path_isfile.return_value = True
  58. try:
  59. with mock.patch('__builtin__.open'):
  60. ly_test_tools.o3de.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
  61. except ImportError:
  62. with mock.patch('builtins.open'):
  63. ly_test_tools.o3de.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
  64. mock_input.return_value.close.assert_called_once_with()
  65. @mock.patch('os.path.isfile')
  66. @mock.patch('fileinput.input')
  67. @mock.patch('sys.stdout')
  68. def test_ReplaceLineInFile_SettingMatch_SettingReplaced(self, mock_stdout, mock_input, mock_isfile):
  69. mock_isfile.return_value = True
  70. mock_input.return_value = MockDocumentInput(self.mock_file_content)
  71. expected_print_lines = [
  72. mock.call.write("Setting1=NewFoo"), mock.call.write('\n'),
  73. mock.call.write(";Setting2=Bar"), mock.call.write('\n'),
  74. mock.call.write("Setting3=Baz"), mock.call.write('\n'),
  75. mock.call.write("Setting4="), mock.call.write('\n'),
  76. ]
  77. ly_test_tools.o3de.settings._edit_text_settings_file(self.file_name, 'Setting1', 'NewFoo')
  78. mock_stdout.assert_has_calls(expected_print_lines)
  79. @mock.patch('os.path.isfile')
  80. @mock.patch('fileinput.input')
  81. @mock.patch('sys.stdout')
  82. def test_ReplaceLineInFile_CommentedSettingMatch_SettingReplaced(self, mock_stdout, mock_input, mock_isfile):
  83. mock_isfile.return_value = True
  84. mock_input.return_value = MockDocumentInput(self.mock_file_content)
  85. expected_print_lines = [
  86. mock.call.write("Setting1=Foo"), mock.call.write('\n'),
  87. mock.call.write("Setting2=NewBar"), mock.call.write('\n'),
  88. mock.call.write("Setting3=Baz"), mock.call.write('\n'),
  89. mock.call.write("Setting4="), mock.call.write('\n'),
  90. ]
  91. ly_test_tools.o3de.settings._edit_text_settings_file(self.file_name, 'Setting2', 'NewBar')
  92. mock_stdout.assert_has_calls(expected_print_lines)
  93. @mock.patch('os.path.isfile')
  94. @mock.patch('fileinput.input')
  95. @mock.patch('sys.stdout')
  96. def test_ReplaceLineInFile_EmptySettingMatch_SettingReplaced(self, mock_stdout, mock_input, mock_isfile):
  97. mock_isfile.return_value = True
  98. mock_input.return_value = MockDocumentInput(self.mock_file_content)
  99. expected_print_lines = [
  100. mock.call.write("Setting1=Foo"), mock.call.write('\n'),
  101. mock.call.write(";Setting2=Bar"), mock.call.write('\n'),
  102. mock.call.write("Setting3=Baz"), mock.call.write('\n'),
  103. mock.call.write("Setting4=NewContent"), mock.call.write('\n'),
  104. ]
  105. ly_test_tools.o3de.settings._edit_text_settings_file(self.file_name, 'Setting4', 'NewContent')
  106. mock_stdout.assert_has_calls(expected_print_lines)
  107. @mock.patch('os.path.isfile')
  108. @mock.patch('fileinput.input')
  109. @mock.patch('sys.stdout')
  110. @mock.patch('builtins.open', mock.MagicMock())
  111. def test_ReplaceLineInFile_NoMatch_SettingAppended(self, mock_stdout, mock_input, mock_isfile):
  112. mock_isfile.return_value = True
  113. mock_input.return_value = MockDocumentInput(self.mock_file_content)
  114. expected_print_lines = [
  115. mock.call.write("Setting1=Foo"), mock.call.write('\n'),
  116. mock.call.write(";Setting2=Bar"), mock.call.write('\n'),
  117. mock.call.write("Setting3=Baz"), mock.call.write('\n'),
  118. mock.call.write("Setting4="), mock.call.write('\n'),
  119. ]
  120. ly_test_tools.o3de.settings._edit_text_settings_file(self.file_name, 'Setting5', 'NewSetting!')
  121. mock_stdout.assert_has_calls(expected_print_lines)
  122. class TestJsonSettings(unittest.TestCase):
  123. def setUp(self):
  124. self.test_file_name = 'something.json'
  125. self.mock_file_content = """
  126. {
  127. "name": "Foo",
  128. "weight": 30,
  129. "scale": {
  130. "x": 1,
  131. "y": 2,
  132. "z": 3
  133. },
  134. " ":"secret",
  135. "": 0
  136. }"""
  137. def test_ReadJson_RetrieveKey_Success(self,):
  138. mock_open = mock.mock_open(read_data=self.mock_file_content)
  139. with mock.patch('builtins.open', mock_open):
  140. with ly_test_tools.o3de.settings.JsonSettings(self.test_file_name) as js:
  141. # get the whole document
  142. value = js.get_key('')
  143. assert len(value) == 5
  144. # get a nested key
  145. value = js.get_key('/scale/x')
  146. assert value == 1
  147. # get the " " key ad the root level
  148. value = js.get_key('/ ')
  149. assert value == 'secret'
  150. # get the "" key at the root level
  151. value = js.get_key('/')
  152. assert value == 0
  153. def test_ReadJson_RetrieveMissingKey_DefaultReturned(self):
  154. mock_open = mock.mock_open(read_data=self.mock_file_content)
  155. default_value = -10
  156. with mock.patch('builtins.open', mock_open):
  157. with ly_test_tools.o3de.settings.JsonSettings(self.test_file_name) as js:
  158. value = js.get_key('/scale/w', default_value)
  159. assert value == default_value
  160. def test_ReadJson_ModifyKey_KeyModified(self):
  161. mock_open = mock.mock_open(read_data=self.mock_file_content)
  162. expected = 100
  163. with mock.patch('builtins.open', mock_open):
  164. with ly_test_tools.o3de.settings.JsonSettings(self.test_file_name) as js:
  165. js.set_key('/scale/x', expected)
  166. value = js.get_key('/scale/x')
  167. assert value == expected
  168. @mock.patch('json.dump')
  169. def test_WriteJson_ModifyKey_KeyModified(self, json_dump):
  170. mock_open = mock.mock_open(read_data=self.mock_file_content)
  171. expected = "this is the new value"
  172. new_dict_content = None
  173. def _mock_dump(content, file_path, indent):
  174. nonlocal new_dict_content
  175. new_dict_content = content
  176. json_dump.side_effect = _mock_dump
  177. with mock.patch('builtins.open', mock_open):
  178. with ly_test_tools.o3de.settings.JsonSettings(self.test_file_name) as js:
  179. js.set_key('/name', expected)
  180. assert expected == new_dict_content['name']
  181. @mock.patch('json.dump')
  182. def test_WriteJson_RemoveKey_KeyRemoved(self, json_dump):
  183. mock_open = mock.mock_open(read_data=self.mock_file_content)
  184. new_dict_content = None
  185. def _mock_dump(content, file_path, indent):
  186. nonlocal new_dict_content
  187. new_dict_content = content
  188. json_dump.side_effect = _mock_dump
  189. with mock.patch('builtins.open', mock_open):
  190. with ly_test_tools.o3de.settings.JsonSettings(self.test_file_name) as js:
  191. js.remove_key('/scale/z')
  192. assert len(new_dict_content['scale']) == 2