Skip to content

Commit 3c3c0b3

Browse files
authored
✅ increase test coverage (#113)
1 parent 0ca2dcc commit 3c3c0b3

File tree

3 files changed

+641
-24
lines changed

3 files changed

+641
-24
lines changed

tests/unit/test_cli_error_paths.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
from types import SimpleNamespace
2+
3+
import pytest
4+
from click.testing import CliRunner
5+
6+
from mysql_to_sqlite3.cli import cli as mysql2sqlite
7+
8+
9+
class _FakeConverter:
10+
def __init__(self, *args, **kwargs):
11+
pass
12+
13+
def transfer(self):
14+
raise RuntimeError("should not run")
15+
16+
17+
def _fake_supported_charsets(charset=None):
18+
"""Produce deterministic charset/collation pairs for tests."""
19+
# When called without a charset, emulate the public API generator used by click.Choice.
20+
if charset is None:
21+
return iter(
22+
[
23+
SimpleNamespace(id=0, charset="utf8mb4", collation="utf8mb4_general_ci"),
24+
SimpleNamespace(id=1, charset="latin1", collation="latin1_swedish_ci"),
25+
]
26+
)
27+
# When scoped to a particular charset, expose only the primary collation.
28+
return iter([SimpleNamespace(id=0, charset=charset, collation=f"{charset}_general_ci")])
29+
30+
31+
class TestCliErrorPaths:
32+
def test_mysql_collation_must_match_charset(self, monkeypatch: pytest.MonkeyPatch) -> None:
33+
"""Invalid charset/collation combinations should be rejected before transfer starts."""
34+
monkeypatch.setattr("mysql_to_sqlite3.cli.mysql_supported_character_sets", _fake_supported_charsets)
35+
monkeypatch.setattr("mysql_to_sqlite3.cli.MySQLtoSQLite", _FakeConverter)
36+
37+
runner = CliRunner()
38+
result = runner.invoke(
39+
mysql2sqlite,
40+
[
41+
"-f",
42+
"out.sqlite3",
43+
"-d",
44+
"db",
45+
"-u",
46+
"user",
47+
"--mysql-charset",
48+
"utf8mb4",
49+
"--mysql-collation",
50+
"latin1_swedish_ci",
51+
],
52+
)
53+
assert result.exit_code == 1
54+
assert "Invalid value for '--collation'" in result.output
55+
56+
def test_debug_reraises_keyboard_interrupt(self, monkeypatch: pytest.MonkeyPatch) -> None:
57+
"""Debug mode should bubble up KeyboardInterrupt for easier debugging."""
58+
59+
class KeyboardInterruptConverter:
60+
def __init__(self, *args, **kwargs):
61+
pass
62+
63+
def transfer(self):
64+
raise KeyboardInterrupt()
65+
66+
monkeypatch.setattr("mysql_to_sqlite3.cli.MySQLtoSQLite", KeyboardInterruptConverter)
67+
68+
kwargs = {
69+
"sqlite_file": "out.sqlite3",
70+
"mysql_user": "user",
71+
"prompt_mysql_password": False,
72+
"mysql_password": None,
73+
"mysql_database": "db",
74+
"mysql_tables": None,
75+
"exclude_mysql_tables": None,
76+
"mysql_views_as_tables": False,
77+
"limit_rows": 0,
78+
"collation": "BINARY",
79+
"prefix_indices": False,
80+
"without_foreign_keys": False,
81+
"without_tables": False,
82+
"without_data": False,
83+
"strict": False,
84+
"mysql_host": "localhost",
85+
"mysql_port": 3306,
86+
"mysql_charset": "utf8mb4",
87+
"mysql_collation": None,
88+
"skip_ssl": False,
89+
"chunk": 200000,
90+
"log_file": None,
91+
"json_as_text": False,
92+
"vacuum": False,
93+
"use_buffered_cursors": False,
94+
"quiet": False,
95+
"debug": True,
96+
}
97+
with pytest.raises(KeyboardInterrupt):
98+
mysql2sqlite.callback(**kwargs)
99+
100+
def test_debug_reraises_generic_exception(self, monkeypatch: pytest.MonkeyPatch) -> None:
101+
"""Debug mode should bubble up unexpected exceptions."""
102+
103+
class ExplodingConverter:
104+
def __init__(self, *args, **kwargs):
105+
pass
106+
107+
def transfer(self):
108+
raise RuntimeError("boom")
109+
110+
monkeypatch.setattr("mysql_to_sqlite3.cli.MySQLtoSQLite", ExplodingConverter)
111+
112+
kwargs = {
113+
"sqlite_file": "out.sqlite3",
114+
"mysql_user": "user",
115+
"prompt_mysql_password": False,
116+
"mysql_password": None,
117+
"mysql_database": "db",
118+
"mysql_tables": None,
119+
"exclude_mysql_tables": None,
120+
"mysql_views_as_tables": False,
121+
"limit_rows": 0,
122+
"collation": "BINARY",
123+
"prefix_indices": False,
124+
"without_foreign_keys": False,
125+
"without_tables": False,
126+
"without_data": False,
127+
"strict": False,
128+
"mysql_host": "localhost",
129+
"mysql_port": 3306,
130+
"mysql_charset": "utf8mb4",
131+
"mysql_collation": None,
132+
"skip_ssl": False,
133+
"chunk": 200000,
134+
"log_file": None,
135+
"json_as_text": False,
136+
"vacuum": False,
137+
"use_buffered_cursors": False,
138+
"quiet": False,
139+
"debug": True,
140+
}
141+
with pytest.raises(RuntimeError):
142+
mysql2sqlite.callback(**kwargs)

0 commit comments

Comments
 (0)