|
| 1 | +from os import environ |
1 | 2 | from pathlib import Path |
2 | 3 | from sys import version_info |
| 4 | +from unittest.mock import patch |
3 | 5 |
|
4 | 6 | import pytest |
5 | 7 | from pydantic import ValidationError |
@@ -54,3 +56,115 @@ def test_platform_toolchain_override(self): |
54 | 56 | assert "clang" in hatch_build_config.platform.cc |
55 | 57 | assert "clang++" in hatch_build_config.platform.cxx |
56 | 58 | assert hatch_build_config.platform.toolchain == "gcc" |
| 59 | + |
| 60 | + def test_cmake_args_env_variable(self): |
| 61 | + """Test that CMAKE_ARGS environment variable is respected.""" |
| 62 | + txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text() |
| 63 | + toml_data = loads(txt) |
| 64 | + hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"]) |
| 65 | + hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump()) |
| 66 | + |
| 67 | + with patch.dict(environ, {"CMAKE_ARGS": "-DFOO=bar -DBAZ=qux"}): |
| 68 | + hatch_build_plan.generate() |
| 69 | + assert "-DFOO=bar" in hatch_build_plan.commands[0] |
| 70 | + assert "-DBAZ=qux" in hatch_build_plan.commands[0] |
| 71 | + |
| 72 | + def test_cmake_args_env_variable_empty(self): |
| 73 | + """Test that an empty CMAKE_ARGS does not add extra whitespace.""" |
| 74 | + txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text() |
| 75 | + toml_data = loads(txt) |
| 76 | + hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"]) |
| 77 | + hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump()) |
| 78 | + |
| 79 | + with patch.dict(environ, {"CMAKE_ARGS": ""}): |
| 80 | + hatch_build_plan.generate() |
| 81 | + # Should not have trailing whitespace from empty CMAKE_ARGS |
| 82 | + assert not hatch_build_plan.commands[0].endswith(" ") |
| 83 | + |
| 84 | + def test_cmake_generator_env_variable(self): |
| 85 | + """Test that CMAKE_GENERATOR environment variable is respected on non-Windows platforms.""" |
| 86 | + txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text() |
| 87 | + toml_data = loads(txt) |
| 88 | + hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"]) |
| 89 | + hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump()) |
| 90 | + |
| 91 | + with patch.dict(environ, {"CMAKE_GENERATOR": "Ninja"}): |
| 92 | + hatch_build_plan.generate() |
| 93 | + assert '-G "Ninja"' in hatch_build_plan.commands[0] |
| 94 | + |
| 95 | + def test_cmake_generator_env_variable_unset(self): |
| 96 | + """Test that no -G flag is added on non-Windows when CMAKE_GENERATOR is not set.""" |
| 97 | + txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text() |
| 98 | + toml_data = loads(txt) |
| 99 | + hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"]) |
| 100 | + hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump()) |
| 101 | + |
| 102 | + with patch.dict(environ, {}, clear=False): |
| 103 | + # Remove CMAKE_GENERATOR if present |
| 104 | + environ.pop("CMAKE_GENERATOR", None) |
| 105 | + hatch_build_plan.generate() |
| 106 | + if hatch_build_plan.platform.platform != "win32": |
| 107 | + assert "-G " not in hatch_build_plan.commands[0] |
| 108 | + |
| 109 | + def test_hatch_cpp_cmake_env_force_off(self): |
| 110 | + """Test that HATCH_CPP_CMAKE=0 disables cmake even when cmake config is present.""" |
| 111 | + txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text() |
| 112 | + toml_data = loads(txt) |
| 113 | + hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"]) |
| 114 | + hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump()) |
| 115 | + |
| 116 | + assert hatch_build_plan.cmake is not None |
| 117 | + with patch.dict(environ, {"HATCH_CPP_CMAKE": "0"}): |
| 118 | + hatch_build_plan.generate() |
| 119 | + # cmake should not be active, so no cmake commands generated |
| 120 | + assert len(hatch_build_plan.commands) == 0 |
| 121 | + assert "cmake" not in hatch_build_plan._active_toolchains |
| 122 | + |
| 123 | + def test_hatch_cpp_cmake_env_force_on(self): |
| 124 | + """Test that HATCH_CPP_CMAKE=1 enables cmake when cmake config is present.""" |
| 125 | + txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text() |
| 126 | + toml_data = loads(txt) |
| 127 | + hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"]) |
| 128 | + hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump()) |
| 129 | + |
| 130 | + assert hatch_build_plan.cmake is not None |
| 131 | + with patch.dict(environ, {"HATCH_CPP_CMAKE": "1"}): |
| 132 | + hatch_build_plan.generate() |
| 133 | + assert "cmake" in hatch_build_plan._active_toolchains |
| 134 | + |
| 135 | + def test_hatch_cpp_cmake_env_force_on_no_config(self): |
| 136 | + """Test that HATCH_CPP_CMAKE=1 warns and skips when no cmake config exists.""" |
| 137 | + txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text() |
| 138 | + toml_data = loads(txt) |
| 139 | + config_data = toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"].copy() |
| 140 | + config_data.pop("cmake", None) |
| 141 | + hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **config_data) |
| 142 | + hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump()) |
| 143 | + |
| 144 | + assert hatch_build_plan.cmake is None |
| 145 | + with patch.dict(environ, {"HATCH_CPP_CMAKE": "1"}): |
| 146 | + hatch_build_plan.generate() |
| 147 | + # cmake should NOT be activated when there's no config |
| 148 | + assert "cmake" not in hatch_build_plan._active_toolchains |
| 149 | + |
| 150 | + def test_hatch_cpp_vcpkg_env_force_off(self): |
| 151 | + """Test that HATCH_CPP_VCPKG=0 disables vcpkg even when vcpkg.json exists.""" |
| 152 | + txt = (Path(__file__).parent / "test_project_cmake_vcpkg" / "pyproject.toml").read_text() |
| 153 | + toml_data = loads(txt) |
| 154 | + hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"]) |
| 155 | + hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump()) |
| 156 | + |
| 157 | + with patch.dict(environ, {"HATCH_CPP_VCPKG": "0"}): |
| 158 | + hatch_build_plan.generate() |
| 159 | + assert "vcpkg" not in hatch_build_plan._active_toolchains |
| 160 | + |
| 161 | + def test_hatch_cpp_vcpkg_env_force_on(self): |
| 162 | + """Test that HATCH_CPP_VCPKG=1 enables vcpkg even when vcpkg.json doesn't exist.""" |
| 163 | + txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text() |
| 164 | + toml_data = loads(txt) |
| 165 | + hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"]) |
| 166 | + hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump()) |
| 167 | + |
| 168 | + with patch.dict(environ, {"HATCH_CPP_VCPKG": "1"}): |
| 169 | + hatch_build_plan.generate() |
| 170 | + assert "vcpkg" in hatch_build_plan._active_toolchains |
0 commit comments