use crate::mysql::query_builder::SqlGenerator;
use proptest::prelude::*;
use std::collections::HashMap;
#[test]
fn test_new_sql_capacity_is_256() {
let sql_gen = SqlGenerator::new();
assert!(
sql_gen.sql_capacity() >= 256,
"sql 字段容量应 >= 256,实际为 {}",
sql_gen.sql_capacity()
);
}
#[test]
fn test_new_params_capacity_is_8() {
let sql_gen = SqlGenerator::new();
assert!(
sql_gen.params_capacity() >= 8,
"params 字段容量应 >= 8,实际为 {}",
sql_gen.params_capacity()
);
}
#[test]
fn test_new_sql_content_is_empty() {
let sql_gen = SqlGenerator::new();
assert!(
sql_gen.get_sql().is_empty(),
"新建的 SqlGenerator sql 应为空"
);
}
#[test]
fn test_new_params_content_is_empty() {
let sql_gen = SqlGenerator::new();
assert!(
sql_gen.get_params().is_empty(),
"新建的 SqlGenerator params 应为空"
);
}
#[test]
fn test_clear_preserves_capacity() {
let mut sql_gen = SqlGenerator::new();
let data =
serde_json::json!({"name": "test_user", "age": 18, "email": "test@example.com"});
sql_gen
.build_insert("users", &data, &HashMap::new())
.unwrap();
let sql_cap_before = sql_gen.sql_capacity();
let params_cap_before = sql_gen.params_capacity();
sql_gen.clear_for_test();
assert!(
sql_gen.sql_capacity() >= sql_cap_before,
"clear() 后 sql 容量不应减少,清空前 {},清空后 {}",
sql_cap_before,
sql_gen.sql_capacity()
);
assert!(
sql_gen.params_capacity() >= params_cap_before,
"clear() 后 params 容量不应减少,清空前 {},清空后 {}",
params_cap_before,
sql_gen.params_capacity()
);
assert!(
sql_gen.get_sql().is_empty(),
"clear() 后 sql 内容应为空"
);
assert!(
sql_gen.get_params().is_empty(),
"clear() 后 params 内容应为空"
);
}
#[test]
fn test_clear_does_not_use_new_allocation() {
let mut sql_gen = SqlGenerator::new();
let data = serde_json::json!({"field1": "value1", "field2": 42});
sql_gen
.build_insert("tbl", &data, &HashMap::new())
.unwrap();
sql_gen.clear_for_test();
assert!(
sql_gen.sql_capacity() >= 256,
"clear() 后 sql 容量应 >= 256(预分配值),实际为 {}",
sql_gen.sql_capacity()
);
assert!(
sql_gen.params_capacity() >= 8,
"clear() 后 params 容量应 >= 8(预分配值),实际为 {}",
sql_gen.params_capacity()
);
}
proptest! {
#[test]
fn prop_p6_prealloc_insert_sql_correctness(
raw_field_names in prop::collection::vec("[a-z][a-z0-9_]{0,8}", 1..=8),
field_values in prop::collection::vec(0i64..=1000i64, 1..=8),
) {
let count = raw_field_names.len().min(field_values.len());
let mut unique_fields: Vec<String> = Vec::new();
let mut seen = std::collections::HashSet::new();
for name in &raw_field_names[..count] {
if seen.insert(name.clone()) {
unique_fields.push(name.clone());
}
}
if unique_fields.is_empty() {
return Ok(());
}
let mut obj = serde_json::Map::new();
for (i, name) in unique_fields.iter().enumerate() {
obj.insert(name.clone(), serde_json::json!(field_values[i]));
}
let data = serde_json::Value::Object(obj);
let mut sql_gen = SqlGenerator::new();
sql_gen.build_insert("test_table", &data, &HashMap::new()).unwrap();
let sql = sql_gen.get_sql().to_string();
let params_len = sql_gen.get_params().len();
prop_assert!(
sql.starts_with("INSERT INTO test_table ("),
"SQL 应以 'INSERT INTO test_table (' 开头,实际: {}",
sql
);
prop_assert!(
sql.contains(") VALUES ("),
"SQL 应包含 ') VALUES (',实际: {}",
sql
);
prop_assert!(
sql.ends_with(')'),
"SQL 应以 ')' 结尾,实际: {}",
sql
);
prop_assert_eq!(
params_len,
unique_fields.len(),
"参数数量应等于字段数量,字段数: {},参数数: {}",
unique_fields.len(),
params_len
);
let placeholder_count = sql.matches('?').count();
prop_assert_eq!(
placeholder_count,
unique_fields.len(),
"占位符数量应等于字段数量,字段数: {},占位符数: {}",
unique_fields.len(),
placeholder_count
);
}
#[test]
fn prop_p6_clear_and_reuse_produces_same_sql(
raw_field_names in prop::collection::vec("[a-z][a-z0-9_]{0,8}", 1..=5),
field_values in prop::collection::vec(0i64..=100i64, 1..=5),
) {
let count = raw_field_names.len().min(field_values.len());
let mut unique_fields: Vec<String> = Vec::new();
let mut seen = std::collections::HashSet::new();
for name in &raw_field_names[..count] {
if seen.insert(name.clone()) {
unique_fields.push(name.clone());
}
}
if unique_fields.is_empty() {
return Ok(());
}
let mut obj = serde_json::Map::new();
for (i, name) in unique_fields.iter().enumerate() {
obj.insert(name.clone(), serde_json::json!(field_values[i]));
}
let data = serde_json::Value::Object(obj);
let mut sql_gen = SqlGenerator::new();
sql_gen.build_insert("tbl", &data, &HashMap::new()).unwrap();
let sql_first = sql_gen.get_sql().to_string();
let params_len_first = sql_gen.get_params().len();
sql_gen.clear_for_test();
sql_gen.build_insert("tbl", &data, &HashMap::new()).unwrap();
let sql_second = sql_gen.get_sql().to_string();
let params_len_second = sql_gen.get_params().len();
prop_assert_eq!(
sql_first, sql_second,
"clear() 后重新生成的 SQL 应与首次相同"
);
prop_assert_eq!(
params_len_first, params_len_second,
"clear() 后重新生成的参数数量应与首次相同"
);
}
}