text: """
  Copyright (c) Contributors to the Open 3D Engine Project.
  For complete copyright and license terms please see the LICENSE at the root of this distribution.
  
  SPDX-License-Identifier: Apache-2.0 OR MIT
  
  Unit Tests for android launcher-wrappers: all are sanity code-path tests, since no interprocess actions should be taken
  """
  
  import unittest.mock as mock
  
  import pytest
  
  import ly_test_tools.launchers
  import ly_test_tools.launchers.platforms.android.launcher
  import ly_test_tools.launchers.exceptions
  import ly_test_tools.mobile.android
  
  pytestmark = pytest.mark.SUITE_smoke
  
  VALID_ANDROID_CONFIG = {
      'android': {
          'id': '000000000000000'
      }
  }
  PACKAGE_NAME = "dummy_project_path"
  
  
  class MockedWorkspace(object):
  
      def __init__(self):
          self.paths = mock.MagicMock()
          self.setup_assistant = mock.MagicMock()
          self.asset_processor = mock.MagicMock()
          self.shader_compiler = mock.MagicMock()
          self.settings = mock.MagicMock()
  
          self.paths.engine_root.return_value = 'engine_path'
          self.paths.build_directory.return_value = 'build_directory'
          self.paths.autoexec_file.return_value = 'autoexec.cfg'
  
          self.project = 'project_name'
  
  
  @mock.patch('ly_test_tools.launchers.platforms.android.launcher.open', mock.mock_open())
  class TestLauncherModule:
  
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.json.loads')
      def test_GetPackageName_MockJsonHasKey_ReturnsValue(self, mock_json):
          dummy_name = "some_name"
          mock_json.return_value = {'android_settings': {'package_name': dummy_name}}
  
          under_test = ly_test_tools.launchers.platforms.android.launcher.get_package_name(PACKAGE_NAME)
  
          assert under_test == "some_name"
  
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.json.loads')
      def test_GetPackageName_MockJsonMissingKey_SetupError(self, mock_json):
          mock_json.return_value = {"one": "two"}
  
          with pytest.raises(ly_test_tools.launchers.exceptions.SetupError):
              ly_test_tools.launchers.platforms.android.launcher.get_package_name(PACKAGE_NAME)
  
      @mock.patch('ly_test_tools.environment.process_utils.check_output')
      def test_GetPid_EarlyVersionAndExplodes_NoPid(self, mock_output):
          mock_output.side_effect = ['23', Exception]
  
          under_test = ly_test_tools.launchers.platforms.android.launcher.get_pid("dummy", ["dummy"])
  
          assert mock_output.call_count == 2
          assert not under_test
  
      @mock.patch('ly_test_tools.environment.process_utils.check_output')
      def test_GetPid_LaterVersionAndExplodes_NoPid(self, mock_output):
          mock_output.side_effect = ['25', Exception]
  
          under_test = ly_test_tools.launchers.platforms.android.launcher.get_pid("dummy", ["dummy"])
  
          assert mock_output.call_count == 2
          assert not under_test
  
      @mock.patch('ly_test_tools.environment.process_utils.check_output')
      def test_GetPid_PidHasSingleValue_ReturnPid(self, mock_output):
          mock_output.side_effect = ['25', '12']
  
          under_test = ly_test_tools.launchers.platforms.android.launcher.get_pid("dummy", ["dummy"])
  
          assert mock_output.call_count == 2
          assert under_test == '12'
  
      @mock.patch('ly_test_tools.environment.process_utils.check_output')
      def test_GetPid_PidHasMultipleValues_ReturnPid(self, mock_output):
          mock_output.side_effect = ['25', 'value 12 found']
  
          under_test = ly_test_tools.launchers.platforms.android.launcher.get_pid("dummy", ["dummy"])
  
          assert mock_output.call_count == 2
          assert under_test == '12'
  
      def test_GenerateMapCommand_HasMapArg_ReturnsMapCommand(self):
          args_list = ['random_arg', '+map', 'map_name', 'another_arg']
  
          under_test = ly_test_tools.launchers.platforms.android.launcher.generate_android_map_command(args_list)
  
          assert under_test == 'map map_name'
  
      def test_GenerateMapCommand_NoMapArg_ReturnsEmptyString(self):
          args_list = ['random_arg', 'stuff', 'map_name', 'another_arg']
  
          under_test = ly_test_tools.launchers.platforms.android.launcher.generate_android_map_command(args_list)
  
          assert under_test == ''
  
  
  @mock.patch('os.listdir', mock.MagicMock())
  @mock.patch('ly_test_tools.launchers.platforms.android.launcher.get_package_name',
              mock.MagicMock(return_value=PACKAGE_NAME))
  @mock.patch('ly_test_tools.environment.file_system.create_backup', mock.MagicMock)
  @mock.patch('ly_test_tools.environment.file_system.restore_backup', mock.MagicMock)
  @mock.patch('ly_test_tools.mobile.android.check_adb_connection_state', mock.MagicMock)
  @mock.patch('ly_test_tools.launchers.platforms.android.launcher.open', mock.mock_open())
  class TestAndroidLauncher:
  
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      def test_ReadDeviceConfigINI_ReturnDeviceID_DeviceIDSet(self, mock_config):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
  
          launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
  
          assert launcher._device_id == VALID_ANDROID_CONFIG['android']['id']
          assert ['adb', '-s', launcher._device_id] == launcher._adb_prefix_command
          mock_config.assert_called_once()
  
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      def test_ReadDeviceConfigINI_ReturnsInvalidConfig_SetupError(self, mock_config):
          mock_config.return_value = {'device': {'id': 12345}}
          mock_workspace = MockedWorkspace()
  
          with pytest.raises(ly_test_tools.launchers.exceptions.SetupError):
              ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
  
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      @mock.patch('ly_test_tools.mobile.android.forward_tcp')
      @mock.patch('ly_test_tools.mobile.android.reverse_tcp')
      @mock.patch('ly_test_tools.mobile.android.undo_tcp_port_changes')
      def test_EnableAndroidCaps_SetsAndroidCaps_CallsReverseTCPForwardTCP(self, mock_undo_tcp, mock_reverse_tcp,
                                                                           mock_forward_tcp, mock_config):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
          under_test = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          under_test._enable_android_capabilities()
  
          assert mock_reverse_tcp.call_count == 2
          mock_forward_tcp.assert_called_once()
          mock_undo_tcp.assert_called_with(VALID_ANDROID_CONFIG['android']['id'])
  
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.backup_settings')
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.configure_settings')
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher._enable_android_capabilities')
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher._is_valid_android_environment')
      @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock(return_value=True))
      def test_Setup_ValidSetup_SetupCallsSucceed(self, mock_valid_env, mock_enable_caps, mock_config,
                                                  mock_configure_settings, mock_backup):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
          mock_project_log_path = 'c:/mock_project/log/'
          mock_workspace.paths.project_log.return_value = mock_project_log_path
  
          under_test = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          under_test.setup()
  
          mock_enable_caps.assert_called_once()
          mock_valid_env.assert_called_once()
          mock_backup.assert_called_once()
          mock_configure_settings.assert_called_once()
          mock_workspace.shader_compiler.start.assert_called_once()
  
      @mock.patch('ly_test_tools.mobile.android.can_run_android')
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.backup_settings', mock.MagicMock())
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.configure_settings',
                  mock.MagicMock())
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher._enable_android_capabilities',
                  mock.MagicMock())
      @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock(return_value=True))
      def test_Setup_InvalidSetupNoADB_RaisesNotImplementedErrorException(self, mock_config, mock_can_run_android):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
          mock_can_run_android.return_value = False
  
          under_test = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
  
          with pytest.raises(NotImplementedError):
              under_test.setup()
  
      @mock.patch('ly_test_tools.mobile.android.get_devices')
      @mock.patch('ly_test_tools.mobile.android.can_run_android', mock.MagicMock(return_value=True))
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.backup_settings', mock.MagicMock())
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.configure_settings',
                  mock.MagicMock())
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher._enable_android_capabilities',
                  mock.MagicMock())
      @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock(return_value=True))
      def test_Setup_InvalidSetupNoDeviceConnected_RaisesSetupErrorException(self, mock_config, mock_get_devices):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
          mock_get_devices.return_value = []
  
          under_test = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
  
          with pytest.raises(ly_test_tools.launchers.exceptions.SetupError):
              under_test.setup()
  
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher.restore_settings')
      @mock.patch('ly_test_tools.mobile.android.undo_tcp_port_changes', mock.MagicMock)
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher._enable_android_capabilities',
                  mock.MagicMock)
      def test_Teardown_ValidTeardown_TeardownSucceeds(self, mock_restore, mock_config):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
  
          launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          launcher.teardown()
  
          mock_restore.assert_called_once()
          mock_workspace.shader_compiler.stop.assert_called_once()
  
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      @mock.patch('ly_test_tools.o3de.settings.LySettings.modify_platform_setting', mock.MagicMock)
      def test_ConfigureSettings_DefaultValues_SetsValues(self, mock_config):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
  
          launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          launcher.configure_settings()
  
          assert mock_workspace.settings.modify_platform_setting.call_count == 8
  
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      @mock.patch('ly_test_tools.environment.process_utils.check_output')
      @mock.patch('os.path.isfile', mock.MagicMock(return_value=False))
      def test_Launch_HappyPathNoAutoexec_CallsLaunchCmd(self, mock_call, mock_config):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
  
          launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          launcher.launch()
  
          mock_call.assert_called_once_with([
              'adb', '-s', VALID_ANDROID_CONFIG['android']['id'], 'shell', 'monkey', '-p', PACKAGE_NAME,
              '-c', 'android.intent.category.LAUNCHER', '1'])
  
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      @mock.patch('ly_test_tools.environment.process_utils.check_output')
      @mock.patch('ly_test_tools.mobile.android.push_files_to_device', mock.MagicMock)
      @mock.patch('os.path.isfile', mock.MagicMock(return_value=True))
      def test_Launch_HappyPathHasAutoExec_PushesFilesToDevice(self, mock_push_files, mock_config):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
  
          launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          launcher.launch()
  
          mock_push_files.assert_called_once()
  
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      @mock.patch('ly_test_tools.environment.process_utils.check_output')
      @mock.patch('os.path.isfile', mock.MagicMock(return_value=False))
      def test_Launch_MonkeyAbortedInLaunchResult_RaisesSetupError(self, mock_call, mock_config):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_call.return_value = 'Monkey Aborted'
          mock_workspace = MockedWorkspace()
  
          launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          with pytest.raises(ly_test_tools.launchers.exceptions.SetupError):
              launcher.launch()
  
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.get_pid')
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      def test_IsAlive_MockPidDNE_False(self, mock_config, mock_pid):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
  
          launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          mock_pid.return_value = ""
  
          assert not launcher.is_alive()
  
      @mock.patch('ly_test_tools.launchers.platforms.android.launcher.get_pid')
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      def test_IsAlive_MockPidExists_True(self, mock_config, mock_pid):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
  
          launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          mock_pid.return_value = "1234"
  
          assert launcher.is_alive()
  
      @mock.patch('ly_test_tools.environment.process_utils.check_call')
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      @mock.patch('ly_test_tools.mobile.android.check_adb_connection_state',
                  mock.MagicMock(return_value=ly_test_tools.mobile.android.SINGLE_DEVICE))
      def test_Kill_HappyPath_KillCommandSuccess(self, mock_config, mock_call):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
  
          launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          launcher.kill()
  
          mock_call.assert_called_once_with(
              ['adb', '-s', VALID_ANDROID_CONFIG['android']['id'], 'shell', 'am', 'force-stop', PACKAGE_NAME])
  
      @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
      def test_BinaryPath_Called_RaisesNotImplementedError(self, mock_config):
          mock_config.return_value = VALID_ANDROID_CONFIG
          mock_workspace = MockedWorkspace()
  
          launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
          with pytest.raises(NotImplementedError):
              launcher.binary_path()
  