From 05dfef7ed54dba0f858115be441febc94b79010a Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 31 Dec 2014 14:45:33 -0500 Subject: Rewrite assert --- setuptools/tests/test_msvc9compiler.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'setuptools/tests/test_msvc9compiler.py') diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py index 970f7679..8567aa58 100644 --- a/setuptools/tests/test_msvc9compiler.py +++ b/setuptools/tests/test_msvc9compiler.py @@ -7,12 +7,13 @@ finds the Visual C++ for Python package. import os import shutil -import sys import tempfile import unittest import distutils.errors import contextlib +import pytest + # importing only setuptools should apply the patch __import__('setuptools') @@ -93,11 +94,8 @@ class TestMSVC9Compiler(unittest.TestCase): # skip return - self.assertEqual( - "setuptools.msvc9_support", - distutils.msvc9compiler.find_vcvarsall.__module__, - "find_vcvarsall was not patched" - ) + mod_name = distutils.msvc9compiler.find_vcvarsall.__module__ + assert mod_name == "setuptools.msvc9_support", "find_vcvarsall unpatched" find_vcvarsall = distutils.msvc9compiler.find_vcvarsall query_vcvarsall = distutils.msvc9compiler.query_vcvarsall @@ -108,12 +106,10 @@ class TestMSVC9Compiler(unittest.TestCase): with MockReg(): self.assertIsNone(find_vcvarsall(9.0)) - try: + expected = distutils.errors.DistutilsPlatformError + with pytest.raises(expected) as exc: query_vcvarsall(9.0) - self.fail('Expected DistutilsPlatformError from query_vcvarsall()') - except distutils.errors.DistutilsPlatformError: - exc_message = str(sys.exc_info()[1]) - self.assertIn('aka.ms/vcpython27', exc_message) + assert 'aka.ms/vcpython27' in str(exc) key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir' key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir' -- cgit v1.2.1 From 04cf504041b38b85c8f2e9ffddda5897b2161e67 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 31 Dec 2014 14:48:52 -0500 Subject: Use pytest importorskip for skip logic --- setuptools/tests/test_msvc9compiler.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'setuptools/tests/test_msvc9compiler.py') diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py index 8567aa58..27747512 100644 --- a/setuptools/tests/test_msvc9compiler.py +++ b/setuptools/tests/test_msvc9compiler.py @@ -17,6 +17,8 @@ import pytest # importing only setuptools should apply the patch __import__('setuptools') +pytest.importorskip("distutils.msvc9compiler") + class MockReg: """Mock for distutils.msvc9compiler.Reg. We patch it with an instance of this class that mocks out the @@ -90,10 +92,6 @@ def patch_env(**replacements): class TestMSVC9Compiler(unittest.TestCase): def test_find_vcvarsall_patch(self): - if not hasattr(distutils, 'msvc9compiler'): - # skip - return - mod_name = distutils.msvc9compiler.find_vcvarsall.__module__ assert mod_name == "setuptools.msvc9_support", "find_vcvarsall unpatched" -- cgit v1.2.1 From 7c075fcc356078930535230fbc975b76db9d68cc Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 2 Jan 2015 10:55:40 -0500 Subject: Extend contexts environment patching logic based on context manager in test_msvc9compiler and use it. --- setuptools/tests/test_msvc9compiler.py | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) (limited to 'setuptools/tests/test_msvc9compiler.py') diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py index 27747512..2a117dc9 100644 --- a/setuptools/tests/test_msvc9compiler.py +++ b/setuptools/tests/test_msvc9compiler.py @@ -10,10 +10,11 @@ import shutil import tempfile import unittest import distutils.errors -import contextlib import pytest +from . import contexts + # importing only setuptools should apply the patch __import__('setuptools') @@ -62,32 +63,6 @@ class MockReg: distutils.msvc9compiler.Reg.read_keys = self.original_read_keys distutils.msvc9compiler.Reg.read_values = self.original_read_values -@contextlib.contextmanager -def patch_env(**replacements): - """ - In a context, patch the environment with replacements. Pass None values - to clear the values. - """ - saved = dict( - (key, os.environ['key']) - for key in replacements - if key in os.environ - ) - - # remove values that are null - remove = (key for (key, value) in replacements.items() if value is None) - for key in list(remove): - os.environ.pop(key, None) - replacements.pop(key) - - os.environ.update(replacements) - - try: - yield saved - finally: - for key in replacements: - os.environ.pop(key, None) - os.environ.update(saved) class TestMSVC9Compiler(unittest.TestCase): @@ -100,7 +75,7 @@ class TestMSVC9Compiler(unittest.TestCase): # No registry entries or environment variable means we should # not find anything - with patch_env(VS90COMNTOOLS=None): + with contexts.environment(VS90COMNTOOLS=None): with MockReg(): self.assertIsNone(find_vcvarsall(9.0)) -- cgit v1.2.1 From 398440e9a878ed9a6dbd8843151bc08e4ba5059a Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 2 Jan 2015 13:24:45 -0500 Subject: Remove unittest dependency from test_msvc9compiler. --- setuptools/tests/test_msvc9compiler.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'setuptools/tests/test_msvc9compiler.py') diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py index 2a117dc9..a1637941 100644 --- a/setuptools/tests/test_msvc9compiler.py +++ b/setuptools/tests/test_msvc9compiler.py @@ -8,7 +8,6 @@ finds the Visual C++ for Python package. import os import shutil import tempfile -import unittest import distutils.errors import pytest @@ -64,7 +63,7 @@ class MockReg: distutils.msvc9compiler.Reg.read_values = self.original_read_values -class TestMSVC9Compiler(unittest.TestCase): +class TestMSVC9Compiler: def test_find_vcvarsall_patch(self): mod_name = distutils.msvc9compiler.find_vcvarsall.__module__ @@ -77,7 +76,7 @@ class TestMSVC9Compiler(unittest.TestCase): # not find anything with contexts.environment(VS90COMNTOOLS=None): with MockReg(): - self.assertIsNone(find_vcvarsall(9.0)) + assert find_vcvarsall(9.0) is None expected = distutils.errors.DistutilsPlatformError with pytest.raises(expected) as exc: @@ -104,11 +103,11 @@ class TestMSVC9Compiler(unittest.TestCase): key_64: mock_installdir_2, } ): - self.assertEqual(mock_vcvarsall_bat_1, find_vcvarsall(9.0)) + assert mock_vcvarsall_bat_1 == find_vcvarsall(9.0) # Ensure we get the local machine value if it's there with MockReg(hkey_local_machine={key_32: mock_installdir_2}): - self.assertEqual(mock_vcvarsall_bat_2, find_vcvarsall(9.0)) + assert mock_vcvarsall_bat_2 == find_vcvarsall(9.0) # Ensure we prefer the 64-bit local machine key # (*not* the Wow6432Node key) @@ -120,7 +119,7 @@ class TestMSVC9Compiler(unittest.TestCase): key_64: mock_installdir_2, } ): - self.assertEqual(mock_vcvarsall_bat_1, find_vcvarsall(9.0)) + assert mock_vcvarsall_bat_1 == find_vcvarsall(9.0) finally: shutil.rmtree(mock_installdir_1) shutil.rmtree(mock_installdir_2) -- cgit v1.2.1 From ed24bfcd1c3b9b7d83e433152c85dd6400edb4e6 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 2 Jan 2015 13:43:18 -0500 Subject: Use mock to patch msvc9compiler.Reg. --- setuptools/tests/test_msvc9compiler.py | 90 +++++++++++++++++----------------- 1 file changed, 44 insertions(+), 46 deletions(-) (limited to 'setuptools/tests/test_msvc9compiler.py') diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py index a1637941..9ed23e38 100644 --- a/setuptools/tests/test_msvc9compiler.py +++ b/setuptools/tests/test_msvc9compiler.py @@ -11,6 +11,7 @@ import tempfile import distutils.errors import pytest +import mock from . import contexts @@ -19,48 +20,41 @@ __import__('setuptools') pytest.importorskip("distutils.msvc9compiler") -class MockReg: - """Mock for distutils.msvc9compiler.Reg. We patch it - with an instance of this class that mocks out the - functions that access the registry. - """ - - def __init__(self, hkey_local_machine={}, hkey_current_user={}): - self.hklm = hkey_local_machine - self.hkcu = hkey_current_user - - def __enter__(self): - self.original_read_keys = distutils.msvc9compiler.Reg.read_keys - self.original_read_values = distutils.msvc9compiler.Reg.read_values - - _winreg = getattr(distutils.msvc9compiler, '_winreg', None) - winreg = getattr(distutils.msvc9compiler, 'winreg', _winreg) - hives = { - winreg.HKEY_CURRENT_USER: self.hkcu, - winreg.HKEY_LOCAL_MACHINE: self.hklm, - } +def mock_reg(hkcu=None, hklm=None): + """ + Return a mock for distutils.msvc9compiler.Reg, patched + to mock out the functions that access the registry. + """ - def read_keys(cls, base, key): - """Return list of registry keys.""" - hive = hives.get(base, {}) - return [k.rpartition('\\')[2] - for k in hive if k.startswith(key.lower())] + _winreg = getattr(distutils.msvc9compiler, '_winreg', None) + winreg = getattr(distutils.msvc9compiler, 'winreg', _winreg) - def read_values(cls, base, key): - """Return dict of registry keys and values.""" - hive = hives.get(base, {}) - return dict((k.rpartition('\\')[2], hive[k]) - for k in hive if k.startswith(key.lower())) + hives = { + winreg.HKEY_CURRENT_USER: hkcu or {}, + winreg.HKEY_LOCAL_MACHINE: hklm or {}, + } - distutils.msvc9compiler.Reg.read_keys = classmethod(read_keys) - distutils.msvc9compiler.Reg.read_values = classmethod(read_values) + @classmethod + def read_keys(cls, base, key): + """Return list of registry keys.""" + hive = hives.get(base, {}) + return [ + k.rpartition('\\')[2] + for k in hive if k.startswith(key.lower()) + ] - return self + @classmethod + def read_values(cls, base, key): + """Return dict of registry keys and values.""" + hive = hives.get(base, {}) + return dict( + (k.rpartition('\\')[2], hive[k]) + for k in hive if k.startswith(key.lower()) + ) - def __exit__(self, exc_type, exc_value, exc_tb): - distutils.msvc9compiler.Reg.read_keys = self.original_read_keys - distutils.msvc9compiler.Reg.read_values = self.original_read_values + return mock.patch.multiple(distutils.msvc9compiler.Reg, + read_keys=read_keys, read_values=read_values) class TestMSVC9Compiler: @@ -75,7 +69,7 @@ class TestMSVC9Compiler: # No registry entries or environment variable means we should # not find anything with contexts.environment(VS90COMNTOOLS=None): - with MockReg(): + with mock_reg(): assert find_vcvarsall(9.0) is None expected = distutils.errors.DistutilsPlatformError @@ -96,29 +90,33 @@ class TestMSVC9Compiler: open(mock_vcvarsall_bat_2, 'w').close() try: # Ensure we get the current user's setting first - with MockReg( - hkey_current_user={key_32: mock_installdir_1}, - hkey_local_machine={ + reg = mock_reg( + hkcu={ + key_32: mock_installdir_1, + }, + hklm={ key_32: mock_installdir_2, key_64: mock_installdir_2, - } - ): + }, + ) + with reg: assert mock_vcvarsall_bat_1 == find_vcvarsall(9.0) # Ensure we get the local machine value if it's there - with MockReg(hkey_local_machine={key_32: mock_installdir_2}): + with mock_reg(hklm={key_32: mock_installdir_2}): assert mock_vcvarsall_bat_2 == find_vcvarsall(9.0) # Ensure we prefer the 64-bit local machine key # (*not* the Wow6432Node key) - with MockReg( - hkey_local_machine={ + reg = mock_reg( + hklm={ # This *should* only exist on 32-bit machines key_32: mock_installdir_1, # This *should* only exist on 64-bit machines key_64: mock_installdir_2, } - ): + ) + with reg: assert mock_vcvarsall_bat_1 == find_vcvarsall(9.0) finally: shutil.rmtree(mock_installdir_1) -- cgit v1.2.1 From fb125b61118422a32af19e8cc88eccd13aed14f8 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 2 Jan 2015 13:46:30 -0500 Subject: Split test into two --- setuptools/tests/test_msvc9compiler.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'setuptools/tests/test_msvc9compiler.py') diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py index 9ed23e38..02790ae7 100644 --- a/setuptools/tests/test_msvc9compiler.py +++ b/setuptools/tests/test_msvc9compiler.py @@ -77,6 +77,8 @@ class TestMSVC9Compiler: query_vcvarsall(9.0) assert 'aka.ms/vcpython27' in str(exc) + def test_find_vcvarsall_patch_2(self): + find_vcvarsall = distutils.msvc9compiler.find_vcvarsall key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir' key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir' -- cgit v1.2.1 From 5485e8bacd95d03f1ee45343a1ae3afec2ecd882 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 2 Jan 2015 13:49:15 -0500 Subject: Split the first test into two more tests. --- setuptools/tests/test_msvc9compiler.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'setuptools/tests/test_msvc9compiler.py') diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py index 02790ae7..fd344678 100644 --- a/setuptools/tests/test_msvc9compiler.py +++ b/setuptools/tests/test_msvc9compiler.py @@ -57,17 +57,21 @@ def mock_reg(hkcu=None, hklm=None): read_keys=read_keys, read_values=read_values) -class TestMSVC9Compiler: +class TestModulePatch: - def test_find_vcvarsall_patch(self): + def test_patched(self): + "Test the module is actually patched" mod_name = distutils.msvc9compiler.find_vcvarsall.__module__ assert mod_name == "setuptools.msvc9_support", "find_vcvarsall unpatched" + def test_no_registry_entryies_means_nothing_found(self): + """ + No registry entries or environment variable should lead to an error + directing the user to download vcpython27. + """ find_vcvarsall = distutils.msvc9compiler.find_vcvarsall query_vcvarsall = distutils.msvc9compiler.query_vcvarsall - # No registry entries or environment variable means we should - # not find anything with contexts.environment(VS90COMNTOOLS=None): with mock_reg(): assert find_vcvarsall(9.0) is None -- cgit v1.2.1 From 2604aac7bb9e9b38546557fc2baaec98057d5740 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 2 Jan 2015 14:22:33 -0500 Subject: Extract three more tests, using fixtures to unify the common aspects. --- setuptools/tests/test_msvc9compiler.py | 124 ++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 41 deletions(-) (limited to 'setuptools/tests/test_msvc9compiler.py') diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py index fd344678..918f8898 100644 --- a/setuptools/tests/test_msvc9compiler.py +++ b/setuptools/tests/test_msvc9compiler.py @@ -6,8 +6,7 @@ finds the Visual C++ for Python package. """ import os -import shutil -import tempfile +import contextlib import distutils.errors import pytest @@ -59,6 +58,9 @@ def mock_reg(hkcu=None, hklm=None): class TestModulePatch: + key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir' + key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir' + def test_patched(self): "Test the module is actually patched" mod_name = distutils.msvc9compiler.find_vcvarsall.__module__ @@ -81,49 +83,89 @@ class TestModulePatch: query_vcvarsall(9.0) assert 'aka.ms/vcpython27' in str(exc) - def test_find_vcvarsall_patch_2(self): - find_vcvarsall = distutils.msvc9compiler.find_vcvarsall - key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir' - key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir' - - # Make two mock files so we can tell whether HCKU entries are - # preferred to HKLM entries. - mock_installdir_1 = tempfile.mkdtemp() - mock_vcvarsall_bat_1 = os.path.join(mock_installdir_1, 'vcvarsall.bat') - open(mock_vcvarsall_bat_1, 'w').close() - mock_installdir_2 = tempfile.mkdtemp() - mock_vcvarsall_bat_2 = os.path.join(mock_installdir_2, 'vcvarsall.bat') - open(mock_vcvarsall_bat_2, 'w').close() - try: - # Ensure we get the current user's setting first + @pytest.yield_fixture + def user_preferred_setting(self): + """ + Set up environment with different install dirs for user vs. system + and yield the user_install_dir for the expected result. + """ + with self.mock_install_dir() as user_install_dir: + with self.mock_install_dir() as system_install_dir: + reg = mock_reg( + hkcu={ + self.key_32: user_install_dir, + }, + hklm={ + self.key_32: system_install_dir, + self.key_64: system_install_dir, + }, + ) + with reg: + yield user_install_dir + + def test_prefer_current_user(self, user_preferred_setting): + """ + Ensure user's settings are preferred. + """ + result = distutils.msvc9compiler.find_vcvarsall(9.0) + assert user_preferred_setting == result + + @pytest.yield_fixture + def local_machine_setting(self): + """ + Set up environment with only the system environment configured. + """ + with self.mock_install_dir() as system_install_dir: reg = mock_reg( - hkcu={ - key_32: mock_installdir_1, - }, hklm={ - key_32: mock_installdir_2, - key_64: mock_installdir_2, + self.key_32: system_install_dir, }, ) with reg: - assert mock_vcvarsall_bat_1 == find_vcvarsall(9.0) + yield system_install_dir - # Ensure we get the local machine value if it's there - with mock_reg(hklm={key_32: mock_installdir_2}): - assert mock_vcvarsall_bat_2 == find_vcvarsall(9.0) + def test_local_machine_recognized(self, local_machine_setting): + """ + Ensure machine setting is honored if user settings are not present. + """ + result = distutils.msvc9compiler.find_vcvarsall(9.0) + assert local_machine_setting == result - # Ensure we prefer the 64-bit local machine key - # (*not* the Wow6432Node key) - reg = mock_reg( - hklm={ - # This *should* only exist on 32-bit machines - key_32: mock_installdir_1, - # This *should* only exist on 64-bit machines - key_64: mock_installdir_2, - } - ) - with reg: - assert mock_vcvarsall_bat_1 == find_vcvarsall(9.0) - finally: - shutil.rmtree(mock_installdir_1) - shutil.rmtree(mock_installdir_2) + @pytest.yield_fixture + def x64_preferred_setting(self): + """ + Set up environment with 64-bit and 32-bit system settings configured + and yield the 64-bit location. + """ + with self.mock_install_dir() as x32_dir: + with self.mock_install_dir() as x64_dir: + reg = mock_reg( + hklm={ + # This *should* only exist on 32-bit machines + self.key_32: x32_dir, + # This *should* only exist on 64-bit machines + self.key_64: x64_dir, + }, + ) + with reg: + yield x64_dir + + def test_ensure_64_bit_preferred(self, x64_preferred_setting): + """ + Ensure 64-bit system key is preferred. + """ + result = distutils.msvc9compiler.find_vcvarsall(9.0) + assert x64_preferred_setting == result + + @staticmethod + @contextlib.contextmanager + def mock_install_dir(): + """ + Make a mock install dir in a unique location so that tests can + distinguish which dir was detected in a given scenario. + """ + with contexts.tempdir() as result: + vcvarsall = os.path.join(result, 'vcvarsall.bat') + with open(vcvarsall, 'w'): + pass + yield -- cgit v1.2.1 From 91754ae31f631bb8bf4e9717799730be07a6331b Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 2 Jan 2015 14:25:21 -0500 Subject: Move docstring to test class. --- setuptools/tests/test_msvc9compiler.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'setuptools/tests/test_msvc9compiler.py') diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py index 918f8898..a0820fff 100644 --- a/setuptools/tests/test_msvc9compiler.py +++ b/setuptools/tests/test_msvc9compiler.py @@ -1,8 +1,5 @@ -"""msvc9compiler monkey patch test - -This test ensures that importing setuptools is sufficient to replace -the standard find_vcvarsall function with our patched version that -finds the Visual C++ for Python package. +""" +Tests for msvc9compiler. """ import os @@ -57,6 +54,11 @@ def mock_reg(hkcu=None, hklm=None): class TestModulePatch: + """ + Ensure that importing setuptools is sufficient to replace + the standard find_vcvarsall function with a version that + recognizes the "Visual C++ for Python" package. + """ key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir' key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir' -- cgit v1.2.1