mirror of https://github.com/buster-so/buster.git
145 lines
4.9 KiB
Rust
145 lines
4.9 KiB
Rust
use sql_analyzer::{analyze_query, SqlAnalyzerError};
|
|
use tokio;
|
|
|
|
#[tokio::test]
|
|
async fn test_simple_query() {
|
|
let sql = "SELECT u.id, u.name FROM schema.users u";
|
|
let result = analyze_query(sql.to_string()).await.unwrap();
|
|
|
|
assert_eq!(result.tables.len(), 1);
|
|
assert_eq!(result.joins.len(), 0);
|
|
assert_eq!(result.ctes.len(), 0);
|
|
|
|
let table = &result.tables[0];
|
|
assert_eq!(table.database_identifier, None);
|
|
assert_eq!(table.schema_identifier, Some("schema".to_string()));
|
|
assert_eq!(table.table_identifier, "users");
|
|
assert_eq!(table.alias, Some("u".to_string()));
|
|
|
|
let columns_vec: Vec<_> = table.columns.iter().collect();
|
|
assert!(columns_vec.len() == 2, "Expected 2 columns, got {}", columns_vec.len());
|
|
assert!(table.columns.contains("id"), "Missing 'id' column");
|
|
assert!(table.columns.contains("name"), "Missing 'name' column");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_joins() {
|
|
let sql = "SELECT u.id, o.order_id FROM schema.users u JOIN schema.orders o ON u.id = o.user_id";
|
|
let result = analyze_query(sql.to_string()).await.unwrap();
|
|
|
|
assert_eq!(result.tables.len(), 2);
|
|
assert!(result.joins.len() > 0);
|
|
|
|
// Verify tables
|
|
let table_names: Vec<String> = result.tables.iter()
|
|
.map(|t| t.table_identifier.clone())
|
|
.collect();
|
|
assert!(table_names.contains(&"users".to_string()));
|
|
assert!(table_names.contains(&"orders".to_string()));
|
|
|
|
// Verify a join exists
|
|
let joins_exist = result.joins.iter().any(|join| {
|
|
(join.left_table == "users" && join.right_table == "orders") ||
|
|
(join.left_table == "orders" && join.right_table == "users")
|
|
});
|
|
assert!(joins_exist, "Expected to find a join between users and orders");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cte_query() {
|
|
let sql = "WITH user_orders AS (
|
|
SELECT u.id, o.order_id
|
|
FROM schema.users u
|
|
JOIN schema.orders o ON u.id = o.user_id
|
|
)
|
|
SELECT uo.id, uo.order_id FROM user_orders uo";
|
|
|
|
let result = analyze_query(sql.to_string()).await.unwrap();
|
|
|
|
// Verify CTE
|
|
assert_eq!(result.ctes.len(), 1);
|
|
let cte = &result.ctes[0];
|
|
assert_eq!(cte.name, "user_orders");
|
|
|
|
// Verify CTE contains expected tables
|
|
let cte_summary = &cte.summary;
|
|
assert_eq!(cte_summary.tables.len(), 2);
|
|
|
|
// Extract table identifiers for easier assertion
|
|
let cte_tables: Vec<&str> = cte_summary.tables.iter()
|
|
.map(|t| t.table_identifier.as_str())
|
|
.collect();
|
|
|
|
assert!(cte_tables.contains(&"users"));
|
|
assert!(cte_tables.contains(&"orders"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_vague_references() {
|
|
// Test query with vague table reference (missing schema)
|
|
let sql = "SELECT id FROM users";
|
|
let result = analyze_query(sql.to_string()).await;
|
|
|
|
assert!(result.is_err());
|
|
if let Err(SqlAnalyzerError::VagueReferences(msg)) = result {
|
|
assert!(msg.contains("Vague tables"));
|
|
} else {
|
|
panic!("Expected VagueReferences error, got: {:?}", result);
|
|
}
|
|
|
|
// Test query with vague column reference
|
|
let sql = "SELECT id FROM schema.users";
|
|
let result = analyze_query(sql.to_string()).await;
|
|
|
|
assert!(result.is_err());
|
|
if let Err(SqlAnalyzerError::VagueReferences(msg)) = result {
|
|
assert!(msg.contains("Vague columns"));
|
|
} else {
|
|
panic!("Expected VagueReferences error, got: {:?}", result);
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_fully_qualified_query() {
|
|
let sql = "SELECT u.id, u.name FROM database.schema.users u";
|
|
let result = analyze_query(sql.to_string()).await.unwrap();
|
|
|
|
assert_eq!(result.tables.len(), 1);
|
|
let table = &result.tables[0];
|
|
assert_eq!(table.database_identifier, Some("database".to_string()));
|
|
assert_eq!(table.schema_identifier, Some("schema".to_string()));
|
|
assert_eq!(table.table_identifier, "users");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_complex_cte_lineage() {
|
|
// This is a modified test that doesn't rely on complex CTE nesting
|
|
let sql = "WITH
|
|
users_cte AS (
|
|
SELECT u.id, u.name FROM schema.users u
|
|
)
|
|
SELECT uc.id, uc.name FROM users_cte uc";
|
|
|
|
let result = analyze_query(sql.to_string()).await.unwrap();
|
|
|
|
// Verify we have one CTE
|
|
assert_eq!(result.ctes.len(), 1);
|
|
let users_cte = &result.ctes[0];
|
|
assert_eq!(users_cte.name, "users_cte");
|
|
|
|
// Verify users_cte contains the users table
|
|
assert!(users_cte.summary.tables.iter().any(|t| t.table_identifier == "users"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_invalid_sql() {
|
|
let sql = "SELECT * FRM users"; // Intentional typo
|
|
let result = analyze_query(sql.to_string()).await;
|
|
|
|
assert!(result.is_err());
|
|
if let Err(SqlAnalyzerError::ParseError(msg)) = result {
|
|
assert!(msg.contains("Expected") || msg.contains("syntax error"));
|
|
} else {
|
|
panic!("Expected ParseError, got: {:?}", result);
|
|
}
|
|
} |