Scert/backend/internal/cli/mysql_backup_test.go
xuans 7bfd400345 修复MySQL恢复会话切换与精确数值备份错误
固定恢复连接,按DECIMAL列类型保留精确文本。新增双版本实库备份恢复、错误停止、取消以及正式命令失败回滚回归;不将同进程命令测试视为独立发行验收。
2026-09-27 19:32:46 +08:00

86 lines
3.0 KiB
Go

package cli
import (
"database/sql"
"strings"
"testing"
)
func TestQuoteMySQLIdentifierEscapesBackticks(t *testing.T) {
if value := quoteMySQLIdentifier("a`b"); value != "`a``b`" {
t.Fatalf("MySQL 标识符转义不正确:%s", value)
}
}
func TestMySQLSQLLiteral(t *testing.T) {
cases := []struct {
name string
value any
want string
}{
{name: "null", value: nil, want: "NULL"},
{name: "string", value: "a'b\\c\n\x00\x1a", want: "'a''b\\\\c\\n\\0\\Z'"},
{name: "binary", value: []byte{0x01, 0xaf}, want: "X'01af'"},
{name: "raw bytes", value: sql.RawBytes{0x00, 0xff}, want: "X'00ff'"},
{name: "integer", value: int64(42), want: "42"},
{name: "boolean", value: true, want: "1"},
}
for _, item := range cases {
t.Run(item.name, func(t *testing.T) {
if value := mysqlSQLLiteral(item.value); value != item.want {
t.Fatalf("SQL 字面量不正确:%s", value)
}
})
}
}
func TestQuoteMySQLColumns(t *testing.T) {
value := quoteMySQLColumns([]string{"id", "display_name"})
if value != "`id`, `display_name`" || strings.Contains(value, "'") {
t.Fatalf("MySQL 字段列表不正确:%s", value)
}
}
func TestMySQLColumnSQLLiteral(t *testing.T) {
for _, item := range []struct {
name string
value any
columnType string
want string
}{
{name: "decimal", value: []byte("123456789.123456"), columnType: "DECIMAL", want: "'123456789.123456'"},
{name: "precision", value: sql.RawBytes("-12345678901234567890123456789012345.123456789012345678901234567890"), columnType: "DECIMAL", want: "'-12345678901234567890123456789012345.123456789012345678901234567890'"},
{name: "null", value: nil, columnType: "DECIMAL", want: "NULL"},
{name: "string", value: "0.000001", columnType: "DECIMAL", want: "'0.000001'"},
{name: "binary", value: []byte("12"), columnType: "BLOB", want: "X'3132'"},
} {
t.Run(item.name, func(t *testing.T) {
if got := mysqlColumnSQLLiteral(item.value, item.columnType); got != item.want {
t.Fatalf("字段字面量不正确:%s", got)
}
})
}
}
func TestSplitMySQLStatementsKeepsQuotedSemicolons(t *testing.T) {
script := "-- 注释\nSET FOREIGN_KEY_CHECKS=0;\nINSERT INTO `items` (`value`) VALUES ('a; b'), ('it''s');\n"
statements := splitMySQLStatements(script)
if len(statements) != 2 {
t.Fatalf("SQL 语句拆分数量不正确:%d %#v", len(statements), statements)
}
if strings.Contains(statements[0], "注释") || !strings.Contains(statements[1], "'a; b'") || !strings.Contains(statements[1], "'it''s'") {
t.Fatalf("SQL 语句拆分内容不正确:%#v", statements)
}
}
func TestSplitMySQLStatementsKeepsExecutableComments(t *testing.T) {
script := "CREATE TABLE `items` (`id` bigint) /*!50100 SET @value = 'a;b' */;\n"
statements := splitMySQLStatements(script)
if len(statements) != 1 {
t.Fatalf("带可执行注释的 SQL 语句拆分数量不正确:%d %#v", len(statements), statements)
}
if !strings.Contains(statements[0], "/*!50100 SET @value = 'a;b' */") {
t.Fatalf("MySQL 可执行注释不应被删除:%s", statements[0])
}
}