1from . import util as test_util 2machinery = test_util.import_importlib('importlib.machinery') 3 4import os 5import re 6import sys 7import unittest 8import warnings 9from test import support 10from test.support import import_helper 11from contextlib import contextmanager 12from .util import temp_module 13 14import_helper.import_module('winreg', required_on=['win']) 15from winreg import ( 16 CreateKey, HKEY_CURRENT_USER, 17 SetValue, REG_SZ, KEY_ALL_ACCESS, 18 EnumKey, CloseKey, DeleteKey, OpenKey 19) 20 21def get_platform(): 22 # Port of distutils.util.get_platform(). 23 TARGET_TO_PLAT = { 24 'x86' : 'win32', 25 'x64' : 'win-amd64', 26 'arm' : 'win-arm32', 27 } 28 if ('VSCMD_ARG_TGT_ARCH' in os.environ and 29 os.environ['VSCMD_ARG_TGT_ARCH'] in TARGET_TO_PLAT): 30 return TARGET_TO_PLAT[os.environ['VSCMD_ARG_TGT_ARCH']] 31 elif 'amd64' in sys.version.lower(): 32 return 'win-amd64' 33 elif '(arm)' in sys.version.lower(): 34 return 'win-arm32' 35 elif '(arm64)' in sys.version.lower(): 36 return 'win-arm64' 37 else: 38 return sys.platform 39 40def delete_registry_tree(root, subkey): 41 try: 42 hkey = OpenKey(root, subkey, access=KEY_ALL_ACCESS) 43 except OSError: 44 # subkey does not exist 45 return 46 while True: 47 try: 48 subsubkey = EnumKey(hkey, 0) 49 except OSError: 50 # no more subkeys 51 break 52 delete_registry_tree(hkey, subsubkey) 53 CloseKey(hkey) 54 DeleteKey(root, subkey) 55 56@contextmanager 57def setup_module(machinery, name, path=None): 58 if machinery.WindowsRegistryFinder.DEBUG_BUILD: 59 root = machinery.WindowsRegistryFinder.REGISTRY_KEY_DEBUG 60 else: 61 root = machinery.WindowsRegistryFinder.REGISTRY_KEY 62 key = root.format(fullname=name, 63 sys_version='%d.%d' % sys.version_info[:2]) 64 try: 65 with temp_module(name, "a = 1") as location: 66 subkey = CreateKey(HKEY_CURRENT_USER, key) 67 if path is None: 68 path = location + ".py" 69 SetValue(subkey, "", REG_SZ, path) 70 yield 71 finally: 72 if machinery.WindowsRegistryFinder.DEBUG_BUILD: 73 key = os.path.dirname(key) 74 delete_registry_tree(HKEY_CURRENT_USER, key) 75 76 77@unittest.skipUnless(sys.platform.startswith('win'), 'requires Windows') 78class WindowsRegistryFinderTests: 79 # The module name is process-specific, allowing for 80 # simultaneous runs of the same test on a single machine. 81 test_module = "spamham{}".format(os.getpid()) 82 83 def test_find_spec_missing(self): 84 spec = self.machinery.WindowsRegistryFinder.find_spec('spam') 85 self.assertIs(spec, None) 86 87 def test_find_module_missing(self): 88 with warnings.catch_warnings(): 89 warnings.simplefilter("ignore", DeprecationWarning) 90 loader = self.machinery.WindowsRegistryFinder.find_module('spam') 91 self.assertIs(loader, None) 92 93 def test_module_found(self): 94 with setup_module(self.machinery, self.test_module): 95 with warnings.catch_warnings(): 96 warnings.simplefilter("ignore", DeprecationWarning) 97 loader = self.machinery.WindowsRegistryFinder.find_module(self.test_module) 98 spec = self.machinery.WindowsRegistryFinder.find_spec(self.test_module) 99 self.assertIsNot(loader, None) 100 self.assertIsNot(spec, None) 101 102 def test_module_not_found(self): 103 with setup_module(self.machinery, self.test_module, path="."): 104 with warnings.catch_warnings(): 105 warnings.simplefilter("ignore", DeprecationWarning) 106 loader = self.machinery.WindowsRegistryFinder.find_module(self.test_module) 107 spec = self.machinery.WindowsRegistryFinder.find_spec(self.test_module) 108 self.assertIsNone(loader) 109 self.assertIsNone(spec) 110 111(Frozen_WindowsRegistryFinderTests, 112 Source_WindowsRegistryFinderTests 113 ) = test_util.test_both(WindowsRegistryFinderTests, machinery=machinery) 114 115@unittest.skipUnless(sys.platform.startswith('win'), 'requires Windows') 116class WindowsExtensionSuffixTests: 117 def test_tagged_suffix(self): 118 suffixes = self.machinery.EXTENSION_SUFFIXES 119 expected_tag = ".cp{0.major}{0.minor}-{1}.pyd".format(sys.version_info, 120 re.sub('[^a-zA-Z0-9]', '_', get_platform())) 121 try: 122 untagged_i = suffixes.index(".pyd") 123 except ValueError: 124 untagged_i = suffixes.index("_d.pyd") 125 expected_tag = "_d" + expected_tag 126 127 self.assertIn(expected_tag, suffixes) 128 129 # Ensure the tags are in the correct order. 130 tagged_i = suffixes.index(expected_tag) 131 self.assertLess(tagged_i, untagged_i) 132 133(Frozen_WindowsExtensionSuffixTests, 134 Source_WindowsExtensionSuffixTests 135 ) = test_util.test_both(WindowsExtensionSuffixTests, machinery=machinery) 136 137 138@unittest.skipUnless(sys.platform.startswith('win'), 'requires Windows') 139class WindowsBootstrapPathTests(unittest.TestCase): 140 def check_join(self, expected, *inputs): 141 from importlib._bootstrap_external import _path_join 142 actual = _path_join(*inputs) 143 if expected.casefold() == actual.casefold(): 144 return 145 self.assertEqual(expected, actual) 146 147 def test_path_join(self): 148 self.check_join(r"C:\A\B", "C:\\", "A", "B") 149 self.check_join(r"C:\A\B", "D:\\", "D", "C:\\", "A", "B") 150 self.check_join(r"C:\A\B", "C:\\", "A", "C:B") 151 self.check_join(r"C:\A\B", "C:\\", "A\\B") 152 self.check_join(r"C:\A\B", r"C:\A\B") 153 154 self.check_join("D:A", r"D:", "A") 155 self.check_join("D:A", r"C:\B\C", "D:", "A") 156 self.check_join("D:A", r"C:\B\C", r"D:A") 157 158 self.check_join(r"A\B\C", "A", "B", "C") 159 self.check_join(r"A\B\C", "A", r"B\C") 160 self.check_join(r"A\B/C", "A", "B/C") 161 self.check_join(r"A\B\C", "A/", "B\\", "C") 162 163 # Dots are not normalised by this function 164 self.check_join(r"A\../C", "A", "../C") 165 self.check_join(r"A.\.\B", "A.", ".", "B") 166 167 self.check_join(r"\\Server\Share\A\B\C", r"\\Server\Share", "A", "B", "C") 168 self.check_join(r"\\Server\Share\A\B\C", r"\\Server\Share", "D", r"\A", "B", "C") 169 self.check_join(r"\\Server\Share\A\B\C", r"\\Server2\Share2", "D", 170 r"\\Server\Share", "A", "B", "C") 171 self.check_join(r"\\Server\Share\A\B\C", r"\\Server", r"\Share", "A", "B", "C") 172 self.check_join(r"\\Server\Share", r"\\Server\Share") 173 self.check_join(r"\\Server\Share\\", r"\\Server\Share\\") 174 175 # Handle edge cases with empty segments 176 self.check_join("C:\\A", "C:/A", "") 177 self.check_join("C:\\", "C:/", "") 178 self.check_join("C:", "C:", "") 179 self.check_join("//Server/Share\\", "//Server/Share/", "") 180 self.check_join("//Server/Share\\", "//Server/Share", "") 181