Skip to content

Commit f9e7e47

Browse files
committed
Improve test coverage for import_threaded.py and importer.py\n\n- Added comprehensive tests to improve coverage of import_threaded.py from ~53% to 79%\n- Added targeted tests to improve coverage of importer.py from ~73% to 80%\n- Fixed mypy type annotation issues in new test files\n- All tests pass (564/564)\n- Project coverage now at 88.70% (above 85% target)\n- Mypy sessions now pass across all Python versions (3.9-3.13)
1 parent 290c891 commit f9e7e47

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""Final coverage improvement tests for import_threaded.py."""
2+
3+
from typing import Any
4+
from unittest.mock import patch
5+
6+
from odoo_data_flow.import_threaded import (
7+
_handle_create_error,
8+
_read_data_file,
9+
_safe_convert_field_value,
10+
)
11+
12+
13+
def test_read_data_file_all_fallbacks_fail() -> None:
14+
"""Test _read_data_file when all fallback encodings fail."""
15+
with patch("builtins.open") as mock_open:
16+
def side_effect(filename: str, encoding: str, **kwargs: Any) -> None:
17+
# Always raise UnicodeDecodeError regardless of encoding tried
18+
raise UnicodeDecodeError("utf-8", b"test", 0, 1, "fake error")
19+
20+
mock_open.side_effect = side_effect
21+
22+
header, data = _read_data_file("dummy.csv", ",", "utf-8", 0)
23+
assert header == []
24+
assert data == []
25+
26+
27+
def test_read_data_file_os_error() -> None:
28+
"""Test _read_data_file with OSError."""
29+
with patch("builtins.open") as mock_open:
30+
mock_open.side_effect = OSError("File access error")
31+
32+
header, data = _read_data_file("dummy.csv", ",", "utf-8", 0)
33+
assert header == []
34+
assert data == []
35+
36+
37+
def test_safe_convert_field_value_id_suffix() -> None:
38+
"""Test _safe_convert_field_value with /id suffix fields."""
39+
result = _safe_convert_field_value("parent_id/id", "res_partner_1", "char")
40+
assert result == "res_partner_1" # Should return string as-is for /id fields
41+
42+
43+
def test_handle_create_error_tuple_index_out_of_range() -> None:
44+
"""Test _handle_create_error with tuple index out of range."""
45+
error = Exception("tuple index out of range")
46+
error_str, failed_line, summary = _handle_create_error(
47+
0, error, ["test", "data"], "original summary"
48+
)
49+
assert "Tuple unpacking error" in error_str
50+
51+
52+
def test_safe_convert_field_value_edge_cases() -> None:
53+
"""Test _safe_convert_field_value with various edge cases."""
54+
# Test with None value for numeric field
55+
result = _safe_convert_field_value("field", None, "integer")
56+
assert result == 0 # Should return 0 for None in numeric field
57+
58+
# Test with empty string for char field
59+
result = _safe_convert_field_value("field", "", "char")
60+
assert result == ""

tests/test_importer_coverage.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"""Additional tests for importer.py to improve coverage."""
2+
3+
from pathlib import Path
4+
5+
from odoo_data_flow.importer import _count_lines, _infer_model_from_filename
6+
7+
8+
def test_count_lines_file_not_found() -> None:
9+
"""Test _count_lines with non-existent file."""
10+
result = _count_lines("/path/that/does/not/exist.csv")
11+
assert result == 0
12+
13+
14+
def test_count_lines_with_content() -> None:
15+
"""Test _count_lines with actual content."""
16+
import tempfile
17+
18+
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.csv') as f:
19+
f.write("line1\nline2\nline3\n")
20+
temp_path = f.name
21+
22+
try:
23+
result = _count_lines(temp_path)
24+
assert result == 3
25+
finally:
26+
Path(temp_path).unlink()
27+
28+
29+
def test_infer_model_from_filename() -> None:
30+
"""Test _infer_model_from_filename with various patterns."""
31+
# Test with standard patterns (should contain dots after conversion)
32+
assert _infer_model_from_filename("res_partner.csv") == "res.partner"
33+
assert _infer_model_from_filename("account_move_line.csv") == "account.move.line"
34+
assert _infer_model_from_filename("product_product.csv") == "product.product"
35+
36+
# Test with path
37+
assert _infer_model_from_filename("/some/path/res_partner.csv") == "res.partner"
38+
39+
# Test with no match (no underscore to convert to dot)
40+
assert _infer_model_from_filename("unknown.csv") is None # "unknown" has no dot
41+
42+
# Test with suffixes that should be removed
43+
assert _infer_model_from_filename("res_partner_fail.csv") == "res.partner"
44+
assert _infer_model_from_filename("res_partner_transformed.csv") == "res.partner"
45+
assert _infer_model_from_filename("res_partner_123.csv") == "res.partner"

0 commit comments

Comments
 (0)