#![allow(
clippy::arithmetic_side_effects,
clippy::expect_used,
clippy::indexing_slicing,
clippy::panic,
clippy::unwrap_used
)]
use crate::io::database::backend::params;
use crate::io::database::macros::build_query;
use crate::io::database::schema::{ActivityRow, CatalogRow, LinkCacheRow, ProgrammingLanguageRow, ResearchActivityCacheRow, Table, ValidationRow};
use crate::io::database::{resolve_database_path, Database, Operations, Row, TableSchemaProvider};
use crate::prelude::PathBuf;
use crate::util::constants::env::DATABASE_PATH;
use std::time::{SystemTime, UNIX_EPOCH};
const TEST_ENV_DATABASE_PATH: &str = "target/test_artifacts/from-env-acorn.db";
mod display_tests;
#[test]
fn test_activity_insert_round_trip_with_database_handle() {
let unique = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|value| value.as_nanos())
.unwrap_or_default();
let path = PathBuf::from(format!("target/test_artifacts/activity-{unique}.duckdb"));
let database = Database::<Table>::from_path(Some(path.clone()));
database.migrate().unwrap();
let activity = ActivityRow::init()
.command("download")
.user_path("target/test_artifacts")
.success(true)
.build();
let inserted = database.insert(activity);
assert!(inserted.is_ok(), "insert failed: {inserted:?}");
let rows = Table::Activity.rows::<ActivityRow, _>(
"SELECT id, command, executed_at, user_path, success FROM activity",
params![],
Some(&path),
);
assert!(rows.is_ok(), "select failed: {rows:?}");
let rows = rows.unwrap();
assert!(!rows.is_empty());
assert_eq!(rows[0].command.as_deref(), Some("download"));
}
#[test]
fn test_activity_row_default() {
let row = ActivityRow::default();
assert!(row.id.is_none());
assert!(row.command.is_none());
assert!(row.executed_at.is_none());
assert!(row.user_path.is_none());
assert!(row.success.is_none());
}
#[test]
fn test_build_query_with_all_none_fields() {
let row = ActivityRow::default();
let base = "SELECT * FROM activity";
let order_by = Some("executed_at DESC");
let (query, params) = build_query!(&row, base, order_by, [id, command, user_path,]);
assert_eq!(query, "SELECT * FROM activity ORDER BY executed_at DESC");
assert!(params.is_empty());
}
#[test]
fn test_build_query_with_some_fields() {
let row = ActivityRow {
id: Some(42),
command: Some("check".to_string()),
user_path: None,
..Default::default()
};
let base = "SELECT * FROM activity";
let order_by = Some("executed_at DESC");
let (query, params) = build_query!(&row, base, order_by, [id, command, user_path,]);
assert_eq!(query, "SELECT * FROM activity WHERE id = ? AND command = ? ORDER BY executed_at DESC");
assert_eq!(params.len(), 2);
}
#[test]
fn test_build_query_without_order_by() {
let row = CatalogRow {
id: Some(1),
bucket_name: Some("test-bucket".to_string()),
..Default::default()
};
let base = "SELECT * FROM catalog";
let order_by: Option<&str> = None;
let (query, params) = build_query!(&row, base, order_by, [id, bucket_name, identifier,]);
assert_eq!(query, "SELECT * FROM catalog WHERE id = ? AND bucket_name = ?");
assert_eq!(params.len(), 2);
}
#[test]
fn test_build_query_with_field_mapping() {
let row = ActivityRow {
id: Some(10),
success: Some(true),
..Default::default()
};
let base = "SELECT * FROM activity";
let order_by: Option<&str> = None;
let (query, params) = build_query!(&row, base, order_by, [
id,
success => i32::from,
]);
assert_eq!(query, "SELECT * FROM activity WHERE id = ? AND success = ?");
assert_eq!(params.len(), 2);
}
#[test]
fn test_build_query_single_field() {
let row = LinkCacheRow {
url: Some("https://example.com".to_string()),
..Default::default()
};
let base = "SELECT * FROM link_cache";
let order_by = Some("checked_at DESC");
let (query, params) = build_query!(&row, base, order_by, [id, url, status_code,]);
assert_eq!(query, "SELECT * FROM link_cache WHERE url = ? ORDER BY checked_at DESC");
assert_eq!(params.len(), 1);
}
#[test]
fn test_build_query_empty_with_no_order_by() {
let row = ValidationRow::default();
let base = "SELECT * FROM validation";
let order_by: Option<&str> = None;
let (query, params) = build_query!(&row, base, order_by, [id, path, check_type,]);
assert_eq!(query, "SELECT * FROM validation");
assert!(params.is_empty());
}
#[test]
fn test_catalog_row_default() {
let row = CatalogRow::default();
assert!(row.id.is_none());
assert!(row.bucket_name.is_none());
assert!(row.bucket_url.is_none());
assert!(row.identifier.is_none());
assert!(row.title.is_none());
assert!(row.updated_at.is_none());
}
#[test]
fn test_database_path_uses_explicit_argument_before_environment() {
let expected = PathBuf::from("target/test_artifacts/explicit-acorn.db");
let from_expected = temp_env::with_vars([(DATABASE_PATH, Some(TEST_ENV_DATABASE_PATH))], || {
resolve_database_path(Some(&expected)).unwrap()
});
assert_eq!(from_expected, expected);
}
#[test]
fn test_database_path_uses_environment_when_argument_absent() {
let expected = PathBuf::from(TEST_ENV_DATABASE_PATH);
let from_env = temp_env::with_vars([(DATABASE_PATH, Some(TEST_ENV_DATABASE_PATH))], || resolve_database_path(None).unwrap());
assert_eq!(from_env, expected);
}
#[test]
fn test_link_cache_row_default() {
let row = LinkCacheRow::default();
assert!(row.id.is_none());
assert!(row.url.is_none());
assert!(row.status_code.is_none());
assert!(row.is_reachable.is_none());
assert!(row.checked_at.is_none());
assert!(row.expires_at.is_none());
}
#[test]
fn test_link_cache_row_is_expired() {
let row = LinkCacheRow::default();
assert!(row.is_expired());
}
#[test]
fn test_research_activity_cache_row_default() {
let row = ResearchActivityCacheRow::default();
assert!(row.id.is_none());
assert!(row.identifier.is_none());
assert!(row.source_bucket.is_none());
assert!(row.title.is_none());
assert!(row.downloaded_at.is_none());
assert!(row.file_path.is_none());
}
#[test]
fn test_programming_language_row_default() {
let row = ProgrammingLanguageRow::default();
assert!(row.id.is_none());
assert!(row.language_id.is_none());
assert!(row.name.is_none());
assert!(row.language_type.is_none());
assert!(row.color.is_none());
assert!(row.group_name.is_none());
}
#[test]
fn test_row_table_implementation() {
assert_eq!(ActivityRow::default().table(), Table::Activity);
assert_eq!(CatalogRow::default().table(), Table::Catalog);
assert_eq!(LinkCacheRow::default().table(), Table::LinkCache);
assert_eq!(ProgrammingLanguageRow::default().table(), Table::ProgrammingLanguages);
assert_eq!(ValidationRow::default().table(), Table::ValidationHistory);
assert_eq!(ResearchActivityCacheRow::default().table(), Table::ResearchActivityCache);
}
#[test]
fn test_table_from_str() {
assert_eq!(Table::from("activity"), Table::Activity);
assert_eq!(Table::from("catalog"), Table::Catalog);
assert_eq!(Table::from("licenses"), Table::Licenses);
assert_eq!(Table::from("license"), Table::Licenses);
assert_eq!(Table::from("link_cache"), Table::LinkCache);
assert_eq!(Table::from("programming_languages"), Table::ProgrammingLanguages);
assert_eq!(Table::from("programminglanguages"), Table::ProgrammingLanguages);
assert_eq!(Table::from("languages"), Table::ProgrammingLanguages);
assert_eq!(Table::from("language"), Table::ProgrammingLanguages);
assert_eq!(Table::from("validation_history"), Table::ValidationHistory);
assert_eq!(Table::from("research_activity_cache"), Table::ResearchActivityCache);
assert_eq!(Table::from("unknown-table"), Table::Activity);
}
#[test]
fn test_validation_row_default() {
let row = ValidationRow::default();
assert!(row.id.is_none());
assert!(row.path.is_none());
assert!(row.check_type.is_none());
assert!(row.success.is_none());
assert!(row.message.is_none());
assert!(row.checked_at.is_none());
}