|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | 3 | import json |
| 4 | +import subprocess |
| 5 | +import sys |
| 6 | +from sys import executable as python_interpreter |
4 | 7 | from typing import TYPE_CHECKING |
5 | 8 |
|
6 | 9 | import pytest |
7 | 10 | import tomlkit |
8 | 11 |
|
| 12 | +import semantic_release |
9 | 13 | from semantic_release.cli.config import RawConfig |
10 | 14 |
|
11 | 15 | from tests.const import GENERATE_CONFIG_SUBCMD, MAIN_PROG_NAME, VERSION_SUBCMD |
|
19 | 23 | from tests.conftest import RunCliFn |
20 | 24 | from tests.fixtures.example_project import ExProjectDir |
21 | 25 |
|
| 26 | +# Constant |
| 27 | +NULL_BYTE = b"\x00" |
| 28 | + |
22 | 29 |
|
23 | 30 | @pytest.fixture |
24 | 31 | def raw_config_dict() -> dict[str, Any]: |
@@ -157,3 +164,74 @@ def test_generate_config_pyproject_toml( |
157 | 164 | # Evaluate: Check that the version command in noop mode ran successfully |
158 | 165 | # which means PSR loaded the configuration successfully |
159 | 166 | assert_successful_exit_code(result, cli_cmd) |
| 167 | + |
| 168 | + |
| 169 | +@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific encoding check") |
| 170 | +@pytest.mark.parametrize( |
| 171 | + "console_executable", |
| 172 | + ( |
| 173 | + "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", |
| 174 | + # "C:\\Windows\\System32\\cmd.exe", # CMD.exe does not support specifying encoding for output |
| 175 | + ), |
| 176 | +) |
| 177 | +@pytest.mark.usefixtures(repo_w_no_tags_conventional_commits.__name__) |
| 178 | +def test_generate_config_toml_utf8_bytes_windows( |
| 179 | + console_executable: str, |
| 180 | + example_project_dir: ExProjectDir, |
| 181 | + run_cli: RunCliFn, |
| 182 | +) -> None: |
| 183 | + """ |
| 184 | + Given an example project directory |
| 185 | + When generating a TOML configuration file via Powershell redirection |
| 186 | + Then the emitted file contains only UTF-8 bytes and no NUL bytes |
| 187 | + """ |
| 188 | + if "powershell.exe" not in console_executable.lower(): |
| 189 | + pytest.skip("Only PowerShell is currently supported for this test") |
| 190 | + |
| 191 | + output_file = example_project_dir / "releaserc.toml" |
| 192 | + psr_cmd = [ |
| 193 | + python_interpreter, |
| 194 | + "-m", |
| 195 | + semantic_release.__name__, |
| 196 | + GENERATE_CONFIG_SUBCMD, |
| 197 | + "-f", |
| 198 | + "toml", |
| 199 | + ] |
| 200 | + |
| 201 | + redirection_cmd = ( |
| 202 | + f"{str.join(' ', psr_cmd)} | Out-File -Encoding utf8 {output_file}" |
| 203 | + ) |
| 204 | + |
| 205 | + # Act: Generate the config file via subprocess call to PowerShell |
| 206 | + proc = subprocess.run( # noqa: S602, not a security concern in testing & required for redirection |
| 207 | + redirection_cmd, |
| 208 | + executable=console_executable, |
| 209 | + shell=True, |
| 210 | + stdin=None, |
| 211 | + capture_output=True, |
| 212 | + check=True, |
| 213 | + ) |
| 214 | + |
| 215 | + config_as_bytes = output_file.read_bytes() |
| 216 | + assert config_as_bytes, "Generated config file is empty!" |
| 217 | + assert ( |
| 218 | + NULL_BYTE not in config_as_bytes |
| 219 | + ), f"Generated config file '{output_file}' contains NUL bytes!" |
| 220 | + assert not proc.stderr |
| 221 | + assert not proc.stdout |
| 222 | + |
| 223 | + # Act: Validate that the generated config is a valid configuration for PSR |
| 224 | + cli_cmd = [ |
| 225 | + MAIN_PROG_NAME, |
| 226 | + "--noop", |
| 227 | + "--strict", |
| 228 | + "-c", |
| 229 | + str(output_file), |
| 230 | + VERSION_SUBCMD, |
| 231 | + "--print", |
| 232 | + ] |
| 233 | + result = run_cli(cli_cmd[1:]) |
| 234 | + |
| 235 | + # Evaluate: Check that the version command in noop mode ran successfully |
| 236 | + # which means PSR loaded the configuration successfully |
| 237 | + assert_successful_exit_code(result, cli_cmd) |
0 commit comments