Fixed unit tests.
This commit is contained in:
1 parent
1f05ae1957
commit
80153dd6ad
3 files changed
+97
-45
No files matched your search
@@ -3,3 +3,4 @@
|
|||||||
/*.sqlite
|
/*.sqlite
|
||||||
/result
|
/result
|
||||||
/.idea
|
/.idea
|
||||||
|
.tmp
|
||||||
@@ -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;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
+93
-44
@@ -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,19 +15,18 @@ 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)
|
||||||
} else if s == "checking"{
|
} else if s == "checking" {
|
||||||
Some(AccountType::Checking)
|
Some(AccountType::Checking)
|
||||||
}else{
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn from_row(row: &Row) -> Result<AccountType> {
|
pub fn from_row(row: &Row) -> Result<AccountType> {
|
||||||
let s: String = row.get("acc_account_type")?;
|
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 {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
AccountType::Checking => "checking",
|
AccountType::Checking => "checking",
|
||||||
AccountType::SecurityEmitter => "security_emitter",
|
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 {
|
fn clone(&self) -> Self {
|
||||||
Account{
|
Account {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
amount: self.amount,
|
amount: self.amount,
|
||||||
timestamp: self.timestamp,
|
timestamp: self.timestamp,
|
||||||
@@ -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)]
|
||||||
@@ -192,7 +191,7 @@ pub fn list_accounts<'a>(conn: &Connection) -> CustomResult<Vec<Account>> {
|
|||||||
return Ok(ret);
|
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,
|
let q = "SELECT acc.id AS acc_id,
|
||||||
acc.amount AS acc_amount,
|
acc.amount AS acc_amount,
|
||||||
UNIXEPOCH(acc.timestamp) AS acc_timestamp,
|
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);
|
.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(
|
||||||
sec: &SecurityId,
|
tx: &Connection,
|
||||||
account_type: AccountType) -> CustomResult<i64>{
|
sec: &SecurityId,
|
||||||
|
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)]
|
||||||
@@ -472,14 +488,13 @@ mod test_accounts {
|
|||||||
return Ok(ret);
|
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();
|
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]
|
||||||
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::Checking);
|
||||||
assert_test_account_type_to_string_and_from_row_works(AccountType::SecurityEmitter);
|
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 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(
|
||||||
&sec.id(),
|
&tx,
|
||||||
&user.id(),
|
&sec.id(),
|
||||||
&format!("Account for {:} in {:}", sec.id(), user.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());
|
||||||
|
|
||||||
@@ -567,7 +584,7 @@ mod test_accounts {
|
|||||||
let tx = conn.transaction().unwrap();
|
let tx = conn.transaction().unwrap();
|
||||||
let sec = secs.get(0).unwrap().id();
|
let sec = secs.get(0).unwrap().id();
|
||||||
let user = users.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)?;
|
let receipt = add_to_account(&tx, &acc.id(), 33)?;
|
||||||
assert_eq!(receipt.account_id, acc.id());
|
assert_eq!(receipt.account_id, acc.id());
|
||||||
assert_eq!(receipt.amount, 33);
|
assert_eq!(receipt.amount, 33);
|
||||||
@@ -591,7 +608,7 @@ mod test_accounts {
|
|||||||
let tx = conn.transaction().unwrap();
|
let tx = conn.transaction().unwrap();
|
||||||
let sec = secs.get(0).unwrap().id();
|
let sec = secs.get(0).unwrap().id();
|
||||||
let user = users.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)?;
|
let receipt = add_to_account(&tx, &acc.id(), -33)?;
|
||||||
assert_eq!(receipt.account_id, acc.id());
|
assert_eq!(receipt.account_id, acc.id());
|
||||||
@@ -608,16 +625,30 @@ 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();
|
||||||
{
|
{
|
||||||
let tx = conn.transaction().unwrap();
|
let tx = conn.transaction().unwrap();
|
||||||
create_all_accounts(& tx, &users, &secs)?;
|
create_all_accounts(&tx, &users, &secs)?;
|
||||||
tx.commit().map_err(Error::SqlError)?;
|
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);
|
assert_eq!(res.len(), 2);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -625,15 +656,28 @@ mod test_accounts {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_get_number_of_accounts() -> CustomResult<()> {
|
fn test_get_number_of_accounts() -> CustomResult<()> {
|
||||||
let (mut conn, users, secs) = setup();
|
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)?;
|
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(())
|
||||||
}
|
}
|
||||||
@@ -641,9 +685,14 @@ mod test_accounts {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_get_security_market_cap() -> CustomResult<()> {
|
fn test_get_security_market_cap() -> CustomResult<()> {
|
||||||
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);
|
||||||
|
|||||||
Reference in new issue
Block a user