vesys-bank-server/bank/src/account.rs

147 lines
3.1 KiB
Rust

use std::hash::{Hash, Hasher};
use thiserror::Error;
use uuid::Uuid;
#[derive(Error, Debug)]
pub enum AccountError {
#[error("can not overdraw account")]
Overdraw,
#[error("account is inactive")]
Inactive,
#[error("amount must be > 0")]
InvalidAmount,
#[error("account does not exist")]
NotFound,
#[error("account still has a balance")]
AccountNotZero,
}
#[derive(Debug, Clone)]
pub struct Account {
pub number: String,
pub owner: String,
pub balance: f64,
pub is_active: bool,
}
impl Default for Account {
fn default() -> Self {
Account {
number: Uuid::new_v4().to_string(),
owner: "".into(),
balance: 0_f64,
is_active: true,
}
}
}
impl PartialEq for Account {
fn eq(&self, other: &Self) -> bool {
self.number == other.number
}
}
impl Eq for Account {}
impl Hash for Account {
fn hash<H: Hasher>(&self, state: &mut H) {
self.number.hash(state);
}
}
impl Account {
#[cfg(test)]
pub fn new() -> Self {
Self {
..Default::default()
}
}
pub fn deposit(&mut self, amount: f64) -> Result<f64, AccountError> {
self.check_account(amount)?;
self.balance += amount;
Ok(self.balance)
}
pub fn withdraw(&mut self, amount: f64) -> Result<f64, AccountError> {
self.check_account(amount)?;
if self.balance - amount < 0 as f64 {
return Err(AccountError::Overdraw);
}
self.balance -= amount;
Ok(self.balance)
}
fn check_account(&self, amount: f64) -> Result<(), AccountError> {
if !self.is_active {
return Err(AccountError::Inactive);
}
if amount < 0 as f64 {
return Err(AccountError::InvalidAmount);
}
Ok(())
}
pub fn passivate(&mut self) -> bool {
let is_passivated = self.balance <= 0 as f64 && self.is_active;
if is_passivated {
self.is_active = false;
}
is_passivated
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deposits() {
let mut acc = Account::new();
let ok_result = acc.deposit(10.56);
assert!(ok_result.is_ok());
let err_result = acc.deposit(-5.89);
assert!(err_result.is_err());
}
#[test]
fn withdrawals() {
let mut acc = Account::new();
let ok_result1 = acc.deposit(10_f64);
assert!(ok_result1.is_ok());
let ok_result2 = acc.withdraw(5_f64);
assert!(ok_result2.is_ok());
let err_result1 = acc.withdraw(10_f64);
assert!(err_result1.is_err());
let err_result2 = acc.withdraw(-10_f64);
assert!(err_result2.is_err());
}
#[test]
fn passivation() {
let mut acc = Account::new();
let deposit_amount = 100_f64;
acc.deposit(deposit_amount).unwrap();
assert!(!acc.passivate());
acc.withdraw(deposit_amount).unwrap();
assert!(acc.passivate());
assert!(!acc.passivate());
}
}