Skip to content

Commit 9a2d4ca

Browse files
committed
✅ add MySQL table prefix support and validation in CLI tests
1 parent 55e0198 commit 9a2d4ca

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

tests/unit/sqlite3_to_mysql_test.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,65 @@ def test_cli_sqlite_views_flag_propagates(
6767
assert transporter_ctor.call_args.kwargs["sqlite_views_as_tables"] is True
6868

6969

70+
def test_cli_mysql_table_prefix_passed_to_transporter(
71+
cli_runner: CliRunner,
72+
sqlite_database: str,
73+
mysql_credentials: MySQLCredentials,
74+
mocker: MockerFixture,
75+
) -> None:
76+
transporter_ctor = mocker.patch("sqlite3_to_mysql.cli.SQLite3toMySQL", autospec=True)
77+
transporter_instance = transporter_ctor.return_value
78+
transporter_instance.transfer.return_value = None
79+
80+
common_args = [
81+
"-f",
82+
sqlite_database,
83+
"-d",
84+
mysql_credentials.database,
85+
"-u",
86+
mysql_credentials.user,
87+
"--mysql-password",
88+
mysql_credentials.password,
89+
"-h",
90+
mysql_credentials.host,
91+
"-P",
92+
str(mysql_credentials.port),
93+
]
94+
95+
result: Result = cli_runner.invoke(sqlite3mysql, common_args + ["--mysql-table-prefix", "stage_"])
96+
assert result.exit_code == 0
97+
assert transporter_ctor.call_args.kwargs["mysql_table_prefix"] == "stage_"
98+
99+
100+
def test_cli_mysql_table_prefix_validation(
101+
cli_runner: CliRunner,
102+
sqlite_database: str,
103+
mysql_credentials: MySQLCredentials,
104+
mocker: MockerFixture,
105+
) -> None:
106+
transporter_ctor = mocker.patch("sqlite3_to_mysql.cli.SQLite3toMySQL", autospec=True)
107+
108+
common_args = [
109+
"-f",
110+
sqlite_database,
111+
"-d",
112+
mysql_credentials.database,
113+
"-u",
114+
mysql_credentials.user,
115+
"--mysql-password",
116+
mysql_credentials.password,
117+
"-h",
118+
mysql_credentials.host,
119+
"-P",
120+
str(mysql_credentials.port),
121+
]
122+
123+
result: Result = cli_runner.invoke(sqlite3mysql, common_args + ["--mysql-table-prefix", "123bad"])
124+
assert result.exit_code != 0
125+
assert "Table prefix" in result.output
126+
transporter_ctor.assert_not_called()
127+
128+
70129
def test_cli_collation_validation(
71130
cli_runner: CliRunner,
72131
sqlite_database: str,
@@ -401,6 +460,7 @@ def _make_transfer_stub(mocker: MockFixture) -> SQLite3toMySQL:
401460
instance._translate_sqlite_view_definition = mocker.MagicMock(return_value="CREATE VIEW translated AS SELECT 1")
402461
instance._sqlite_cur.fetchall.return_value = []
403462
instance._sqlite_cur.execute.return_value = None
463+
instance._mysql_table_prefix = ""
404464
instance._get_table_info = mocker.MagicMock(
405465
return_value=[
406466
{"name": "c1", "type": "TEXT", "hidden": 0},
@@ -483,6 +543,27 @@ def execute_side_effect(sql, *params):
483543
assert "INSERT" in sql_arg
484544

485545

546+
def test_transfer_applies_mysql_table_prefix(mocker: MockFixture) -> None:
547+
instance = _make_transfer_stub(mocker)
548+
instance._mysql_table_prefix = "pre_"
549+
instance._mysql_transfer_data = True
550+
instance._sqlite_cur.fetchone.return_value = {"total_records": 1}
551+
instance._sqlite_cur.fetchall.return_value = [(1,)]
552+
553+
def execute_side_effect(sql, *params):
554+
if sql.startswith("SELECT ") and "FROM" in sql and "COUNT" not in sql.upper():
555+
instance._sqlite_cur.description = [("c1",)]
556+
return None
557+
558+
instance._sqlite_cur.execute.side_effect = execute_side_effect
559+
instance._fetch_sqlite_master_rows = mocker.MagicMock(side_effect=[[{"name": "tbl", "type": "table"}], []])
560+
561+
instance.transfer()
562+
563+
sql_arg = instance._transfer_table_data.call_args.kwargs["sql"]
564+
assert "INTO `pre_tbl`" in sql_arg
565+
566+
486567
def test_transfer_escapes_sqlite_identifiers(mocker: MockFixture) -> None:
487568
instance = _make_transfer_stub(mocker)
488569
instance._mysql_transfer_data = True
@@ -1717,6 +1798,34 @@ def test_add_foreign_keys_shorthand_references_primary_key(
17171798
assert "REFERENCES `parent`(`id`)" in executed_sql
17181799
proc._mysql.commit.assert_called_once()
17191800

1801+
def test_add_foreign_keys_apply_mysql_table_prefix(self, mocker: MockFixture) -> None:
1802+
proc = SQLite3toMySQL.__new__(SQLite3toMySQL)
1803+
sqlite_cursor = mocker.MagicMock()
1804+
sqlite_cursor.fetchall.return_value = [
1805+
{
1806+
"id": 0,
1807+
"seq": 0,
1808+
"table": "parent",
1809+
"from": "parent_id",
1810+
"to": "id",
1811+
"on_delete": "NO ACTION",
1812+
"on_update": "NO ACTION",
1813+
}
1814+
]
1815+
proc._sqlite_cur = sqlite_cursor
1816+
proc._sqlite_table_xinfo_support = False
1817+
proc._mysql_cur = mocker.MagicMock()
1818+
proc._mysql = mocker.MagicMock()
1819+
proc._logger = mocker.MagicMock()
1820+
proc._mysql_table_prefix = "pre_"
1821+
1822+
proc._add_foreign_keys("child")
1823+
1824+
executed_sql = proc._mysql_cur.execute.call_args[0][0]
1825+
assert "ALTER TABLE `pre_child`" in executed_sql
1826+
assert "REFERENCES `pre_parent`" in executed_sql
1827+
proc._mysql.commit.assert_called_once()
1828+
17201829
def test_add_foreign_keys_shorthand_pk_mismatch_is_skipped(
17211830
self,
17221831
sqlite_database: str,

0 commit comments

Comments
 (0)