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
+97 -45

No files matched your search

+1
View File
@@ -3,3 +3,4 @@
/*.sqlite
/result
/.idea
.tmp
+3 -1
View File
@@ -41,7 +41,9 @@
pre-commit
rustPackages.clippy
cargo-tarpaulin
deno];
deno
foreman
postgresql];
RUST_SRC_PATH = rustPlatform.rustLibSrc;
};
});
+93 -44
View File
@@ -1,12 +1,12 @@
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::_securities::Security;
use crate::db::external_id::SecurityId;
use crate::util::{CustomResult, Error};
use crate::util::Error::FuckingError;
use crate::util::{CustomResult, Error};
#[derive(Debug)]
pub enum AccountType {
@@ -15,19 +15,18 @@ pub enum AccountType {
}
impl AccountType {
fn from_string(s: & String) -> Option<AccountType>{
fn from_string(s: &String) -> Option<AccountType> {
if s == "security_emitter" {
Some(AccountType::SecurityEmitter)
} else if s == "checking"{
} else if s == "checking" {
Some(AccountType::Checking)
}else{
} else {
None
}
}
pub fn from_row(row: &Row) -> Result<AccountType> {
let s: String = row.get("acc_account_type")?;
AccountType::from_string(& s).ok_or(rusqlite::Error::ExecuteReturnedResults)
AccountType::from_string(&s).ok_or(rusqlite::Error::ExecuteReturnedResults)
}
}
@@ -41,12 +40,13 @@ impl PartialEq for AccountType {
}
}
impl ToString for AccountType{
impl ToString for AccountType {
fn to_string(&self) -> String {
match self {
AccountType::Checking => "checking",
AccountType::SecurityEmitter => "security_emitter",
}.to_string()
}
.to_string()
}
}
@@ -107,9 +107,9 @@ impl Account {
}
}
impl Clone for Account{
impl Clone for Account {
fn clone(&self) -> Self {
Account{
Account {
id: self.id,
amount: self.amount,
timestamp: self.timestamp,
@@ -117,7 +117,6 @@ impl Clone for Account{
account_type: self.account_type.clone(),
label: self.label.clone(),
}
}
}
#[derive(Debug)]
@@ -192,7 +191,7 @@ pub fn list_accounts<'a>(conn: &Connection) -> CustomResult<Vec<Account>> {
return Ok(ret);
}
pub fn list_user_accounts(conn: &Connection, user_id: & UserId) -> CustomResult<Vec<Account>> {
pub fn list_user_accounts(conn: &Connection, user_id: &UserId) -> CustomResult<Vec<Account>> {
let q = "SELECT acc.id AS acc_id,
acc.amount AS acc_amount,
UNIXEPOCH(acc.timestamp) AS acc_timestamp,
@@ -237,7 +236,10 @@ pub fn get_account_by_id(tx: &Connection, id: &AccountId) -> CustomResult<Accoun
.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 = "
SELECT acc.id AS acc_id,
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)
.collect();
return Ok(ret);
}
fn create_account(
@@ -353,7 +354,7 @@ impl AccountChangeReceipt {
amount: row.get("amount")?,
timestamp: row.get("timestamp")?,
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(())
}
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.
///
/// 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
";
let params = params![amount, account_id];
let ret = tx
.query_row(q, params, AccountChangeReceipt::from_row)
.map_err(Error::SqlError);
let res = tx.query_row(q, params, AccountChangeReceipt::from_row);
let ret = res.map_err(|e| {
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)?;
return ret;
return Ok(ret);
}
pub fn get_number_of_accounts(tx: &Connection,
sec: &SecurityId,
account_type: AccountType) -> CustomResult<i64>{
pub fn get_number_of_accounts(
tx: &Connection,
sec: &SecurityId,
account_type: AccountType,
) -> CustomResult<i64> {
let q = "
SELECT COUNT(*) AS count
FROM accounts
@@ -415,15 +430,15 @@ pub fn get_number_of_accounts(tx: &Connection,
AND account_type = ?
";
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.
/// We use this technique because the sum of the security
/// emitter accounts MUST equals (more or less very tiny interest
/// amounts) the sum of the checking accounts.
pub fn get_security_market_cap(tx: &Connection,
sec: &SecurityId) -> CustomResult<i64> {
pub fn get_security_market_cap(tx: &Connection, sec: &SecurityId) -> CustomResult<i64> {
let q = "
SELECT COALESCE(-1 * SUM(amount), 0) AS count
FROM accounts
@@ -431,7 +446,8 @@ pub fn get_security_market_cap(tx: &Connection,
AND account_type = ?
";
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)]
@@ -472,14 +488,13 @@ mod test_accounts {
return Ok(ret);
}
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();
assert_eq!(AccountType::from_string(&serialized).unwrap(), account_type);
}
#[test]
fn test_account_type_to_string_and_from_row(){
fn test_account_type_to_string_and_from_row() {
assert_test_account_type_to_string_and_from_row_works(AccountType::Checking);
assert_test_account_type_to_string_and_from_row_works(AccountType::SecurityEmitter);
}
@@ -492,10 +507,12 @@ mod test_accounts {
let sec = secs.get(0).unwrap();
let tx = conn.transaction().unwrap();
let acc = create_checking_account(&tx,
&sec.id(),
&user.id(),
&format!("Account for {:} in {:}", sec.id(), user.id()))?;
let acc = create_checking_account(
&tx,
&sec.id(),
&user.id(),
&format!("Account for {:} in {:}", sec.id(), user.id()),
)?;
assert_eq!(acc.account_type, AccountType::Checking);
assert_eq!(0, acc.raw_amount());
@@ -567,7 +584,7 @@ mod test_accounts {
let tx = conn.transaction().unwrap();
let sec = secs.get(0).unwrap().id();
let user = users.get(0).unwrap().id();
let acc = create_checking_account(&tx, &sec, &user, & "acc".to_string()).unwrap();
let acc = create_checking_account(&tx, &sec, &user, &"acc".to_string()).unwrap();
let receipt = add_to_account(&tx, &acc.id(), 33)?;
assert_eq!(receipt.account_id, acc.id());
assert_eq!(receipt.amount, 33);
@@ -591,7 +608,7 @@ mod test_accounts {
let tx = conn.transaction().unwrap();
let sec = secs.get(0).unwrap().id();
let user = users.get(0).unwrap().id();
let acc = create_security_emitter_account(&tx, &sec, &user, & "acc".to_string())?;
let acc = create_security_emitter_account(&tx, &sec, &user, &"acc".to_string())?;
let receipt = add_to_account(&tx, &acc.id(), -33)?;
assert_eq!(receipt.account_id, acc.id());
@@ -608,16 +625,30 @@ mod test_accounts {
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]
fn test_list_user_accounts() -> CustomResult<()> {
let (mut conn, users, secs) = setup();
{
let tx = conn.transaction().unwrap();
create_all_accounts(& tx, &users, &secs)?;
create_all_accounts(&tx, &users, &secs)?;
tx.commit().map_err(Error::SqlError)?;
}
let res = list_user_accounts(& conn, & users[0].id())?;
let res = list_user_accounts(&conn, &users[0].id())?;
assert_eq!(res.len(), 2);
Ok(())
}
@@ -625,15 +656,28 @@ mod test_accounts {
#[test]
fn test_get_number_of_accounts() -> CustomResult<()> {
let (mut conn, users, secs) = setup();
create_all_accounts(&conn, &users, &secs)?;
create_all_accounts(&conn, &users, &secs)?;
let n = get_number_of_accounts(&conn, &secs.get(0).unwrap().id(), AccountType::Checking)?;
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);
create_security_emitter_account(&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)?;
create_security_emitter_account(
&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);
Ok(())
}
@@ -641,9 +685,14 @@ mod test_accounts {
#[test]
fn test_get_security_market_cap() -> CustomResult<()> {
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_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)?;
assert_eq!(n, 0);