Files
pdf2cad/tests/test_dwg_converter.py
2026-03-03 21:24:02 +00:00

257 lines
9.9 KiB
Python

"""Tests for DWG converter module."""
import subprocess
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, patch
from pdf2imos.output.dwg_converter import (
convert_dxf_to_dwg,
is_oda_converter_available,
)
class TestIsOdaConverterAvailable:
"""Tests for is_oda_converter_available function."""
def test_returns_bool(self):
"""Test that function returns a boolean."""
result = is_oda_converter_available()
assert isinstance(result, bool)
@patch("pdf2imos.output.dwg_converter.shutil.which")
def test_returns_true_when_found(self, mock_which):
"""Test returns True when ODAFileConverter found in PATH."""
mock_which.return_value = "/usr/bin/ODAFileConverter"
assert is_oda_converter_available() is True
mock_which.assert_called_once_with("ODAFileConverter")
@patch("pdf2imos.output.dwg_converter.shutil.which")
def test_returns_false_when_not_found(self, mock_which):
"""Test returns False when ODAFileConverter not in PATH."""
mock_which.return_value = None
assert is_oda_converter_available() is False
mock_which.assert_called_once_with("ODAFileConverter")
class TestConvertDxfToDwg:
"""Tests for convert_dxf_to_dwg function."""
def test_returns_none_when_converter_not_available(self):
"""Test returns None when ODAFileConverter not available."""
with patch(
"pdf2imos.output.dwg_converter.is_oda_converter_available",
return_value=False,
):
with tempfile.TemporaryDirectory() as tmpdir:
dxf_path = Path(tmpdir) / "test.dxf"
dwg_path = Path(tmpdir) / "test.dwg"
dxf_path.write_text("dummy dxf content")
result = convert_dxf_to_dwg(dxf_path, dwg_path)
assert result is None
assert not dwg_path.exists()
@patch("pdf2imos.output.dwg_converter.subprocess.run")
@patch("pdf2imos.output.dwg_converter.is_oda_converter_available")
def test_constructs_correct_subprocess_command(
self, mock_available, mock_run
):
"""Test that correct subprocess command is constructed."""
mock_available.return_value = True
mock_run.return_value = MagicMock(returncode=0)
with tempfile.TemporaryDirectory() as tmpdir:
dxf_path = Path(tmpdir) / "test.dxf"
dwg_path = Path(tmpdir) / "output" / "test.dwg"
dxf_path.write_text("dummy dxf content")
with patch(
"pdf2imos.output.dwg_converter.shutil.copy2"
) as mock_copy:
# Mock copy2 to create the expected output file
def copy_side_effect(src, dst):
if str(src).endswith(".dxf"):
Path(dst).write_text("dummy dxf")
elif str(src).endswith(".dwg"):
Path(dst).write_text("dummy dwg")
mock_copy.side_effect = copy_side_effect
# Create a mock temp directory structure
with patch("tempfile.TemporaryDirectory") as mock_temp:
temp_input = Path(tmpdir) / "temp_input"
temp_output = Path(tmpdir) / "temp_output"
temp_input.mkdir()
temp_output.mkdir()
# Create the expected output file
(temp_output / "test.dwg").write_text("dummy dwg")
mock_temp.return_value.__enter__.side_effect = [
str(temp_input),
str(temp_output),
]
convert_dxf_to_dwg(dxf_path, dwg_path)
# Verify subprocess.run was called with correct command
assert mock_run.called
call_args = mock_run.call_args
cmd = call_args[0][0]
assert cmd[0] == "ODAFileConverter"
assert cmd[3] == "ACAD2018"
assert cmd[4] == "DWG"
assert cmd[5] == "0"
assert cmd[6] == "1"
@patch("pdf2imos.output.dwg_converter.subprocess.run")
@patch("pdf2imos.output.dwg_converter.is_oda_converter_available")
def test_returns_none_on_subprocess_failure(
self, mock_available, mock_run
):
"""Test returns None when subprocess returns non-zero exit code."""
mock_available.return_value = True
mock_run.return_value = MagicMock(
returncode=1, stderr="Conversion failed"
)
with tempfile.TemporaryDirectory() as tmpdir:
dxf_path = Path(tmpdir) / "test.dxf"
dwg_path = Path(tmpdir) / "test.dwg"
dxf_path.write_text("dummy dxf content")
result = convert_dxf_to_dwg(dxf_path, dwg_path)
assert result is None
@patch("pdf2imos.output.dwg_converter.subprocess.run")
@patch("pdf2imos.output.dwg_converter.is_oda_converter_available")
def test_returns_none_on_timeout(self, mock_available, mock_run):
"""Test returns None when subprocess times out."""
mock_available.return_value = True
mock_run.side_effect = subprocess.TimeoutExpired("cmd", 30)
with tempfile.TemporaryDirectory() as tmpdir:
dxf_path = Path(tmpdir) / "test.dxf"
dwg_path = Path(tmpdir) / "test.dwg"
dxf_path.write_text("dummy dxf content")
result = convert_dxf_to_dwg(dxf_path, dwg_path)
assert result is None
@patch("pdf2imos.output.dwg_converter.subprocess.run")
@patch("pdf2imos.output.dwg_converter.is_oda_converter_available")
def test_returns_none_when_output_not_created(
self, mock_available, mock_run
):
"""Test returns None if output DWG file not created by converter."""
mock_available.return_value = True
mock_run.return_value = MagicMock(returncode=0)
with tempfile.TemporaryDirectory() as tmpdir:
dxf_path = Path(tmpdir) / "test.dxf"
dwg_path = Path(tmpdir) / "test.dwg"
dxf_path.write_text("dummy dxf content")
with patch("tempfile.TemporaryDirectory") as mock_temp:
temp_input = Path(tmpdir) / "temp_input"
temp_output = Path(tmpdir) / "temp_output"
temp_input.mkdir()
temp_output.mkdir()
# Don't create the expected output file
mock_temp.return_value.__enter__.side_effect = [
str(temp_input),
str(temp_output),
]
with patch(
"pdf2imos.output.dwg_converter.shutil.copy2"
):
result = convert_dxf_to_dwg(dxf_path, dwg_path)
assert result is None
@patch("pdf2imos.output.dwg_converter.subprocess.run")
@patch("pdf2imos.output.dwg_converter.is_oda_converter_available")
def test_creates_output_directory(self, mock_available, mock_run):
"""Test that output directory is created if it doesn't exist."""
mock_available.return_value = True
mock_run.return_value = MagicMock(returncode=0)
with tempfile.TemporaryDirectory() as tmpdir:
dxf_path = Path(tmpdir) / "test.dxf"
dwg_path = Path(tmpdir) / "nested" / "output" / "test.dwg"
dxf_path.write_text("dummy dxf content")
with patch("tempfile.TemporaryDirectory") as mock_temp:
temp_input = Path(tmpdir) / "temp_input"
temp_output = Path(tmpdir) / "temp_output"
temp_input.mkdir()
temp_output.mkdir()
(temp_output / "test.dwg").write_text("dummy dwg")
mock_temp.return_value.__enter__.side_effect = [
str(temp_input),
str(temp_output),
]
with patch(
"pdf2imos.output.dwg_converter.shutil.copy2"
) as mock_copy:
def copy_side_effect(src, dst):
Path(dst).parent.mkdir(parents=True, exist_ok=True)
Path(dst).write_text("dummy")
mock_copy.side_effect = copy_side_effect
convert_dxf_to_dwg(dxf_path, dwg_path)
# Verify parent directory was created
assert dwg_path.parent.exists()
@patch("pdf2imos.output.dwg_converter.subprocess.run")
@patch("pdf2imos.output.dwg_converter.is_oda_converter_available")
def test_returns_path_on_success(self, mock_available, mock_run):
"""Test returns Path object on successful conversion."""
mock_available.return_value = True
mock_run.return_value = MagicMock(returncode=0)
with tempfile.TemporaryDirectory() as tmpdir:
dxf_path = Path(tmpdir) / "test.dxf"
dwg_path = Path(tmpdir) / "test.dwg"
dxf_path.write_text("dummy dxf content")
with patch("tempfile.TemporaryDirectory") as mock_temp:
temp_input = Path(tmpdir) / "temp_input"
temp_output = Path(tmpdir) / "temp_output"
temp_input.mkdir()
temp_output.mkdir()
(temp_output / "test.dwg").write_text("dummy dwg")
mock_temp.return_value.__enter__.side_effect = [
str(temp_input),
str(temp_output),
]
with patch(
"pdf2imos.output.dwg_converter.shutil.copy2"
) as mock_copy:
def copy_side_effect(src, dst):
Path(dst).parent.mkdir(parents=True, exist_ok=True)
Path(dst).write_text("dummy")
mock_copy.side_effect = copy_side_effect
result = convert_dxf_to_dwg(dxf_path, dwg_path)
assert result == dwg_path
assert isinstance(result, Path)