test_msvccompiler.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. """Tests for distutils._msvccompiler."""
  2. import sys
  3. import unittest
  4. import os
  5. import threading
  6. from distutils.errors import DistutilsPlatformError
  7. from distutils.tests import support
  8. from test.support import run_unittest
  9. SKIP_MESSAGE = (None if sys.platform == "win32" else
  10. "These tests are only for win32")
  11. @unittest.skipUnless(SKIP_MESSAGE is None, SKIP_MESSAGE)
  12. class msvccompilerTestCase(support.TempdirManager,
  13. unittest.TestCase):
  14. def test_no_compiler(self):
  15. import distutils._msvccompiler as _msvccompiler
  16. # makes sure query_vcvarsall raises
  17. # a DistutilsPlatformError if the compiler
  18. # is not found
  19. def _find_vcvarsall(plat_spec):
  20. return None, None
  21. old_find_vcvarsall = _msvccompiler._find_vcvarsall
  22. _msvccompiler._find_vcvarsall = _find_vcvarsall
  23. try:
  24. self.assertRaises(DistutilsPlatformError,
  25. _msvccompiler._get_vc_env,
  26. 'wont find this version')
  27. finally:
  28. _msvccompiler._find_vcvarsall = old_find_vcvarsall
  29. def test_get_vc_env_unicode(self):
  30. import distutils._msvccompiler as _msvccompiler
  31. test_var = 'ṰḖṤṪ┅ṼẨṜ'
  32. test_value = '₃⁴₅'
  33. # Ensure we don't early exit from _get_vc_env
  34. old_distutils_use_sdk = os.environ.pop('DISTUTILS_USE_SDK', None)
  35. os.environ[test_var] = test_value
  36. try:
  37. env = _msvccompiler._get_vc_env('x86')
  38. self.assertIn(test_var.lower(), env)
  39. self.assertEqual(test_value, env[test_var.lower()])
  40. finally:
  41. os.environ.pop(test_var)
  42. if old_distutils_use_sdk:
  43. os.environ['DISTUTILS_USE_SDK'] = old_distutils_use_sdk
  44. def test_get_vc2017(self):
  45. import distutils._msvccompiler as _msvccompiler
  46. # This function cannot be mocked, so pass it if we find VS 2017
  47. # and mark it skipped if we do not.
  48. version, path = _msvccompiler._find_vc2017()
  49. if version:
  50. self.assertGreaterEqual(version, 15)
  51. self.assertTrue(os.path.isdir(path))
  52. else:
  53. raise unittest.SkipTest("VS 2017 is not installed")
  54. def test_get_vc2015(self):
  55. import distutils._msvccompiler as _msvccompiler
  56. # This function cannot be mocked, so pass it if we find VS 2015
  57. # and mark it skipped if we do not.
  58. version, path = _msvccompiler._find_vc2015()
  59. if version:
  60. self.assertGreaterEqual(version, 14)
  61. self.assertTrue(os.path.isdir(path))
  62. else:
  63. raise unittest.SkipTest("VS 2015 is not installed")
  64. class CheckThread(threading.Thread):
  65. exc_info = None
  66. def run(self):
  67. try:
  68. super().run()
  69. except Exception:
  70. self.exc_info = sys.exc_info()
  71. def __bool__(self):
  72. return not self.exc_info
  73. class TestSpawn(unittest.TestCase):
  74. def test_concurrent_safe(self):
  75. """
  76. Concurrent calls to spawn should have consistent results.
  77. """
  78. import distutils._msvccompiler as _msvccompiler
  79. compiler = _msvccompiler.MSVCCompiler()
  80. compiler._paths = "expected"
  81. inner_cmd = 'import os; assert os.environ["PATH"] == "expected"'
  82. command = ['python', '-c', inner_cmd]
  83. threads = [
  84. CheckThread(target=compiler.spawn, args=[command])
  85. for n in range(100)
  86. ]
  87. for thread in threads:
  88. thread.start()
  89. for thread in threads:
  90. thread.join()
  91. assert all(threads)
  92. def test_concurrent_safe_fallback(self):
  93. """
  94. If CCompiler.spawn has been monkey-patched without support
  95. for an env, it should still execute.
  96. """
  97. import distutils._msvccompiler as _msvccompiler
  98. from distutils import ccompiler
  99. compiler = _msvccompiler.MSVCCompiler()
  100. compiler._paths = "expected"
  101. def CCompiler_spawn(self, cmd):
  102. "A spawn without an env argument."
  103. assert os.environ["PATH"] == "expected"
  104. with unittest.mock.patch.object(
  105. ccompiler.CCompiler, 'spawn', CCompiler_spawn):
  106. compiler.spawn(["n/a"])
  107. assert os.environ.get("PATH") != "expected"
  108. def test_suite():
  109. return unittest.makeSuite(msvccompilerTestCase)
  110. if __name__ == "__main__":
  111. run_unittest(test_suite())