use super::generator::generate_schema_diff;
use super::parser::parse_sql_tables;
#[test]
fn test_table_name_with_and_without_backticks() {
let sql_with_backticks = "CREATE TABLE `user` (`id` INT PRIMARY KEY);";
let sql_without_backticks = "CREATE TABLE user (id INT PRIMARY KEY);";
let tables1 = parse_sql_tables(sql_with_backticks).expect("解析失败");
let tables2 = parse_sql_tables(sql_without_backticks).expect("解析失败");
assert!(tables1.contains_key("user"), "应该包含 user 表");
assert!(tables2.contains_key("user"), "应该包含 user 表");
assert!(!tables1.contains_key("`user`"), "不应该有带反引号的表名");
assert!(!tables2.contains_key("`user`"), "不应该有带反引号的表名");
}
#[test]
fn test_column_name_with_and_without_backticks() {
let sql_with_backticks = "CREATE TABLE test (`id` INT, `name` VARCHAR(50));";
let sql_without_backticks = "CREATE TABLE test (id INT, name VARCHAR(50));";
let tables1 = parse_sql_tables(sql_with_backticks).expect("解析失败");
let tables2 = parse_sql_tables(sql_without_backticks).expect("解析失败");
let table1 = tables1.get("test").expect("应该有 test 表");
let table2 = tables2.get("test").expect("应该有 test 表");
assert_eq!(table1.columns[0].name, "id");
assert_eq!(table1.columns[1].name, "name");
assert_eq!(table2.columns[0].name, "id");
assert_eq!(table2.columns[1].name, "name");
}
#[test]
fn test_index_column_with_and_without_backticks() {
let sql_with_backticks =
"CREATE TABLE test (`id` INT, `name` VARCHAR(50), INDEX idx_name (`name`));";
let sql_without_backticks =
"CREATE TABLE test (id INT, name VARCHAR(50), INDEX idx_name (name));";
let tables1 = parse_sql_tables(sql_with_backticks).expect("解析失败");
let tables2 = parse_sql_tables(sql_without_backticks).expect("解析失败");
let table1 = tables1.get("test").expect("应该有 test 表");
let table2 = tables2.get("test").expect("应该有 test 表");
let index1 = table1
.indexes
.iter()
.find(|i| i.name == "idx_name")
.expect("应该有 idx_name 索引");
let index2 = table2
.indexes
.iter()
.find(|i| i.name == "idx_name")
.expect("应该有 idx_name 索引");
assert_eq!(index1.columns[0], "name");
assert_eq!(index2.columns[0], "name");
}
#[test]
fn test_primary_key_with_and_without_backticks() {
let sql_with_backticks =
"CREATE TABLE test (`id` INT, `name` VARCHAR(50), PRIMARY KEY (`id`));";
let sql_without_backticks = "CREATE TABLE test (id INT, name VARCHAR(50), PRIMARY KEY (id));";
let tables1 = parse_sql_tables(sql_with_backticks).expect("解析失败");
let tables2 = parse_sql_tables(sql_without_backticks).expect("解析失败");
let table1 = tables1.get("test").expect("应该有 test 表");
let table2 = tables2.get("test").expect("应该有 test 表");
let pk1 = table1
.indexes
.iter()
.find(|i| i.is_primary)
.expect("应该有主键");
let pk2 = table2
.indexes
.iter()
.find(|i| i.is_primary)
.expect("应该有主键");
assert_eq!(pk1.columns[0], "id");
assert_eq!(pk2.columns[0], "id");
}
#[test]
fn test_mysql_keywords_as_identifiers() {
let sql = "CREATE TABLE `order` (`user` VARCHAR(50), `type` VARCHAR(20), `key` INT);";
let tables = parse_sql_tables(sql).expect("解析失败");
assert!(tables.contains_key("order"), "应该包含 order 表");
let table = tables.get("order").unwrap();
assert_eq!(table.columns[0].name, "user");
assert_eq!(table.columns[1].name, "type");
assert_eq!(table.columns[2].name, "key");
}
#[test]
fn test_diff_with_same_structure_different_backticks() {
let sql_mysql = "CREATE TABLE `custom_page_config` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`description` VARCHAR(255),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;";
let sql_file = "CREATE TABLE custom_page_config (
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
description VARCHAR(255),
PRIMARY KEY (id)
) ENGINE=InnoDB;";
let (diff_sql, _description) =
generate_schema_diff(Some(sql_mysql), sql_file, Some("MySQL"), "文件")
.expect("生成差异失败");
let meaningful_lines: Vec<&str> = diff_sql
.lines()
.filter(|line| !line.trim().is_empty() && !line.trim().starts_with("--"))
.collect();
assert!(
meaningful_lines.is_empty(),
"相同结构的表不应产生差异,但生成了: {:?}",
meaningful_lines
);
}
#[test]
fn test_diff_with_multiple_tables_mixed_backticks() {
let sql_mysql = "
CREATE TABLE `agent_config` (`id` INT, `name` VARCHAR(64), PRIMARY KEY (`id`));
CREATE TABLE `agent_component_config` (`id` INT, `type` VARCHAR(32), PRIMARY KEY (`id`));
";
let sql_file = "
CREATE TABLE agent_config (id INT, name VARCHAR(64), PRIMARY KEY (id));
CREATE TABLE agent_component_config (id INT, type VARCHAR(32), PRIMARY KEY (id));
";
let (diff_sql, _description) =
generate_schema_diff(Some(sql_mysql), sql_file, Some("MySQL"), "文件")
.expect("生成差异失败");
let meaningful_lines: Vec<&str> = diff_sql
.lines()
.filter(|line| !line.trim().is_empty() && !line.trim().starts_with("--"))
.collect();
assert!(
meaningful_lines.is_empty(),
"相同结构的多个表不应产生差异,但生成了: {:?}",
meaningful_lines
);
}
#[test]
fn test_column_level_primary_key_with_backticks() {
let sql_with_backticks = "CREATE TABLE test (`id` INT PRIMARY KEY, `name` VARCHAR(50));";
let sql_without_backticks = "CREATE TABLE test (id INT PRIMARY KEY, name VARCHAR(50));";
let tables1 = parse_sql_tables(sql_with_backticks).expect("解析失败");
let tables2 = parse_sql_tables(sql_without_backticks).expect("解析失败");
let table1 = tables1.get("test").expect("应该有 test 表");
let table2 = tables2.get("test").expect("应该有 test 表");
let pk1 = table1
.indexes
.iter()
.find(|i| i.is_primary)
.expect("应该有主键");
let pk2 = table2
.indexes
.iter()
.find(|i| i.is_primary)
.expect("应该有主键");
assert_eq!(pk1.columns[0], "id");
assert_eq!(pk2.columns[0], "id");
}
#[test]
fn test_composite_primary_key_with_backticks() {
let sql_with_backticks =
"CREATE TABLE test (`user_id` INT, `order_id` INT, PRIMARY KEY (`user_id`, `order_id`));";
let sql_without_backticks =
"CREATE TABLE test (user_id INT, order_id INT, PRIMARY KEY (user_id, order_id));";
let tables1 = parse_sql_tables(sql_with_backticks).expect("解析失败");
let tables2 = parse_sql_tables(sql_without_backticks).expect("解析失败");
let table1 = tables1.get("test").expect("应该有 test 表");
let table2 = tables2.get("test").expect("应该有 test 表");
let pk1 = table1
.indexes
.iter()
.find(|i| i.is_primary)
.expect("应该有主键");
let pk2 = table2
.indexes
.iter()
.find(|i| i.is_primary)
.expect("应该有主键");
assert_eq!(pk1.columns.len(), 2);
assert_eq!(pk1.columns[0], "user_id");
assert_eq!(pk1.columns[1], "order_id");
assert_eq!(pk2.columns.len(), 2);
assert_eq!(pk2.columns[0], "user_id");
assert_eq!(pk2.columns[1], "order_id");
}
#[test]
fn test_unique_index_with_backticks() {
let sql_with_backticks =
"CREATE TABLE test (`id` INT, `email` VARCHAR(100), UNIQUE KEY `uk_email` (`email`));";
let sql_without_backticks =
"CREATE TABLE test (id INT, email VARCHAR(100), UNIQUE KEY uk_email (email));";
let tables1 = parse_sql_tables(sql_with_backticks).expect("解析失败");
let tables2 = parse_sql_tables(sql_without_backticks).expect("解析失败");
let table1 = tables1.get("test").expect("应该有 test 表");
let table2 = tables2.get("test").expect("应该有 test 表");
let uk1 = table1
.indexes
.iter()
.find(|i| i.is_unique && !i.is_primary)
.expect("应该有唯一索引");
let uk2 = table2
.indexes
.iter()
.find(|i| i.is_unique && !i.is_primary)
.expect("应该有唯一索引");
assert_eq!(uk1.columns[0], "email");
assert_eq!(uk2.columns[0], "email");
assert_eq!(uk1.name, uk2.name);
}
#[test]
fn test_real_world_scenario_mysql_vs_file() {
let mysql_sql = "CREATE TABLE `agent_config` (
`id` bigint AUTO_INCREMENT,
`uid` varchar(64) NOT NULL,
`_tenant_id` bigint DEFAULT 1 NOT NULL,
`name` varchar(64) NOT NULL,
`type` varchar(32) DEFAULT 'ChatBot' NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
let file_sql = "create table agent_config
(
id bigint auto_increment,
uid varchar(64) not null,
_tenant_id bigint default 1 not null,
name varchar(64) not null,
type varchar(32) default 'ChatBot' not null,
primary key (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
let tables_mysql = parse_sql_tables(mysql_sql).expect("解析 MySQL SQL 失败");
let tables_file = parse_sql_tables(file_sql).expect("解析文件 SQL 失败");
assert!(tables_mysql.contains_key("agent_config"));
assert!(tables_file.contains_key("agent_config"));
let (diff_sql, _description) =
generate_schema_diff(Some(mysql_sql), file_sql, Some("MySQL"), "文件")
.expect("生成差异失败");
let meaningful_lines: Vec<&str> = diff_sql
.lines()
.filter(|line| {
let trimmed = line.trim();
!trimmed.is_empty() && !trimmed.starts_with("--")
})
.collect();
if !meaningful_lines.is_empty() {
println!("生成的差异 SQL:\n{}", diff_sql);
}
assert!(
!diff_sql.contains("DROP COLUMN `id`") && !diff_sql.contains("ADD COLUMN `id`"),
"不应该删除和添加相同的列"
);
}