use std::path::PathBuf;
use tempfile::{NamedTempFile, TempDir};
use things3_core::ThingsDatabase;
#[tokio::test]
async fn test_database_not_found() {
let nonexistent_path = PathBuf::from("/nonexistent/path/to/database.db");
let result = ThingsDatabase::new(&nonexistent_path).await;
assert!(result.is_err(), "Should fail when database doesn't exist");
let err = result.unwrap_err();
let err_msg = format!("{}", err);
assert!(
err_msg.contains("Failed to connect") || err_msg.contains("database"),
"Error message should mention connection or database: {}",
err_msg
);
}
#[tokio::test]
async fn test_database_path_is_directory() {
let temp_dir = TempDir::new().unwrap();
let dir_path = temp_dir.path();
let result = ThingsDatabase::new(dir_path).await;
assert!(result.is_err(), "Should fail when path is a directory");
}
#[tokio::test]
async fn test_database_empty_file() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
let result = ThingsDatabase::new(db_path).await;
match result {
Ok(db) => {
let inbox_result = db.get_inbox(Some(10)).await;
assert!(
inbox_result.is_err(),
"Queries should fail on invalid/empty database"
);
}
Err(_) => {
}
}
}
#[tokio::test]
async fn test_database_corrupted_file() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
std::fs::write(db_path, b"This is not a valid SQLite database file!").unwrap();
let result = ThingsDatabase::new(db_path).await;
match result {
Ok(db) => {
let inbox_result = db.get_inbox(Some(10)).await;
assert!(
inbox_result.is_err(),
"Queries should fail on corrupted database"
);
}
Err(_) => {
}
}
}
#[tokio::test]
async fn test_database_invalid_path_characters() {
let invalid_path = PathBuf::from("invalid\0path.db");
let result = ThingsDatabase::new(&invalid_path).await;
assert!(result.is_err(), "Should fail with invalid path characters");
}
#[tokio::test]
async fn test_database_wrong_schema() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
let pool = sqlx::sqlite::SqlitePool::connect(&format!("sqlite:{}", db_path.display()))
.await
.unwrap();
sqlx::query("CREATE TABLE wrong_table (id INTEGER PRIMARY KEY, data TEXT)")
.execute(&pool)
.await
.unwrap();
pool.close().await;
let result = ThingsDatabase::new(db_path).await;
match result {
Ok(db) => {
let inbox_result = db.get_inbox(Some(10)).await;
assert!(
inbox_result.is_err(),
"Queries should fail when schema is wrong"
);
let today_result = db.get_today(Some(10)).await;
assert!(
today_result.is_err(),
"Today query should fail when schema is wrong"
);
let projects_result = db.get_projects(Some(10)).await;
assert!(
projects_result.is_err(),
"Projects query should fail when schema is wrong"
);
}
Err(_) => {
}
}
}
#[tokio::test]
async fn test_database_invalid_connection_string() {
let invalid_conn_str = "invalid://connection/string";
let result = ThingsDatabase::from_connection_string(invalid_conn_str).await;
assert!(
result.is_err(),
"Should fail with invalid connection string"
);
}
#[tokio::test]
async fn test_database_file_removed_during_operation() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path().to_path_buf();
{
let pool = sqlx::sqlite::SqlitePool::connect(&format!("sqlite:{}", db_path.display()))
.await
.unwrap();
sqlx::query("CREATE TABLE IF NOT EXISTS TMTask (uuid TEXT PRIMARY KEY, title TEXT)")
.execute(&pool)
.await
.unwrap();
pool.close().await;
}
let db = ThingsDatabase::new(&db_path).await.unwrap();
std::fs::remove_file(&db_path).unwrap();
let result = db.get_inbox(Some(10)).await;
assert!(result.is_err(), "Should fail when database file is removed");
}
#[tokio::test]
async fn test_database_health_check_on_invalid_db() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
let pool = sqlx::sqlite::SqlitePool::connect(&format!("sqlite:{}", db_path.display()))
.await
.unwrap();
pool.close().await;
let db = ThingsDatabase::new(db_path).await.unwrap();
let is_connected = db.is_connected().await;
assert!(
is_connected,
"Health check should succeed on valid connection"
);
}
#[tokio::test]
async fn test_database_extremely_long_path() {
let long_component = "a".repeat(300);
let long_path = PathBuf::from(format!("/tmp/{}/{}", long_component, long_component));
let result = ThingsDatabase::new(&long_path).await;
assert!(result.is_err(), "Should fail with extremely long path");
}