• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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