test_xcode_selection.py (4745B)
1 from __future__ import annotations 2 3 import json 4 import os 5 import shutil 6 import subprocess 7 import sys 8 import tempfile 9 import unittest 10 from pathlib import Path 11 12 ROOT = Path(__file__).resolve().parent.parent 13 14 15 class XcodeSelectionTests(unittest.TestCase): 16 def setUp(self) -> None: 17 self.directory = tempfile.TemporaryDirectory() 18 self.addCleanup(self.directory.cleanup) 19 self.root = Path(self.directory.name) 20 (self.root / "scripts").mkdir() 21 shutil.copyfile(ROOT / "scripts/xcode.sh", self.root / "scripts/xcode.sh") 22 (self.root / "TeraUITests").mkdir() 23 shutil.copyfile( 24 ROOT / "TeraUITests/TeraAccessibilityUITests.swift", 25 self.root / "TeraUITests/TeraAccessibilityUITests.swift", 26 ) 27 self.arguments = self.root / "arguments.json" 28 executable = self.root / "xcodebuild" 29 executable.write_text( 30 f"#!{sys.executable}\n" 31 "import json, os, sys\n" 32 "from pathlib import Path\n" 33 "Path(os.environ['TEST_XCODE_ARGUMENTS']).write_text(json.dumps(sys.argv[1:]))\n" 34 ) 35 executable.chmod(0o700) 36 self.environment = { 37 **os.environ, 38 "PATH": f"{self.root}:{os.environ['PATH']}", 39 "TEST_XCODE_ARGUMENTS": str(self.arguments), 40 "XCODE_DERIVED_DATA": str(self.root / "derived"), 41 "XCODE_SOURCE_PACKAGES": str(self.root / "sources"), 42 "XCODE_PACKAGE_CACHE": str(self.root / "cache"), 43 } 44 45 def run_selector(self, target: str, *selector: str) -> subprocess.CompletedProcess: 46 return subprocess.run( 47 [ 48 "/bin/bash", 49 str(self.root / "scripts/xcode.sh"), 50 "project-test", 51 "platform=iOS Simulator,id=078A0172-207D-4EA6-8767-74DF7C42A73A", 52 target, 53 *selector, 54 ], 55 env=self.environment, 56 capture_output=True, 57 text=True, 58 check=False, 59 ) 60 61 def assert_selection(self, target: str, *selector: str) -> None: 62 result = self.run_selector(target, *selector) 63 self.assertEqual(result.returncode, 0, result.stderr) 64 arguments = json.loads(self.arguments.read_text()) 65 expected = target + (f"/{selector[0]}" if selector and selector[0] else "") 66 self.assertIn(f"-only-testing:{expected}", arguments) 67 self.assertEqual(arguments[-1], "test") 68 self.assertIn("-disableAutomaticPackageResolution", arguments) 69 self.assertIn("-onlyUsePackageVersionsFromResolvedFile", arguments) 70 for flag, variable in [ 71 ("-derivedDataPath", "XCODE_DERIVED_DATA"), 72 ("-clonedSourcePackagesDirPath", "XCODE_SOURCE_PACKAGES"), 73 ("-packageCachePath", "XCODE_PACKAGE_CACHE"), 74 ]: 75 self.assertEqual( 76 arguments[arguments.index(flag) + 1], self.environment[variable] 77 ) 78 79 def test_default_full_targets_and_empty_make_argument_are_preserved(self) -> None: 80 self.assert_selection("TeraTests") 81 self.assert_selection("TeraUITests") 82 self.assert_selection("TeraUITests", "") 83 84 def test_owned_class_and_method_select_exact_native_case(self) -> None: 85 self.assert_selection("TeraUITests", "TeraAccessibilityUITests") 86 self.assert_selection( 87 "TeraUITests", 88 "TeraAccessibilityUITests/testActualPhotoDescriptionRemainsEditableAcrossSaveFailureAndRecovery", 89 ) 90 91 def test_unknown_or_injected_selector_never_launches_xcode(self) -> None: 92 for target, selector in [ 93 ("TeraTests", "TeraAccessibilityUITests"), 94 ("Unknown", "TeraAccessibilityUITests"), 95 ("TeraUITests", "MissingUITests"), 96 ("TeraUITests", "TeraAccessibilityUITests/testMissing"), 97 ("TeraUITests", "../TeraAccessibilityUITests"), 98 ("TeraUITests", "TeraAccessibilityUITests/"), 99 ( 100 "TeraUITests", 101 "TeraAccessibilityUITests/testMissing/-skip-testing:TeraUITests", 102 ), 103 ("TeraUITests", "TeraAccessibilityUITests;touch marker"), 104 ]: 105 with self.subTest(target=target, selector=selector): 106 result = self.run_selector(target, selector) 107 self.assertNotEqual(result.returncode, 0) 108 self.assertFalse(self.arguments.exists()) 109 110 def test_extra_arguments_never_launch_xcode(self) -> None: 111 result = self.run_selector("TeraUITests", "", "-skip-testing:TeraUITests") 112 self.assertNotEqual(result.returncode, 0) 113 self.assertFalse(self.arguments.exists()) 114 115 116 if __name__ == "__main__": 117 unittest.main()