Fixed unit tests.

This commit is contained in:
didier amyot committed 2023-04-13 08:30:47 -04:00
1 parent 1f05ae1957
commit 80153dd6ad
3 files changed
+78 -26

No files matched your search

+1
View File
@@ -3,3 +3,4 @@
/*.sqlite /*.sqlite
/result /result
/.idea /.idea
.tmp
+3 -1
View File
@@ -41,7 +41,9 @@
pre-commit pre-commit
rustPackages.clippy rustPackages.clippy
cargo-tarpaulin cargo-tarpaulin
deno]; deno
foreman
postgresql];
RUST_SRC_PATH = rustPlatform.rustLibSrc; RUST_SRC_PATH = rustPlatform.rustLibSrc;
}; };
}); });
+74 -25
View File
@@ -1,12 +1,12 @@
use fraction::Fraction; use fraction::Fraction;
use rusqlite::{params, Connection, OptionalExtension, Result, Row}; use rusqlite::{params, Connection, ErrorCode, OptionalExtension, Result, Row};
use crate::db::_external_id::{AccountId, Id, UserId}; use crate::db::_external_id::{AccountId, Id, UserId};
use crate::db::_securities::Security; use crate::db::_securities::Security;
use crate::db::external_id::SecurityId; use crate::db::external_id::SecurityId;
use crate::util::{CustomResult, Error};
use crate::util::Error::FuckingError; use crate::util::Error::FuckingError;
use crate::util::{CustomResult, Error};
#[derive(Debug)] #[derive(Debug)]
pub enum AccountType { pub enum AccountType {
@@ -15,7 +15,6 @@ pub enum AccountType {
} }
impl AccountType { impl AccountType {
fn from_string(s: &String) -> Option<AccountType> { fn from_string(s: &String) -> Option<AccountType> {
if s == "security_emitter" { if s == "security_emitter" {
Some(AccountType::SecurityEmitter) Some(AccountType::SecurityEmitter)
@@ -46,7 +45,8 @@ impl ToString for AccountType{
match self { match self {
AccountType::Checking => "checking", AccountType::Checking => "checking",
AccountType::SecurityEmitter => "security_emitter", AccountType::SecurityEmitter => "security_emitter",
}.to_string() }
.to_string()
} }
} }
@@ -117,7 +117,6 @@ impl Clone for Account{
account_type: self.account_type.clone(), account_type: self.account_type.clone(),
label: self.label.clone(), label: self.label.clone(),
} }
} }
} }
#[derive(Debug)] #[derive(Debug)]
@@ -237,7 +236,10 @@ pub fn get_account_by_id(tx: &Connection, id: &AccountId) -> CustomResult<Accoun
.map_err(Error::SqlError); .map_err(Error::SqlError);
} }
pub fn get_checking_accounts_for_sec_id(tx: &Connection, sec_id: &SecurityId) -> CustomResult<Vec<Account>> { pub fn get_checking_accounts_for_sec_id(
tx: &Connection,
sec_id: &SecurityId,
) -> CustomResult<Vec<Account>> {
let q = " let q = "
SELECT acc.id AS acc_id, SELECT acc.id AS acc_id,
acc.amount AS acc_amount, acc.amount AS acc_amount,
@@ -260,7 +262,6 @@ pub fn get_checking_accounts_for_sec_id(tx: &Connection, sec_id: &SecurityId) ->
.map(Result::unwrap) .map(Result::unwrap)
.collect(); .collect();
return Ok(ret); return Ok(ret);
} }
fn create_account( fn create_account(
@@ -353,7 +354,7 @@ impl AccountChangeReceipt {
amount: row.get("amount")?, amount: row.get("amount")?,
timestamp: row.get("timestamp")?, timestamp: row.get("timestamp")?,
security_id: SecurityId::from_id(row.get("security_id")?), security_id: SecurityId::from_id(row.get("security_id")?),
account_type: AccountType::from_row(row)? account_type: AccountType::from_row(row)?,
}) })
} }
} }
@@ -373,6 +374,13 @@ fn update_account_history(tx: &Connection, account_id: &AccountId) -> CustomResu
Ok(()) Ok(())
} }
fn is_invalid_amount_error(e: &rusqlite::Error) -> bool {
match e {
rusqlite::Error::SqliteFailure(uf, _) => uf.code == ErrorCode::ConstraintViolation,
_ => false,
}
}
/// Super low level functions that needs to be wrapped in something else. /// Super low level functions that needs to be wrapped in something else.
/// ///
/// This method does NOT guarantee that all amount added into an account /// This method does NOT guarantee that all amount added into an account
@@ -398,16 +406,23 @@ pub fn add_to_account(
security AS security_id security AS security_id
"; ";
let params = params![amount, account_id]; let params = params![amount, account_id];
let ret = tx let res = tx.query_row(q, params, AccountChangeReceipt::from_row);
.query_row(q, params, AccountChangeReceipt::from_row) let ret = res.map_err(|e| {
.map_err(Error::SqlError); if is_invalid_amount_error(&e) {
Error::InvalidAmount(format!("Invalid value {:} added to account {:}", amount, account_id))
} else {
Error::SqlError(e)
}
})?;
update_account_history(tx, account_id)?; update_account_history(tx, account_id)?;
return ret; return Ok(ret);
} }
pub fn get_number_of_accounts(tx: &Connection, pub fn get_number_of_accounts(
tx: &Connection,
sec: &SecurityId, sec: &SecurityId,
account_type: AccountType) -> CustomResult<i64>{ account_type: AccountType,
) -> CustomResult<i64> {
let q = " let q = "
SELECT COUNT(*) AS count SELECT COUNT(*) AS count
FROM accounts FROM accounts
@@ -415,15 +430,15 @@ pub fn get_number_of_accounts(tx: &Connection,
AND account_type = ? AND account_type = ?
"; ";
let params = params![sec, account_type.to_string()]; let params = params![sec, account_type.to_string()];
tx.query_row(q, params, |row| row.get("count")).map_err(Error::SqlError) tx.query_row(q, params, |row| row.get("count"))
.map_err(Error::SqlError)
} }
/// Market cap is computer by summing the security emitter accounts. /// Market cap is computer by summing the security emitter accounts.
/// We use this technique because the sum of the security /// We use this technique because the sum of the security
/// emitter accounts MUST equals (more or less very tiny interest /// emitter accounts MUST equals (more or less very tiny interest
/// amounts) the sum of the checking accounts. /// amounts) the sum of the checking accounts.
pub fn get_security_market_cap(tx: &Connection, pub fn get_security_market_cap(tx: &Connection, sec: &SecurityId) -> CustomResult<i64> {
sec: &SecurityId) -> CustomResult<i64> {
let q = " let q = "
SELECT COALESCE(-1 * SUM(amount), 0) AS count SELECT COALESCE(-1 * SUM(amount), 0) AS count
FROM accounts FROM accounts
@@ -431,7 +446,8 @@ pub fn get_security_market_cap(tx: &Connection,
AND account_type = ? AND account_type = ?
"; ";
let params = params![sec, AccountType::SecurityEmitter.to_string()]; let params = params![sec, AccountType::SecurityEmitter.to_string()];
tx.query_row(q, params, |row| row.get("count")).map_err(Error::SqlError) tx.query_row(q, params, |row| row.get("count"))
.map_err(Error::SqlError)
} }
#[cfg(test)] #[cfg(test)]
@@ -475,7 +491,6 @@ mod test_accounts {
fn assert_test_account_type_to_string_and_from_row_works(account_type: AccountType) { fn assert_test_account_type_to_string_and_from_row_works(account_type: AccountType) {
let serialized = account_type.to_string(); let serialized = account_type.to_string();
assert_eq!(AccountType::from_string(&serialized).unwrap(), account_type); assert_eq!(AccountType::from_string(&serialized).unwrap(), account_type);
} }
#[test] #[test]
@@ -492,10 +507,12 @@ mod test_accounts {
let sec = secs.get(0).unwrap(); let sec = secs.get(0).unwrap();
let tx = conn.transaction().unwrap(); let tx = conn.transaction().unwrap();
let acc = create_checking_account(&tx, let acc = create_checking_account(
&tx,
&sec.id(), &sec.id(),
&user.id(), &user.id(),
&format!("Account for {:} in {:}", sec.id(), user.id()))?; &format!("Account for {:} in {:}", sec.id(), user.id()),
)?;
assert_eq!(acc.account_type, AccountType::Checking); assert_eq!(acc.account_type, AccountType::Checking);
assert_eq!(0, acc.raw_amount()); assert_eq!(0, acc.raw_amount());
@@ -608,6 +625,20 @@ mod test_accounts {
Ok(()) Ok(())
} }
#[test]
fn test_add_to_account_unfounded_err() -> CustomResult<()> {
let (mut conn, users, secs) = setup();
let sec = secs.get(0).unwrap().id();
let user = users.get(0).unwrap().id();
// let sec_emitter_acc = create_security_emitter_account(&conn, &sec, &user, & "sec emitter acc".to_string())?;
let checking_account =
create_checking_account(&conn, &sec, &user, &"checking acc".to_string())?;
match add_to_account(&conn, &checking_account.id(), -33) {
Err(Error::InvalidAmount(_)) => Ok(()),
_ => Err(Error::Testing("Expected InvalidAmount error".to_string()))
}
}
#[test] #[test]
fn test_list_user_accounts() -> CustomResult<()> { fn test_list_user_accounts() -> CustomResult<()> {
let (mut conn, users, secs) = setup(); let (mut conn, users, secs) = setup();
@@ -629,11 +660,24 @@ mod test_accounts {
let n = get_number_of_accounts(&conn, &secs.get(0).unwrap().id(), AccountType::Checking)?; let n = get_number_of_accounts(&conn, &secs.get(0).unwrap().id(), AccountType::Checking)?;
assert_eq!(n, 2); assert_eq!(n, 2);
let n = get_number_of_accounts(&conn, &secs.get(0).unwrap().id(), AccountType::SecurityEmitter)?; let n = get_number_of_accounts(
&conn,
&secs.get(0).unwrap().id(),
AccountType::SecurityEmitter,
)?;
assert_eq!(n, 0); assert_eq!(n, 0);
create_security_emitter_account(&conn, &secs.get(0).unwrap().id(), &users.get(0).unwrap().id(), &"".to_string())?; create_security_emitter_account(
let n = get_number_of_accounts(&conn, &secs.get(0).unwrap().id(), AccountType::SecurityEmitter)?; &conn,
&secs.get(0).unwrap().id(),
&users.get(0).unwrap().id(),
&"".to_string(),
)?;
let n = get_number_of_accounts(
&conn,
&secs.get(0).unwrap().id(),
AccountType::SecurityEmitter,
)?;
assert_eq!(n, 1); assert_eq!(n, 1);
Ok(()) Ok(())
} }
@@ -643,7 +687,12 @@ mod test_accounts {
let (mut conn, users, secs) = setup(); let (mut conn, users, secs) = setup();
let accounts = create_all_accounts(&conn, &users, &secs.get(0..1).unwrap().to_vec())?; let accounts = create_all_accounts(&conn, &users, &secs.get(0..1).unwrap().to_vec())?;
let sec_id = &secs.get(0).unwrap().id(); let sec_id = &secs.get(0).unwrap().id();
let sec_emitter = create_security_emitter_account(&conn, sec_id, &users.get(0).unwrap().id(), &"".to_string())?; let sec_emitter = create_security_emitter_account(
&conn,
sec_id,
&users.get(0).unwrap().id(),
&"".to_string(),
)?;
let n = get_security_market_cap(&conn, sec_id)?; let n = get_security_market_cap(&conn, sec_id)?;
assert_eq!(n, 0); assert_eq!(n, 0);