diff options
| author | Joe Carstairs <me@joeac.net> | 2024-12-12 08:28:04 +0000 |
|---|---|---|
| committer | Joe Carstairs <me@joeac.net> | 2024-12-12 08:28:04 +0000 |
| commit | 54894f9de9bad4fecb2a116d59a03cdd003f84c0 (patch) | |
| tree | 6ce5517cecf23d4e93d7a381a374e1fa6c810cee /actualbudget_queries/tests | |
| parent | 8a30bcbdf9264d235bf93da3df8e170cfde53d02 (diff) | |
Moves rust workspace to root
Diffstat (limited to 'actualbudget_queries/tests')
16 files changed, 990 insertions, 0 deletions
diff --git a/actualbudget_queries/tests/actualbudget_accounts.rs b/actualbudget_queries/tests/actualbudget_accounts.rs new file mode 100644 index 0000000..954cac1 --- /dev/null +++ b/actualbudget_queries/tests/actualbudget_accounts.rs @@ -0,0 +1,32 @@ +pub mod common; + +use actualbudget_queries::actualbudget_accounts::{get_all_actualbudget_accounts, get_category_transfers_account}; +use common::{account_names::ACCOUNT_NAMES, db_url::DB_URL}; +use diesel::{Connection, SqliteConnection}; + +#[test] +fn given_test_database_when_get_all_accounts_then_return_accounts() { + let connection = &mut SqliteConnection::establish(DB_URL).unwrap(); + + let accounts = get_all_actualbudget_accounts(connection); + + assert!(accounts.is_ok()); + let accounts = accounts.unwrap(); + assert_eq!(ACCOUNT_NAMES.len(), accounts.len()); + for account_name in ACCOUNT_NAMES { + assert!(accounts.iter().any(|a| a.name.as_str() == *account_name)); + } +} + +#[test] +fn given_test_database_when_get_category_transfer_account_then_return_category_transfer_account() { + let connection = &mut SqliteConnection::establish(DB_URL).unwrap(); + + let account = get_category_transfers_account(connection); + + assert!(account.is_ok()); + let account = account.unwrap(); + assert!(account.is_some()); + let account = account.unwrap(); + assert!(account.name == "Category transfers"); +} diff --git a/actualbudget_queries/tests/actualbudget_categories.rs b/actualbudget_queries/tests/actualbudget_categories.rs new file mode 100644 index 0000000..27c17c8 --- /dev/null +++ b/actualbudget_queries/tests/actualbudget_categories.rs @@ -0,0 +1,19 @@ +pub mod common; + +use actualbudget_queries::actualbudget_categories::get_all_actualbudget_categories; +use common::{category_names::CATEGORY_NAMES, db_url::DB_URL}; +use diesel::{Connection, SqliteConnection}; + +#[test] +fn given_test_database_when_get_all_categories_then_return_categories() { + let connection = &mut SqliteConnection::establish(DB_URL).unwrap(); + + let categories = get_all_actualbudget_categories(connection); + + assert!(categories.is_ok()); + let categories = categories.unwrap(); + assert_eq!(CATEGORY_NAMES.len(), categories.len()); + for &category_name in CATEGORY_NAMES { + assert!(categories.iter().any(|a| a.name.as_str() == category_name)); + } +} diff --git a/actualbudget_queries/tests/actualbudget_payees.rs b/actualbudget_queries/tests/actualbudget_payees.rs new file mode 100644 index 0000000..acf5c4e --- /dev/null +++ b/actualbudget_queries/tests/actualbudget_payees.rs @@ -0,0 +1,25 @@ +pub mod common; + +use actualbudget_queries::actualbudget_payees::get_all_actualbudget_payees; +use common::{db_url::DB_URL, get_reference_data::get_accounts, payee_matchers::get_payee_matchers}; +use diesel::{Connection, SqliteConnection}; + +#[test] +fn given_test_database_when_get_all_payees_then_return_payees() { + let connection = &mut SqliteConnection::establish(DB_URL).unwrap(); + let accounts = get_accounts(connection); + + let payees = get_all_actualbudget_payees(connection); + + assert!(payees.is_ok()); + let payees = payees.unwrap(); + let payee_matchers = get_payee_matchers(); + assert_eq!(payee_matchers.len(), payees.len()); + for payee in payees { + assert!( + payee_matchers.iter().any(|payee_matcher| payee_matcher(&payee, &accounts)), + "no match found for payee {:?}", + payee, + ); + } +} diff --git a/actualbudget_queries/tests/actualbudget_transactions.rs b/actualbudget_queries/tests/actualbudget_transactions.rs new file mode 100644 index 0000000..c9d72a9 --- /dev/null +++ b/actualbudget_queries/tests/actualbudget_transactions.rs @@ -0,0 +1,38 @@ +pub mod common; + +use actualbudget_queries::actualbudget_transactions::{get_all_actualbudget_transactions, get_first_actualbudget_transaction_date}; +use common::{db_url::DB_URL, get_reference_data::{get_accounts, get_categories}, transaction_matchers::get_transaction_matchers}; +use diesel::{Connection, SqliteConnection}; + +#[test] +fn given_test_database_when_get_all_transactions_then_return_transactions() { + let connection = &mut SqliteConnection::establish(DB_URL).unwrap(); + let accounts = get_accounts(connection); + let categories = get_categories(connection); + + let transactions = get_all_actualbudget_transactions(connection); + + assert!(transactions.is_ok()); + let transactions = transactions.unwrap(); + let transaction_matchers = get_transaction_matchers(); + assert_eq!(transaction_matchers.len(), transactions.len()); + for transaction in transactions { + let any_match = transaction_matchers.iter().any(|transaction_matcher| + transaction_matcher(&transaction, &accounts, &categories) + ); + assert!(any_match, "no match found for transaction {:?}", transaction); + } +} + +#[test] +fn given_test_database_when_get_first_transaction_date_then_return_01_aug_2024() { + let connection = &mut SqliteConnection::establish(DB_URL).unwrap(); + + let date = get_first_actualbudget_transaction_date(connection); + + assert!(date.is_ok()); + let date = date.unwrap(); + assert_eq!("01", date.day()); + assert_eq!("08", date.month()); + assert_eq!("2024", date.year()); +} diff --git a/actualbudget_queries/tests/actualbudget_zero_budgets.rs b/actualbudget_queries/tests/actualbudget_zero_budgets.rs new file mode 100644 index 0000000..7218227 --- /dev/null +++ b/actualbudget_queries/tests/actualbudget_zero_budgets.rs @@ -0,0 +1,34 @@ +pub mod common; + +use actualbudget_queries::actualbudget_zero_budgets::{get_all_actualbudget_zero_budgets, get_first_zero_budget_date}; +use common::{db_url::DB_URL, get_reference_data::get_categories, zero_budget_matchers::get_zero_budget_matchers}; +use diesel::{Connection, SqliteConnection}; + +#[test] +fn given_test_database_when_get_all_zero_budgets_then_return_zero_budgets() { + let connection = &mut SqliteConnection::establish(DB_URL).unwrap(); + let categories = get_categories(connection); + + let zero_budgets = get_all_actualbudget_zero_budgets(connection); + + assert!(zero_budgets.is_ok()); + let zero_budgets = zero_budgets.unwrap(); + let zero_budget_matchers = get_zero_budget_matchers(); + assert_eq!(zero_budget_matchers.len(), zero_budgets.len()); + for matcher in zero_budget_matchers { + assert!(zero_budgets.iter().any(|zb| matcher(zb, &categories))) + } +} + +#[test] +fn given_test_database_when_get_first_zero_budget_date_then_return_1_aug_2024() { + let connection = &mut SqliteConnection::establish(DB_URL).unwrap(); + + let date = get_first_zero_budget_date(connection); + + assert!(date.is_ok()); + let date = date.unwrap(); + assert_eq!("01", date.day()); + assert_eq!("08", date.month()); + assert_eq!("2024", date.year()); +} diff --git a/actualbudget_queries/tests/common/account_names.rs b/actualbudget_queries/tests/common/account_names.rs new file mode 100644 index 0000000..1abee4b --- /dev/null +++ b/actualbudget_queries/tests/common/account_names.rs @@ -0,0 +1,17 @@ +pub const ACCOUNT_NAMES: &[&'static str] = &[ + "My bank account", + "My cash account", + "Category transfers", +]; + +pub struct AccountNamesDict { + pub bank_account: &'static str, + pub cash_account: &'static str, + pub transfers_account: &'static str, +} + +pub const ACCOUNT_NAMES_DICT: AccountNamesDict = AccountNamesDict { + bank_account: ACCOUNT_NAMES[0], + cash_account: ACCOUNT_NAMES[1], + transfers_account: ACCOUNT_NAMES[2], +}; diff --git a/actualbudget_queries/tests/common/category_names.rs b/actualbudget_queries/tests/common/category_names.rs new file mode 100644 index 0000000..a2f7d84 --- /dev/null +++ b/actualbudget_queries/tests/common/category_names.rs @@ -0,0 +1,29 @@ +pub const CATEGORY_NAMES: &[&'static str] = &[ + "Food", + "General", + "Bills", + "Bills (Flexible)", + "Savings", + "Starting Balances", + "Income", +]; + +pub struct CategoryNamesDict { + pub food: &'static str, + pub general: &'static str, + pub bills: &'static str, + pub bills_flexible: &'static str, + pub savings: &'static str, + pub starting_balances: &'static str, + pub income: &'static str, +} + +pub const CATEGORY_NAMES_DICT: CategoryNamesDict = CategoryNamesDict { + food: CATEGORY_NAMES[0], + general: CATEGORY_NAMES[1], + bills: CATEGORY_NAMES[2], + bills_flexible: CATEGORY_NAMES[3], + savings: CATEGORY_NAMES[4], + starting_balances: CATEGORY_NAMES[5], + income: CATEGORY_NAMES[6], +}; diff --git a/actualbudget_queries/tests/common/db_url.rs b/actualbudget_queries/tests/common/db_url.rs new file mode 100644 index 0000000..ff778a8 --- /dev/null +++ b/actualbudget_queries/tests/common/db_url.rs @@ -0,0 +1 @@ +pub const DB_URL: &str = "tests/resources/actualbudget_test_db.sqlite"; diff --git a/actualbudget_queries/tests/common/get_reference_data.rs b/actualbudget_queries/tests/common/get_reference_data.rs new file mode 100644 index 0000000..0d4f19c --- /dev/null +++ b/actualbudget_queries/tests/common/get_reference_data.rs @@ -0,0 +1,45 @@ +use std::collections::HashMap; + +use actualbudget_models::{ActualbudgetAccount, ActualbudgetCategory}; +use actualbudget_queries::{actualbudget_accounts::get_all_actualbudget_accounts, actualbudget_categories::get_all_actualbudget_categories}; +use diesel::SqliteConnection; + +use super::{account_names::ACCOUNT_NAMES, category_names::CATEGORY_NAMES}; + +pub fn get_accounts(connection: &mut SqliteConnection) -> HashMap<String, ActualbudgetAccount> { + let accounts = get_all_actualbudget_accounts(connection).expect("failed to get accounts"); + let mut accounts_hash_map = HashMap::new(); + + for &account_name in ACCOUNT_NAMES { + let account = accounts + .clone() + .into_iter() + .find(|a| a.name.as_str() == account_name) + .expect(&format!("failed to get account: {}", account_name)); + accounts_hash_map.insert( + String::from(account_name), + account, + ); + } + + accounts_hash_map +} + +pub fn get_categories(connection: &mut SqliteConnection) -> HashMap<String, ActualbudgetCategory> { + let categories = get_all_actualbudget_categories(connection).expect("failed to get categories"); + let mut categories_hash_map = HashMap::new(); + + for &category_name in CATEGORY_NAMES { + let category = categories + .clone() + .into_iter() + .find(|a| a.name.as_str() == category_name) + .expect(&format!("failed to get category: {}", category_name)); + categories_hash_map.insert( + String::from(category_name), + category, + ); + } + + categories_hash_map +} diff --git a/actualbudget_queries/tests/common/mod.rs b/actualbudget_queries/tests/common/mod.rs new file mode 100644 index 0000000..b19b061 --- /dev/null +++ b/actualbudget_queries/tests/common/mod.rs @@ -0,0 +1,8 @@ +pub mod account_names; +pub mod category_names; +pub mod db_url; +pub mod get_reference_data; +pub mod payee_matchers; +pub mod payee_names; +pub mod transaction_matchers; +pub mod zero_budget_matchers; diff --git a/actualbudget_queries/tests/common/payee_matchers.rs b/actualbudget_queries/tests/common/payee_matchers.rs new file mode 100644 index 0000000..ccba204 --- /dev/null +++ b/actualbudget_queries/tests/common/payee_matchers.rs @@ -0,0 +1,124 @@ +use std::collections::HashMap; + +use actualbudget_models::{ActualbudgetAccount, ActualbudgetPayee}; +use anyhow::Context; + +use super::{account_names::ACCOUNT_NAMES_DICT, payee_names::PAYEE_NAMES_DICT}; + +pub fn get_payee_matchers( +) -> Vec<Box<dyn Fn(&ActualbudgetPayee, &HashMap<String, ActualbudgetAccount>) -> bool>> { + vec![ + Box::new(|p, a| matches_bank_account_transfer_account(p, a)), + Box::new(|p, a| matches_cash_account_transfer_account(p, a)), + Box::new(|p, a| matches_category_transfers_transfer_account(p, a)), + Box::new(|p, a| matches_starting_balances(p, a)), + Box::new(|p, a| matches_employer(p, a)), + Box::new(|p, a| matches_tesco(p, a)), + ] +} + +fn matches_bank_account_transfer_account( + payee: &ActualbudgetPayee, + accounts: &HashMap<String, ActualbudgetAccount>, +) -> bool { + let bank_account = accounts + .get(ACCOUNT_NAMES_DICT.bank_account) + .with_context(|| "failed to get bank account") + .unwrap(); + + match payee { + ActualbudgetPayee { + name, + transfer_account_id, + .. + } => name == "" + && transfer_account_id.clone().is_some_and( + |account_id| account_id == bank_account.id, + ), + } +} + +fn matches_cash_account_transfer_account( + payee: &ActualbudgetPayee, + accounts: &HashMap<String, ActualbudgetAccount>, +) -> bool { + let cash_account = accounts + .get(ACCOUNT_NAMES_DICT.cash_account) + .with_context(|| "failed to find cash account") + .unwrap(); + + match payee { + ActualbudgetPayee { + name, + transfer_account_id, + .. + } => name == "" + && transfer_account_id.clone().is_some_and( + |account_id| account_id == cash_account.id, + ), + } +} + +fn matches_category_transfers_transfer_account( + payee: &ActualbudgetPayee, + accounts: &HashMap<String, ActualbudgetAccount>, +) -> bool { + let category_transfers_account = accounts + .get(ACCOUNT_NAMES_DICT.transfers_account) + .with_context(|| "failed to find category transfers account") + .unwrap(); + + match payee { + ActualbudgetPayee { + name, + transfer_account_id, + .. + } => name == "" + && transfer_account_id.clone().is_some_and( + |account_id| account_id == category_transfers_account.id, + ), + } +} + +fn matches_starting_balances( + payee: &ActualbudgetPayee, + _accounts: &HashMap<String, ActualbudgetAccount>, +) -> bool { + match payee { + ActualbudgetPayee { + name, + transfer_account_id, + .. + } => transfer_account_id.is_none() + && name.clone() == PAYEE_NAMES_DICT.starting_balances, + } +} + +fn matches_employer( + payee: &ActualbudgetPayee, + _accounts: &HashMap<String, ActualbudgetAccount>, +) -> bool { + match payee { + ActualbudgetPayee { + name, + transfer_account_id, + .. + } => transfer_account_id.is_none() + && name == PAYEE_NAMES_DICT.employer, + } +} + + +fn matches_tesco( + payee: &ActualbudgetPayee, + _accounts: &HashMap<String, ActualbudgetAccount>, +) -> bool { + match payee { + ActualbudgetPayee { + name, + transfer_account_id, + .. + } => transfer_account_id.is_none() + && name == PAYEE_NAMES_DICT.tesco, + } +} diff --git a/actualbudget_queries/tests/common/payee_names.rs b/actualbudget_queries/tests/common/payee_names.rs new file mode 100644 index 0000000..42b6024 --- /dev/null +++ b/actualbudget_queries/tests/common/payee_names.rs @@ -0,0 +1,17 @@ +pub const PAYEE_NAMES: &[&'static str] = &[ + "Starting Balance", + "Employer Ltd", + "Tesco", +]; + +pub struct PayeeNamesDict { + pub starting_balances: &'static str, + pub employer: &'static str, + pub tesco: &'static str, +} + +pub const PAYEE_NAMES_DICT: PayeeNamesDict = PayeeNamesDict { + starting_balances: PAYEE_NAMES[0], + employer: PAYEE_NAMES[1], + tesco: PAYEE_NAMES[2], +}; diff --git a/actualbudget_queries/tests/common/transaction_matchers.rs b/actualbudget_queries/tests/common/transaction_matchers.rs new file mode 100644 index 0000000..2620da5 --- /dev/null +++ b/actualbudget_queries/tests/common/transaction_matchers.rs @@ -0,0 +1,315 @@ +use std::collections::HashMap; + +use actualbudget_models::{ActualbudgetAccount, ActualbudgetCategory, ActualbudgetTransaction}; + +use super::{account_names::ACCOUNT_NAMES_DICT, category_names::CATEGORY_NAMES_DICT}; + +pub fn get_transaction_matchers() -> Vec<Box<dyn Fn(&ActualbudgetTransaction, &HashMap<String, ActualbudgetAccount>, &HashMap<String, ActualbudgetCategory>) -> bool>> { + vec![ + Box::new(|t, a, c| matches_bank_account_initial_transaction(t, a, c)), + Box::new(|t, a, c| matches_cash_account_initial_transaction(t, a, c)), + Box::new(|t, a, c| matches_income_transaction(t, a, c, "08")), + Box::new(|t, a, c| matches_income_transaction(t, a, c, "09")), + Box::new(|t, a, c| matches_income_transaction(t, a, c, "10")), + Box::new(|t, a, c| matches_income_transaction(t, a, c, "11")), + Box::new(|t, a, c| matches_food_transaction(t, a, c, "08")), + Box::new(|t, a, c| matches_food_transaction(t, a, c, "09")), + Box::new(|t, a, c| matches_food_transaction(t, a, c, "10")), + Box::new(|t, a, c| matches_food_transaction(t, a, c, "11")), + Box::new(|t, a, c| matches_category_transfer_parent_transaction(t, a, c)), + Box::new(|t, a, c| matches_category_transfer_child_out_transaction(t, a, c)), + Box::new(|t, a, c| matches_category_transfer_child_in_transaction(t, a, c)), + Box::new(|t, a, c| matches_account_transfer_out_transaction(t, a, c)), + Box::new(|t, a, c| matches_account_transfer_in_transaction(t, a, c)), + ] +} + +fn matches_bank_account_initial_transaction( + t: &ActualbudgetTransaction, + accounts: &HashMap<String, ActualbudgetAccount>, + categories: &HashMap<String, ActualbudgetCategory>, +) -> bool { + let bank_account_id = accounts + .get(ACCOUNT_NAMES_DICT.bank_account) + .expect("failed to find bank account") + .id + .clone(); + + let starting_balances_category_id = categories + .get(CATEGORY_NAMES_DICT.starting_balances) + .expect("failed to find starting balances category") + .id + .clone(); + + match t { + ActualbudgetTransaction { + is_parent: false, + is_child: false, + parent_id: None, + account_id, + category_id: Some(category_id), + amount: 1200_00, + date, + .. + } => *account_id == bank_account_id + && *category_id == starting_balances_category_id + && date.to_iso().get(0..10) == Some("2024-08-01"), + _ => false, + } +} + +fn matches_cash_account_initial_transaction( + t: &ActualbudgetTransaction, + accounts: &HashMap<String, ActualbudgetAccount>, + categories: &HashMap<String, ActualbudgetCategory>, +) -> bool { + let bank_account_id = accounts + .get(ACCOUNT_NAMES_DICT.cash_account) + .expect("failed to find cash account") + .id + .clone(); + + let starting_balances_category_id = categories + .get(CATEGORY_NAMES_DICT.starting_balances) + .expect("failed to find starting balances category") + .id + .clone(); + + match t { + ActualbudgetTransaction { + is_parent: false, + is_child: false, + parent_id: None, + account_id, + category_id: Some(category_id), + amount: 45_10, + date, + .. + } => *account_id == bank_account_id + && *category_id == starting_balances_category_id + && date.to_iso().get(0..10) == Some("2024-08-01"), + _ => false, + } +} + +fn matches_income_transaction( + t: &ActualbudgetTransaction, + accounts: &HashMap<String, ActualbudgetAccount>, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let bank_account_id = accounts + .get(ACCOUNT_NAMES_DICT.bank_account) + .expect("failed to find bank account") + .id + .clone(); + + let income_category_id = categories + .get(CATEGORY_NAMES_DICT.income) + .expect("failed to find income category") + .id + .clone(); + + match t { + ActualbudgetTransaction { + is_parent: false, + is_child: false, + parent_id: None, + account_id, + category_id, + amount: 846_46, + date, + notes: Some(notes), + .. + } => + *account_id == bank_account_id + && *category_id == Some(income_category_id) + && date.to_iso().get(0..10) == Some(format!("2024-{}-21", month).as_str()) + && *notes == String::from("Salary"), + _ => false, + } +} + +fn matches_food_transaction( + t: &ActualbudgetTransaction, + accounts: &HashMap<String, ActualbudgetAccount>, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let bank_account_id = accounts + .get(ACCOUNT_NAMES_DICT.bank_account) + .expect("failed to find bank account") + .id + .clone(); + + let income_category_id = categories + .get(CATEGORY_NAMES_DICT.food) + .expect("failed to find food category") + .id + .clone(); + + match t { + ActualbudgetTransaction { + is_parent: false, + is_child: false, + parent_id: None, + account_id, + category_id, + amount: -200_00, + date, + .. + } => *account_id == bank_account_id + && *category_id == Some(income_category_id) + && date.to_iso().get(0..10) == Some(format!("2024-{}-08", month).as_str()), + _ => false, + } +} + +fn matches_category_transfer_parent_transaction( + t: &ActualbudgetTransaction, + accounts: &HashMap<String, ActualbudgetAccount>, + _categories: &HashMap<String, ActualbudgetCategory>, +) -> bool { + let category_transfers_account_id = accounts + .get(ACCOUNT_NAMES_DICT.transfers_account) + .expect("failed to find transfers account") + .id + .clone(); + + match t { + ActualbudgetTransaction { + is_parent: true, + is_child: false, + parent_id: None, + account_id, + category_id: None, + amount: 0, + date, + .. + } => *account_id == category_transfers_account_id + && date.to_iso().get(0..10) == Some("2024-10-23"), + _ => false, + } +} + +fn matches_category_transfer_child_out_transaction( + t: &ActualbudgetTransaction, + accounts: &HashMap<String, ActualbudgetAccount>, + categories: &HashMap<String, ActualbudgetCategory>, +) -> bool { + let category_transfers_account_id = accounts + .get(ACCOUNT_NAMES_DICT.transfers_account) + .expect("failed to find transfers account") + .id + .clone(); + + let savings_category_id = categories + .get(CATEGORY_NAMES_DICT.savings) + .expect("failed to find savings category") + .id + .clone(); + + match t { + ActualbudgetTransaction { + is_parent: false, + is_child: true, + parent_id: Some(_), + account_id, + category_id: Some(category_id), + amount: -120_00, + date, + .. + } => *account_id == category_transfers_account_id + && *category_id == savings_category_id + && date.to_iso().get(0..10) == Some("2024-10-23"), + _ => false, + } +} + +fn matches_category_transfer_child_in_transaction( + t: &ActualbudgetTransaction, + accounts: &HashMap<String, ActualbudgetAccount>, + categories: &HashMap<String, ActualbudgetCategory>, +) -> bool { + let category_transfers_account_id = accounts + .get(ACCOUNT_NAMES_DICT.transfers_account) + .expect("failed to find transfers account") + .id + .clone(); + + let savings_category_id = categories + .get(CATEGORY_NAMES_DICT.general) + .expect("failed to find general category") + .id + .clone(); + + match t { + ActualbudgetTransaction { + is_parent: false, + is_child: true, + parent_id: Some(_), + account_id, + category_id: Some(category_id), + amount: 120_00, + date, + .. + } => *account_id == category_transfers_account_id + && *category_id == savings_category_id + && date.to_iso().get(0..10) == Some("2024-10-23"), + _ => false, + } +} + +fn matches_account_transfer_out_transaction( + t: &ActualbudgetTransaction, + accounts: &HashMap<String, ActualbudgetAccount>, + _categories: &HashMap<String, ActualbudgetCategory>, +) -> bool { + let bank_account_id = accounts + .get(ACCOUNT_NAMES_DICT.bank_account) + .expect("failed to find bank account") + .id + .clone(); + + match t { + ActualbudgetTransaction { + is_parent: false, + is_child: false, + parent_id: None, + account_id, + category_id: None, + amount: -80_00, + date, + .. + } => *account_id == bank_account_id + && date.to_iso().get(0..10) == Some("2024-09-10"), + _ => false, + } +} + +fn matches_account_transfer_in_transaction( + t: &ActualbudgetTransaction, + accounts: &HashMap<String, ActualbudgetAccount>, + _categories: &HashMap<String, ActualbudgetCategory>, +) -> bool { + let cash_account_id = accounts + .get(ACCOUNT_NAMES_DICT.cash_account) + .expect("failed to find cash account") + .id + .clone(); + + match t { + ActualbudgetTransaction { + is_parent: false, + is_child: false, + parent_id: None, + account_id, + category_id: None, + amount: 80_00, + date, + .. + } => *account_id == cash_account_id + && date.to_iso().get(0..10) == Some("2024-09-10"), + _ => false, + } +} diff --git a/actualbudget_queries/tests/common/zero_budget_matchers.rs b/actualbudget_queries/tests/common/zero_budget_matchers.rs new file mode 100644 index 0000000..ac88d3b --- /dev/null +++ b/actualbudget_queries/tests/common/zero_budget_matchers.rs @@ -0,0 +1,285 @@ +use std::collections::HashMap; + +use actualbudget_models::{ActualbudgetCategory, ActualbudgetZeroBudget}; + +use super::category_names::CATEGORY_NAMES_DICT; + +pub fn get_zero_budget_matchers() -> Vec<Box<dyn Fn(&ActualbudgetZeroBudget, &HashMap<String, ActualbudgetCategory>) -> bool>> { + vec![ + Box::new(|t, c| matches_food_budget(t, c, "08")), + Box::new(|t, c| matches_food_budget(t, c, "09")), + Box::new(|t, c| matches_food_budget(t, c, "10")), + Box::new(|t, c| matches_food_budget(t, c, "11")), + Box::new(|t, c| matches_zero_food_budget(t, c, "12")), + Box::new(|t, c| matches_general_budget(t, c, "08")), + Box::new(|t, c| matches_general_budget(t, c, "09")), + Box::new(|t, c| matches_general_budget(t, c, "10")), + Box::new(|t, c| matches_general_budget(t, c, "11")), + Box::new(|t, c| matches_zero_general_budget(t, c, "12")), + Box::new(|t, c| matches_bills_budget(t, c, "08")), + Box::new(|t, c| matches_bills_budget(t, c, "09")), + Box::new(|t, c| matches_bills_budget(t, c, "10")), + Box::new(|t, c| matches_bills_budget(t, c, "11")), + Box::new(|t, c| matches_zero_bills_budget(t, c, "12")), + Box::new(|t, c| matches_bills_flexible_budget(t, c, "08")), + Box::new(|t, c| matches_bills_flexible_budget(t, c, "09")), + Box::new(|t, c| matches_bills_flexible_budget(t, c, "10")), + Box::new(|t, c| matches_bills_flexible_budget(t, c, "11")), + Box::new(|t, c| matches_zero_bills_flexible_budget(t, c, "12")), + Box::new(|t, c| matches_savings_budget(t, c, "08")), + Box::new(|t, c| matches_savings_budget(t, c, "09")), + Box::new(|t, c| matches_savings_budget(t, c, "10")), + Box::new(|t, c| matches_savings_budget(t, c, "11")), + Box::new(|t, c| matches_zero_savings_budget(t, c, "12")), + ] +} + +fn matches_food_budget( + t: &ActualbudgetZeroBudget, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let food_category_id = categories + .get(CATEGORY_NAMES_DICT.food) + .expect("failed to find food category") + .id + .clone(); + + match t { + ActualbudgetZeroBudget { + month: date, + category_id, + amount: 200_00, + do_carry_over: false, + .. + } => + *category_id == food_category_id + && date.month() == month, + _ => false, + } +} + +fn matches_zero_food_budget( + t: &ActualbudgetZeroBudget, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let food_category_id = categories + .get(CATEGORY_NAMES_DICT.food) + .expect("failed to find food category") + .id + .clone(); + + match t { + ActualbudgetZeroBudget { + month: date, + category_id, + amount: 0, + do_carry_over: false, + .. + } => + *category_id == food_category_id + && date.month() == month, + _ => false, + } +} + +fn matches_general_budget( + t: &ActualbudgetZeroBudget, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let general_category_id = categories + .get(CATEGORY_NAMES_DICT.general) + .expect("failed to find general category") + .id + .clone(); + + match t { + ActualbudgetZeroBudget { + month: date, + category_id, + amount: 100_00, + do_carry_over: false, + .. + } => + *category_id == general_category_id + && date.month() == month, + _ => false, + } +} + +fn matches_zero_general_budget( + t: &ActualbudgetZeroBudget, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let general_category_id = categories + .get(CATEGORY_NAMES_DICT.general) + .expect("failed to find general category") + .id + .clone(); + + match t { + ActualbudgetZeroBudget { + month: date, + category_id, + amount: 0, + do_carry_over: false, + .. + } => + *category_id == general_category_id + && date.month() == month, + _ => false, + } +} + +fn matches_bills_budget( + t: &ActualbudgetZeroBudget, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let bills_category_id = categories + .get(CATEGORY_NAMES_DICT.bills) + .expect("failed to find bills category") + .id + .clone(); + + match t { + ActualbudgetZeroBudget { + month: date, + category_id, + amount: 125_00, + do_carry_over: false, + .. + } => + *category_id == bills_category_id + && date.month() == month, + _ => false, + } +} + +fn matches_zero_bills_budget( + t: &ActualbudgetZeroBudget, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let bills_category_id = categories + .get(CATEGORY_NAMES_DICT.bills) + .expect("failed to find bills category") + .id + .clone(); + + match t { + ActualbudgetZeroBudget { + month: date, + category_id, + amount: 0, + do_carry_over: false, + .. + } => + *category_id == bills_category_id + && date.month() == month, + _ => false, + } +} + +fn matches_bills_flexible_budget( + t: &ActualbudgetZeroBudget, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let bills_flexible_category_id = categories + .get(CATEGORY_NAMES_DICT.bills_flexible) + .expect("failed to find bills (flexible) category") + .id + .clone(); + + match t { + ActualbudgetZeroBudget { + month: date, + category_id, + amount: 25_00, + do_carry_over: false, + .. + } => + *category_id == bills_flexible_category_id + && date.month() == month, + _ => false, + } +} + +fn matches_zero_bills_flexible_budget( + t: &ActualbudgetZeroBudget, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let bills_flexible_category_id = categories + .get(CATEGORY_NAMES_DICT.bills_flexible) + .expect("failed to find bills (flexible) category") + .id + .clone(); + + match t { + ActualbudgetZeroBudget { + month: date, + category_id, + amount: 0, + do_carry_over: false, + .. + } => + *category_id == bills_flexible_category_id + && date.month() == month, + _ => false, + } +} + +fn matches_savings_budget( + t: &ActualbudgetZeroBudget, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let savings_category_id = categories + .get(CATEGORY_NAMES_DICT.savings) + .expect("failed to find savings category") + .id + .clone(); + + match t { + ActualbudgetZeroBudget { + month: date, + category_id, + amount: 400_00, + do_carry_over: false, + .. + } => + *category_id == savings_category_id + && date.month() == month, + _ => false, + } +} + +fn matches_zero_savings_budget( + t: &ActualbudgetZeroBudget, + categories: &HashMap<String, ActualbudgetCategory>, + month: &str, +) -> bool { + let savings_category_id = categories + .get(CATEGORY_NAMES_DICT.savings) + .expect("failed to find savings category") + .id + .clone(); + + match t { + ActualbudgetZeroBudget { + month: date, + category_id, + amount: 0, + do_carry_over: false, + .. + } => + *category_id == savings_category_id + && date.month() == month, + _ => false, + } +} diff --git a/actualbudget_queries/tests/resources/actualbudget_test_db.sqlite b/actualbudget_queries/tests/resources/actualbudget_test_db.sqlite Binary files differnew file mode 100644 index 0000000..4146bb0 --- /dev/null +++ b/actualbudget_queries/tests/resources/actualbudget_test_db.sqlite diff --git a/actualbudget_queries/tests/resources/actualbudget_test_db_metadata.json b/actualbudget_queries/tests/resources/actualbudget_test_db_metadata.json new file mode 100644 index 0000000..4d83f81 --- /dev/null +++ b/actualbudget_queries/tests/resources/actualbudget_test_db_metadata.json @@ -0,0 +1 @@ +{"id":"My-Finances-1-36ec11a","budgetName":"My Finances 1","userId":"fec9ba17-c260-4f55-8d44-676ef0ec5da9","lastScheduleRun":"2024-11-21","resetClock":true}
\ No newline at end of file |
