|
1 | 1 | # type: ignore |
| 2 | +import io |
2 | 3 | import json |
3 | 4 | import os |
4 | 5 | import zipfile |
@@ -328,6 +329,57 @@ def test_include_file_extensions( |
328 | 329 | "Binary file content was corrupted during packing" |
329 | 330 | ) |
330 | 331 |
|
| 332 | + def test_include_wheel_file_not_corrupted( |
| 333 | + self, |
| 334 | + runner: CliRunner, |
| 335 | + temp_dir: str, |
| 336 | + project_details: ProjectDetails, |
| 337 | + ) -> None: |
| 338 | + """Test that .whl files included via packOptions are packed byte-for-byte. |
| 339 | +
|
| 340 | + A .whl file is itself a zip archive full of arbitrary binary bytes. If it |
| 341 | + is not recognized as binary by the packager, it gets round-tripped through |
| 342 | + a text decode/encode (latin-1 -> UTF-8), which corrupts any byte >= 0x80 |
| 343 | + and produces an invalid zip file at runtime. |
| 344 | + """ |
| 345 | + wheel_file_name = "example_pkg-1.0.0-py3-none-any.whl" |
| 346 | + |
| 347 | + # Minimal valid zip (wheel) content, deliberately containing high bytes |
| 348 | + # (0x80-0xff) that would be mangled by a latin-1 -> UTF-8 round trip. |
| 349 | + buf = io.BytesIO() |
| 350 | + with zipfile.ZipFile(buf, "w") as wheel_zip: |
| 351 | + wheel_zip.writestr("example_pkg/__init__.py", bytes(range(256)) * 4) |
| 352 | + wheel_bytes = buf.getvalue() |
| 353 | + |
| 354 | + pack_options = {"fileExtensionsIncluded": [".whl"]} |
| 355 | + |
| 356 | + with runner.isolated_filesystem(temp_dir=temp_dir): |
| 357 | + with open("uipath.json", "w") as f: |
| 358 | + json.dump(create_uipath_json(pack_options=pack_options), f) |
| 359 | + with open("pyproject.toml", "w") as f: |
| 360 | + f.write(project_details.to_toml()) |
| 361 | + with open("main.py", "w") as f: |
| 362 | + f.write("def main(input): return input") |
| 363 | + with open(wheel_file_name, "wb") as f: |
| 364 | + f.write(wheel_bytes) |
| 365 | + |
| 366 | + with patch("uipath._cli.cli_init.Middlewares.next") as mock_middleware: |
| 367 | + mock_middleware.return_value = MiddlewareResult(should_continue=True) |
| 368 | + init_result = runner.invoke(cli, ["init"], env={}) |
| 369 | + assert init_result.exit_code == 0 |
| 370 | + |
| 371 | + result = runner.invoke(cli, ["pack", "./"], env={}) |
| 372 | + |
| 373 | + assert result.exit_code == 0 |
| 374 | + with zipfile.ZipFile( |
| 375 | + f".uipath/{project_details.name}.{project_details.version}.nupkg", "r" |
| 376 | + ) as z: |
| 377 | + assert f"content/{wheel_file_name}" in z.namelist() |
| 378 | + extracted_wheel_bytes = z.read(f"content/{wheel_file_name}") |
| 379 | + assert extracted_wheel_bytes == wheel_bytes, ( |
| 380 | + ".whl file content was corrupted during packing" |
| 381 | + ) |
| 382 | + |
331 | 383 | def test_include_files( |
332 | 384 | self, |
333 | 385 | runner: CliRunner, |
|
0 commit comments