codekingpro/portable-devtools
114k
1import os2import sys3import sysconfig4import threading5import unittest.mock as mock6from distutils.errors import DistutilsPlatformError7from distutils.tests import support8from distutils.util import get_platform9 10import pytest11 12from .. import msvc13 14needs_winreg = pytest.mark.skipif('not hasattr(msvc, "winreg")')15 16 17class Testmsvccompiler(support.TempdirManager):18 def test_no_compiler(self, monkeypatch):19 # makes sure query_vcvarsall raises20 # a DistutilsPlatformError if the compiler21 # is not found22 def _find_vcvarsall(plat_spec):23 return None, None24 25 monkeypatch.setattr(msvc, '_find_vcvarsall', _find_vcvarsall)26 27 with pytest.raises(DistutilsPlatformError):28 msvc._get_vc_env(29 'wont find this version',30 )31 32 @pytest.mark.skipif(33 not sysconfig.get_platform().startswith("win"),34 reason="Only run test for non-mingw Windows platforms",35 )36 @pytest.mark.parametrize(37 "plat_name, expected",38 [39 ("win-arm64", "win-arm64"),40 ("win-amd64", "win-amd64"),41 (None, get_platform()),42 ],43 )44 def test_cross_platform_compilation_paths(self, monkeypatch, plat_name, expected):45 """46 Ensure a specified target platform is passed to _get_vcvars_spec.47 """48 compiler = msvc.Compiler()49 50 def _get_vcvars_spec(host_platform, platform):51 assert platform == expected52 53 monkeypatch.setattr(msvc, '_get_vcvars_spec', _get_vcvars_spec)54 compiler.initialize(plat_name)55 56 @needs_winreg57 def test_get_vc_env_unicode(self):58 test_var = 'ṰḖṤṪ┅ṼẨṜ'59 test_value = '₃⁴₅'60 61 # Ensure we don't early exit from _get_vc_env62 old_distutils_use_sdk = os.environ.pop('DISTUTILS_USE_SDK', None)63 os.environ[test_var] = test_value64 try:65 env = msvc._get_vc_env('x86')66 assert test_var.lower() in env67 assert test_value == env[test_var.lower()]68 finally:69 os.environ.pop(test_var)70 if old_distutils_use_sdk:71 os.environ['DISTUTILS_USE_SDK'] = old_distutils_use_sdk72 73 @needs_winreg74 @pytest.mark.parametrize('ver', (2015, 2017))75 def test_get_vc(self, ver):76 # This function cannot be mocked, so pass if VC is found77 # and skip otherwise.78 lookup = getattr(msvc, f'_find_vc{ver}')79 expected_version = {2015: 14, 2017: 15}[ver]80 version, path = lookup()81 if not version:82 pytest.skip(f"VS {ver} is not installed")83 assert version >= expected_version84 assert os.path.isdir(path)85 86 87class CheckThread(threading.Thread):88 exc_info = None89 90 def run(self):91 try:92 super().run()93 except Exception:94 self.exc_info = sys.exc_info()95 96 def __bool__(self):97 return not self.exc_info98 99 100class TestSpawn:101 def test_concurrent_safe(self):102 """103 Concurrent calls to spawn should have consistent results.104 """105 compiler = msvc.Compiler()106 compiler._paths = "expected"107 inner_cmd = 'import os; assert os.environ["PATH"] == "expected"'108 command = [sys.executable, '-c', inner_cmd]109 110 threads = [111 CheckThread(target=compiler.spawn, args=[command]) for n in range(100)112 ]113 for thread in threads:114 thread.start()115 for thread in threads:116 thread.join()117 assert all(threads)118 119 def test_concurrent_safe_fallback(self):120 """121 If CCompiler.spawn has been monkey-patched without support122 for an env, it should still execute.123 """124 from distutils import ccompiler125 126 compiler = msvc.Compiler()127 compiler._paths = "expected"128 129 def CCompiler_spawn(self, cmd):130 "A spawn without an env argument."131 assert os.environ["PATH"] == "expected"132 133 with mock.patch.object(ccompiler.CCompiler, 'spawn', CCompiler_spawn):134 compiler.spawn(["n/a"])135 136 assert os.environ.get("PATH") != "expected"137 