|  | #!/usr/bin/env vpython3 | 
|  | # Copyright 2021 The Chromium Authors | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  | """Unittests for xcode_util.py.""" | 
|  |  | 
|  | import logging | 
|  | import mock | 
|  | import os | 
|  | import unittest | 
|  |  | 
|  | import test_runner_errors | 
|  | import test_runner_test | 
|  | import xcode_util | 
|  |  | 
|  |  | 
|  | _XCODEBUILD_VERSION_OUTPUT_12 = b"""Xcode 12.4 | 
|  | Build version 12D4e | 
|  | """ | 
|  | _XCODEBUILD_VERSION_OUTPUT_13 = b"""Xcode 13.0 | 
|  | Build version 13A5155e | 
|  | """ | 
|  |  | 
|  |  | 
|  | class XcodeUtilTest(test_runner_test.TestCase): | 
|  | """Test class for xcode_util functions.""" | 
|  |  | 
|  | def setUp(self): | 
|  | super(XcodeUtilTest, self).setUp() | 
|  |  | 
|  | @mock.patch( | 
|  | 'subprocess.check_output', return_value=_XCODEBUILD_VERSION_OUTPUT_13) | 
|  | def test_version(self, _): | 
|  | """Tests xcode_util.version()""" | 
|  | version, build_version = xcode_util.version() | 
|  | self.assertEqual(version, '13.0') | 
|  | self.assertEqual(build_version, '13a5155e') | 
|  |  | 
|  | @mock.patch( | 
|  | 'subprocess.check_output', return_value=_XCODEBUILD_VERSION_OUTPUT_12) | 
|  | def test_using_xcode_12(self, _): | 
|  | """Tests xcode_util.using_xcode_11_or_higher""" | 
|  | self.assertTrue(xcode_util.using_xcode_11_or_higher()) | 
|  | self.assertFalse(xcode_util.using_xcode_13_or_higher()) | 
|  |  | 
|  | @mock.patch( | 
|  | 'subprocess.check_output', return_value=_XCODEBUILD_VERSION_OUTPUT_13) | 
|  | def test_using_xcode_13(self, _): | 
|  | """Tests xcode_util.using_xcode_13_or_higher""" | 
|  | self.assertTrue(xcode_util.using_xcode_11_or_higher()) | 
|  | self.assertTrue(xcode_util.using_xcode_13_or_higher()) | 
|  |  | 
|  |  | 
|  | class InstallTest(XcodeUtilTest): | 
|  | """Test class for xcode_util.install function.""" | 
|  |  | 
|  | def setUp(self): | 
|  | super(InstallTest, self).setUp() | 
|  | self.mac_toolchain = 'mac_toolchain' | 
|  | self.xcode_build_version = 'TestXcodeVersion' | 
|  | self.xcode_app_path = 'test/path/Xcode.app' | 
|  | self.runtime_cache_folder = 'test/path/Runtime' | 
|  | self.ios_version = '14.4' | 
|  |  | 
|  | @mock.patch('xcode_util.move_runtime', autospec=True) | 
|  | @mock.patch('xcode_util._install_runtime', autospec=True) | 
|  | @mock.patch('xcode_util._install_xcode', autospec=True) | 
|  | def test_legacy_mactoolchain_new_xcode(self, mock_install_xcode, | 
|  | mock_install_runtime, | 
|  | mock_move_runtime): | 
|  | self.mock(xcode_util, '_using_new_mac_toolchain', lambda cmd: False) | 
|  | self.mock(xcode_util, '_is_legacy_xcode_package', lambda path: False) | 
|  |  | 
|  | with self.assertRaises(test_runner_errors.XcodeMacToolchainMismatchError): | 
|  | is_legacy_xcode = xcode_util.install(self.mac_toolchain, | 
|  | self.xcode_build_version, | 
|  | self.xcode_app_path) | 
|  | self.assertTrue(is_legacy_xcode, 'install should return true') | 
|  |  | 
|  | mock_install_xcode.assert_called_with('mac_toolchain', 'TestXcodeVersion', | 
|  | 'test/path/Xcode.app', False) | 
|  | self.assertFalse(mock_install_runtime.called, | 
|  | '_install_runtime shouldn\'t be called') | 
|  | self.assertFalse(mock_move_runtime.called, | 
|  | 'move_runtime shouldn\'t be called') | 
|  |  | 
|  | @mock.patch('xcode_util.move_runtime', autospec=True) | 
|  | @mock.patch('xcode_util._install_runtime', autospec=True) | 
|  | @mock.patch('xcode_util._install_xcode', autospec=True) | 
|  | def test_legacy_mactoolchain_legacy_xcode(self, mock_install_xcode, | 
|  | mock_install_runtime, | 
|  | mock_move_runtime): | 
|  | self.mock(xcode_util, '_using_new_mac_toolchain', lambda cmd: False) | 
|  | self.mock(xcode_util, '_is_legacy_xcode_package', lambda path: True) | 
|  |  | 
|  | is_legacy_xcode = xcode_util.install(self.mac_toolchain, | 
|  | self.xcode_build_version, | 
|  | self.xcode_app_path) | 
|  |  | 
|  | self.assertTrue(is_legacy_xcode, 'install_should return true') | 
|  | mock_install_xcode.assert_called_with('mac_toolchain', 'TestXcodeVersion', | 
|  | 'test/path/Xcode.app', False) | 
|  | self.assertFalse(mock_install_runtime.called, | 
|  | '_install_runtime shouldn\'t be called') | 
|  | self.assertFalse(mock_move_runtime.called, | 
|  | 'move_runtime shouldn\'t be called') | 
|  |  | 
|  | @mock.patch('xcode_util.move_runtime', autospec=True) | 
|  | @mock.patch('xcode_util._install_runtime', autospec=True) | 
|  | @mock.patch('xcode_util._install_xcode', autospec=True) | 
|  | def test_new_mactoolchain_legacy_xcode(self, mock_install_xcode, | 
|  | mock_install_runtime, | 
|  | mock_move_runtime): | 
|  | self.mock(xcode_util, '_using_new_mac_toolchain', lambda cmd: True) | 
|  | self.mock(xcode_util, '_is_legacy_xcode_package', lambda path: True) | 
|  |  | 
|  | is_legacy_xcode = xcode_util.install(self.mac_toolchain, | 
|  | self.xcode_build_version, | 
|  | self.xcode_app_path) | 
|  |  | 
|  | self.assertTrue(is_legacy_xcode, 'install should return true') | 
|  | mock_install_xcode.assert_called_with('mac_toolchain', 'TestXcodeVersion', | 
|  | 'test/path/Xcode.app', True) | 
|  | self.assertFalse(mock_install_runtime.called, | 
|  | '_install_runtime shouldn\'t be called') | 
|  | self.assertFalse(mock_move_runtime.called, | 
|  | 'move_runtime shouldn\'t be called') | 
|  |  | 
|  | @mock.patch('xcode_util.move_runtime', autospec=True) | 
|  | @mock.patch('xcode_util._install_runtime') | 
|  | @mock.patch('xcode_util._install_xcode') | 
|  | def test_new_mactoolchain_new_xcode(self, mock_install_xcode, | 
|  | mock_install_runtime, mock_move_runtime): | 
|  | self.mock(xcode_util, '_using_new_mac_toolchain', lambda cmd: True) | 
|  | self.mock(xcode_util, '_is_legacy_xcode_package', lambda path: False) | 
|  |  | 
|  | is_legacy_xcode = xcode_util.install( | 
|  | self.mac_toolchain, | 
|  | self.xcode_build_version, | 
|  | self.xcode_app_path, | 
|  | runtime_cache_folder=self.runtime_cache_folder, | 
|  | ios_version=self.ios_version) | 
|  |  | 
|  | self.assertFalse(is_legacy_xcode, 'install should return False') | 
|  | mock_install_xcode.assert_called_with('mac_toolchain', 'TestXcodeVersion', | 
|  | 'test/path/Xcode.app', True) | 
|  | mock_install_runtime.assert_called_with('mac_toolchain', | 
|  | 'test/path/Runtime', | 
|  | 'TestXcodeVersion', '14.4') | 
|  | mock_move_runtime.assert_called_with('test/path/Runtime', | 
|  | 'test/path/Xcode.app', True) | 
|  |  | 
|  | @mock.patch('xcode_util.move_runtime', autospec=True) | 
|  | @mock.patch('xcode_util._install_runtime') | 
|  | @mock.patch('xcode_util._install_xcode') | 
|  | def test_new_mactoolchain_new_xcode_no_runtime(self, mock_install_xcode, | 
|  | mock_install_runtime, | 
|  | mock_move_runtime): | 
|  | self.mock(xcode_util, '_using_new_mac_toolchain', lambda cmd: True) | 
|  | self.mock(xcode_util, '_is_legacy_xcode_package', lambda path: False) | 
|  |  | 
|  | is_legacy_xcode = xcode_util.install( | 
|  | self.mac_toolchain, | 
|  | self.xcode_build_version, | 
|  | self.xcode_app_path, | 
|  | runtime_cache_folder=None, | 
|  | ios_version=None) | 
|  |  | 
|  | self.assertFalse(is_legacy_xcode, 'install should return False') | 
|  | mock_install_xcode.assert_called_with('mac_toolchain', 'TestXcodeVersion', | 
|  | 'test/path/Xcode.app', True) | 
|  | self.assertFalse(mock_install_runtime.called) | 
|  | self.assertFalse(mock_move_runtime.called) | 
|  |  | 
|  |  | 
|  | class HelperFunctionTests(XcodeUtilTest): | 
|  | """Test class for xcode_util misc util functions.""" | 
|  |  | 
|  | def setUp(self): | 
|  | super(HelperFunctionTests, self).setUp() | 
|  | self.xcode_runtime_dir_rel_path = ( | 
|  | 'Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes') | 
|  | self.xcode_runtime_rel_path = ( | 
|  | 'Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/iOS.simruntime') | 
|  |  | 
|  | @mock.patch('subprocess.check_output', autospec=True) | 
|  | def test_using_new_mac_toolchain(self, mock_check_output): | 
|  | mock_check_output.return_value = b""" | 
|  | Mac OS / iOS toolchain management | 
|  |  | 
|  | Usage:  mac_toolchain [command] [arguments] | 
|  |  | 
|  | Commands: | 
|  | help             prints help about a command | 
|  | install          Installs Xcode. | 
|  | upload           Uploads Xcode CIPD packages. | 
|  | package          Create CIPD packages locally. | 
|  | install-runtime  Installs Runtime. | 
|  |  | 
|  |  | 
|  | Use "mac_toolchain help [command]" for more information about a command.""" | 
|  | self.assertTrue(xcode_util._using_new_mac_toolchain('mac_toolchain')) | 
|  |  | 
|  | @mock.patch('subprocess.check_output', autospec=True) | 
|  | def test_using_new_legacy_toolchain(self, mock_check_output): | 
|  | mock_check_output.return_value = b""" | 
|  | Mac OS / iOS toolchain management | 
|  |  | 
|  | Usage:  mac_toolchain [command] [arguments] | 
|  |  | 
|  | Commands: | 
|  | help             prints help about a command | 
|  | install          Installs Xcode. | 
|  | upload           Uploads Xcode CIPD packages. | 
|  | package          Create CIPD packages locally. | 
|  |  | 
|  |  | 
|  | Use "mac_toolchain help [command]" for more information about a command.""" | 
|  | self.assertFalse(xcode_util._using_new_mac_toolchain('mac_toolchain')) | 
|  |  | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | def test_is_legacy_xcode_package_legacy(self, mock_glob, mock_rmtree): | 
|  | test_xcode_path = 'test/path/Xcode.app/' | 
|  | runtime_names = ['iOS.simruntime', 'iOS 12.4.simruntime'] | 
|  | xcode_runtime_paths = [ | 
|  | os.path.join(test_xcode_path, self.xcode_runtime_dir_rel_path, | 
|  | runtime_name) for runtime_name in runtime_names | 
|  | ] | 
|  | mock_glob.return_value = xcode_runtime_paths | 
|  | self.assertTrue(xcode_util._is_legacy_xcode_package(test_xcode_path)) | 
|  | mock_glob.assert_called_with( | 
|  | os.path.join(test_xcode_path, self.xcode_runtime_dir_rel_path, | 
|  | '*.simruntime')) | 
|  | self.assertFalse(mock_rmtree.called) | 
|  |  | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | def test_is_legacy_xcode_package_no_runtime(self, mock_glob, mock_rmtree): | 
|  | test_xcode_path = 'test/path/Xcode.app/' | 
|  | xcode_runtime_paths = [] | 
|  | mock_glob.return_value = xcode_runtime_paths | 
|  | self.assertFalse(xcode_util._is_legacy_xcode_package(test_xcode_path)) | 
|  | mock_glob.assert_called_with( | 
|  | os.path.join(test_xcode_path, self.xcode_runtime_dir_rel_path, | 
|  | '*.simruntime')) | 
|  | self.assertFalse(mock_rmtree.called) | 
|  |  | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | def test_is_legacy_xcode_package_single_runtime(self, mock_glob, mock_rmtree): | 
|  | test_xcode_path = 'test/path/Xcode.app/' | 
|  | runtime_names = ['iOS.simruntime'] | 
|  | xcode_runtime_paths = [ | 
|  | os.path.join(test_xcode_path, self.xcode_runtime_dir_rel_path, | 
|  | runtime_name) for runtime_name in runtime_names | 
|  | ] | 
|  | mock_glob.return_value = xcode_runtime_paths | 
|  | self.assertFalse(xcode_util._is_legacy_xcode_package(test_xcode_path)) | 
|  | mock_glob.assert_called_with( | 
|  | os.path.join(test_xcode_path, self.xcode_runtime_dir_rel_path, | 
|  | '*.simruntime')) | 
|  | mock_rmtree.assert_called_with( | 
|  | os.path.join(test_xcode_path, self.xcode_runtime_dir_rel_path, | 
|  | 'iOS.simruntime')) | 
|  |  | 
|  |  | 
|  | class MoveRuntimeTests(XcodeUtilTest): | 
|  | """Test class for xcode_util.move_runtime function.""" | 
|  |  | 
|  | def setUp(self): | 
|  | super(MoveRuntimeTests, self).setUp() | 
|  | self.runtime_cache_folder = 'test/path/Runtime' | 
|  | self.xcode_app_path = 'test/path/Xcode.app' | 
|  |  | 
|  | @mock.patch('shutil.move', autospec=True) | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | def test_move_runtime_into_xcode(self, mock_glob, mock_rmtree, mock_move): | 
|  |  | 
|  | mock_glob.side_effect = [['test/path/Runtime/iOS.simruntime'], []] | 
|  |  | 
|  | xcode_util.move_runtime(self.runtime_cache_folder, self.xcode_app_path, | 
|  | True) | 
|  |  | 
|  | xcode_runtime_path = ('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/iOS.simruntime') | 
|  | calls = [ | 
|  | mock.call('test/path/Runtime/*.simruntime'), | 
|  | mock.call(('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/*.simruntime')) | 
|  | ] | 
|  | mock_glob.assert_has_calls(calls) | 
|  | self.assertFalse(mock_rmtree.called) | 
|  | mock_move.assert_called_with('test/path/Runtime/iOS.simruntime', | 
|  | xcode_runtime_path) | 
|  |  | 
|  | @mock.patch('shutil.move', autospec=True) | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | def test_move_runtime_outside_xcode(self, mock_glob, mock_rmtree, mock_move): | 
|  | xcode_runtime_folder = ('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes') | 
|  | mock_glob.side_effect = [[xcode_runtime_folder + '/iOS.simruntime'], []] | 
|  |  | 
|  | xcode_util.move_runtime(self.runtime_cache_folder, self.xcode_app_path, | 
|  | False) | 
|  |  | 
|  | calls = [ | 
|  | mock.call(('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/*.simruntime')), | 
|  | mock.call('test/path/Runtime/*.simruntime') | 
|  | ] | 
|  | mock_glob.assert_has_calls(calls) | 
|  | self.assertFalse(mock_rmtree.called) | 
|  | mock_move.assert_called_with(xcode_runtime_folder + '/iOS.simruntime', | 
|  | 'test/path/Runtime/iOS.simruntime') | 
|  |  | 
|  | @mock.patch('shutil.move', autospec=True) | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | def test_move_runtime_multiple_in_src(self, mock_glob, mock_rmtree, | 
|  | mock_move): | 
|  | mock_glob.side_effect = [[ | 
|  | 'test/path/Runtime/iOS.simruntime', | 
|  | 'test/path/Runtime/iOS 13.4.simruntime' | 
|  | ], []] | 
|  |  | 
|  | with self.assertRaises(test_runner_errors.IOSRuntimeHandlingError): | 
|  | xcode_util.move_runtime(self.runtime_cache_folder, self.xcode_app_path, | 
|  | True) | 
|  | mock_glob.assert_called_with('test/path/Runtime/*.simruntime') | 
|  | self.assertFalse(mock_rmtree.called) | 
|  | self.assertFalse(mock_move.called) | 
|  |  | 
|  | @mock.patch('shutil.move', autospec=True) | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | def test_move_runtime_remove_from_dst(self, mock_glob, mock_rmtree, | 
|  | mock_move): | 
|  |  | 
|  | mock_glob.side_effect = [['test/path/Runtime/iOS.simruntime'], | 
|  | [('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/iOS.simruntime') | 
|  | ]] | 
|  |  | 
|  | xcode_util.move_runtime(self.runtime_cache_folder, self.xcode_app_path, | 
|  | True) | 
|  |  | 
|  | xcode_runtime_path = ('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/iOS.simruntime') | 
|  | calls = [ | 
|  | mock.call('test/path/Runtime/*.simruntime'), | 
|  | mock.call(('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/*.simruntime')) | 
|  | ] | 
|  | mock_glob.assert_has_calls(calls) | 
|  | mock_rmtree.assert_called_with(xcode_runtime_path) | 
|  | mock_move.assert_called_with('test/path/Runtime/iOS.simruntime', | 
|  | xcode_runtime_path) | 
|  |  | 
|  |  | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | def test_remove_runtimes(self, mock_glob, mock_rmtree): | 
|  |  | 
|  | mock_glob.return_value = [ | 
|  | ('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/iOS.simruntime'), | 
|  | ('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/iOS 15.0.simruntime') | 
|  | ] | 
|  |  | 
|  | xcode_util.remove_runtimes(self.xcode_app_path) | 
|  |  | 
|  | calls = [ | 
|  | mock.call(('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/*.simruntime')) | 
|  | ] | 
|  | mock_glob.assert_has_calls(calls) | 
|  | calls = [ | 
|  | mock.call(('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/iOS.simruntime')), | 
|  | mock.call(('test/path/Xcode.app/Contents/Developer/' | 
|  | 'Platforms/iPhoneOS.platform/Library/Developer/' | 
|  | 'CoreSimulator/Profiles/Runtimes/iOS 15.0.simruntime')) | 
|  | ] | 
|  | mock_rmtree.assert_has_calls(calls) | 
|  |  | 
|  |  | 
|  | class MacToolchainInvocationTests(XcodeUtilTest): | 
|  | """Test class for xcode_util functions invoking mac_toolchain.""" | 
|  |  | 
|  | def setUp(self): | 
|  | super(MacToolchainInvocationTests, self).setUp() | 
|  | self.mac_toolchain = 'mac_toolchain' | 
|  | self.xcode_build_version = 'TestXcodeVersion' | 
|  | self.xcode_app_path = 'test/path/Xcode.app' | 
|  | self.runtime_cache_folder = 'test/path/Runtime' | 
|  | self.ios_version = '14.4' | 
|  |  | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('os.path.exists', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | @mock.patch('subprocess.check_call', autospec=True) | 
|  | def test_install_runtime_no_cache(self, mock_check_output, mock_glob, | 
|  | mock_exists, mock_rmtree): | 
|  | mock_glob.return_value = [] | 
|  | mock_exists.return_value = False | 
|  |  | 
|  | xcode_util._install_runtime(self.mac_toolchain, self.runtime_cache_folder, | 
|  | self.xcode_build_version, self.ios_version) | 
|  |  | 
|  | mock_glob.assert_called_with('test/path/Runtime/*.simruntime') | 
|  | calls = [ | 
|  | mock.call('test/path/Runtime/.cipd'), | 
|  | mock.call('test/path/Runtime/.xcode_versions'), | 
|  | ] | 
|  | mock_exists.assert_has_calls(calls) | 
|  | self.assertFalse(mock_rmtree.called) | 
|  | mock_check_output.assert_called_with([ | 
|  | 'mac_toolchain', 'install-runtime', '-xcode-version', | 
|  | 'testxcodeversion', '-runtime-version', 'ios-14-4', '-output-dir', | 
|  | 'test/path/Runtime' | 
|  | ], | 
|  | stderr=-2) | 
|  |  | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('os.path.exists', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | @mock.patch('subprocess.check_call', autospec=True) | 
|  | def test_install_runtime_has_cache(self, mock_check_output, mock_glob, | 
|  | mock_exists, mock_rmtree): | 
|  | mock_glob.return_value = ['test/path/Runtime/iOS.simruntime'] | 
|  | xcode_util._install_runtime(self.mac_toolchain, self.runtime_cache_folder, | 
|  | self.xcode_build_version, self.ios_version) | 
|  |  | 
|  | mock_glob.assert_called_with('test/path/Runtime/*.simruntime') | 
|  | self.assertFalse(mock_exists.called) | 
|  | self.assertFalse(mock_rmtree.called) | 
|  | mock_check_output.assert_called_with([ | 
|  | 'mac_toolchain', 'install-runtime', '-xcode-version', | 
|  | 'testxcodeversion', '-runtime-version', 'ios-14-4', '-output-dir', | 
|  | 'test/path/Runtime' | 
|  | ], | 
|  | stderr=-2) | 
|  |  | 
|  | @mock.patch('shutil.rmtree', autospec=True) | 
|  | @mock.patch('os.path.exists', autospec=True) | 
|  | @mock.patch('glob.glob', autospec=True) | 
|  | @mock.patch('subprocess.check_call', autospec=True) | 
|  | def test_install_runtime_incorrect_cache(self, mock_check_output, mock_glob, | 
|  | mock_exists, mock_rmtree): | 
|  | mock_glob.return_value = [] | 
|  | mock_exists.return_value = True | 
|  |  | 
|  | xcode_util._install_runtime(self.mac_toolchain, self.runtime_cache_folder, | 
|  | self.xcode_build_version, self.ios_version) | 
|  |  | 
|  | mock_glob.assert_called_with('test/path/Runtime/*.simruntime') | 
|  | calls = [ | 
|  | mock.call('test/path/Runtime/.cipd'), | 
|  | mock.call('test/path/Runtime/.xcode_versions'), | 
|  | ] | 
|  | mock_exists.assert_has_calls(calls) | 
|  | mock_rmtree.assert_has_calls(calls) | 
|  |  | 
|  | mock_check_output.assert_called_with([ | 
|  | 'mac_toolchain', 'install-runtime', '-xcode-version', | 
|  | 'testxcodeversion', '-runtime-version', 'ios-14-4', '-output-dir', | 
|  | 'test/path/Runtime' | 
|  | ], | 
|  | stderr=-2) | 
|  |  | 
|  | @mock.patch('subprocess.check_call', autospec=True) | 
|  | def test_install_xcode_legacy_mac_toolchain(self, mock_check_output): | 
|  | using_new_mac_toolchain = False | 
|  | xcode_util._install_xcode(self.mac_toolchain, self.xcode_build_version, | 
|  | self.xcode_app_path, using_new_mac_toolchain) | 
|  | mock_check_output.assert_called_with([ | 
|  | 'mac_toolchain', 'install', '-kind', 'ios', '-xcode-version', | 
|  | 'testxcodeversion', '-output-dir', 'test/path/Xcode.app' | 
|  | ], | 
|  | stderr=-2) | 
|  |  | 
|  | @mock.patch('subprocess.check_call', autospec=True) | 
|  | def test_install_xcode_new_mac_toolchain(self, mock_check_output): | 
|  | using_new_mac_toolchain = True | 
|  | xcode_util._install_xcode(self.mac_toolchain, self.xcode_build_version, | 
|  | self.xcode_app_path, using_new_mac_toolchain) | 
|  | mock_check_output.assert_called_with([ | 
|  | 'mac_toolchain', 'install', '-kind', 'ios', '-xcode-version', | 
|  | 'testxcodeversion', '-output-dir', 'test/path/Xcode.app', | 
|  | '-with-runtime=False' | 
|  | ], | 
|  | stderr=-2) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | logging.basicConfig( | 
|  | format='[%(asctime)s:%(levelname)s] %(message)s', | 
|  | level=logging.DEBUG, | 
|  | datefmt='%I:%M:%S') | 
|  | unittest.main() |