saving
This commit is contained in:
parent
da582df6eb
commit
d837b60327
68
src/lib.rs
68
src/lib.rs
@ -41,11 +41,18 @@ deposit,1,3,2.0
|
|||||||
withdrawal,1,4,1.5
|
withdrawal,1,4,1.5
|
||||||
withdrawal,2,5,3.0";
|
withdrawal,2,5,3.0";
|
||||||
|
|
||||||
let expected = vec![Transaction {tx_type: TransactionType::Deposit, amount: 10000, client: 1, tx: 1}];
|
let expected = vec![
|
||||||
|
Transaction {tx_type: TransactionType::Deposit, amount: 10000, client: 1, tx: 1},
|
||||||
|
Transaction {tx_type: TransactionType::Deposit, amount: 20000, client: 2, tx: 2},
|
||||||
|
Transaction {tx_type: TransactionType::Deposit, amount: 20000, client: 1, tx: 3},
|
||||||
|
Transaction {tx_type: TransactionType::Withdrawal, amount: 15000, client: 1, tx: 4},
|
||||||
|
Transaction {tx_type: TransactionType::Withdrawal, amount: 30000, client: 2, tx: 5},
|
||||||
|
];
|
||||||
let txs = parse(data.as_bytes()).collect::<Vec<Transaction>>().await;
|
let txs = parse(data.as_bytes()).collect::<Vec<Transaction>>().await;
|
||||||
assert_eq!(expected, txs);
|
assert_eq!(expected, txs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn valid_csv_with_whitespaces_is_parsed() {
|
fn valid_csv_with_whitespaces_is_parsed() {
|
||||||
block_on(async {
|
block_on(async {
|
||||||
@ -57,9 +64,62 @@ deposit, 1, 3, 2.0
|
|||||||
withdrawal, 1, 4, 1.5
|
withdrawal, 1, 4, 1.5
|
||||||
withdrawal, 2, 5, 3.0";
|
withdrawal, 2, 5, 3.0";
|
||||||
|
|
||||||
let txs = parse(data.as_bytes());
|
let expected = vec![
|
||||||
let result: Vec<Transaction> = txs.collect::<Vec<Transaction>>().await;
|
Transaction {tx_type: TransactionType::Deposit, amount: 10000, client: 1, tx: 1},
|
||||||
result.iter().for_each(|t| eprintln!("{:?}", t));
|
Transaction {tx_type: TransactionType::Deposit, amount: 20000, client: 2, tx: 2},
|
||||||
|
Transaction {tx_type: TransactionType::Deposit, amount: 20000, client: 1, tx: 3},
|
||||||
|
Transaction {tx_type: TransactionType::Withdrawal, amount: 15000, client: 1, tx: 4},
|
||||||
|
Transaction {tx_type: TransactionType::Withdrawal, amount: 30000, client: 2, tx: 5},
|
||||||
|
];
|
||||||
|
let txs = parse(data.as_bytes()).collect::<Vec<Transaction>>().await;
|
||||||
|
assert_eq!(expected, txs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn amounts_are_parsed_correctly() {
|
||||||
|
block_on(async {
|
||||||
|
let data = "\
|
||||||
|
type,client,tx,amount
|
||||||
|
deposit,1,1,1.0001
|
||||||
|
deposit,2,2,2.0010
|
||||||
|
deposit,1,3,10.01
|
||||||
|
withdrawal,1,4,01.10
|
||||||
|
withdrawal,2,5,10.0110101";
|
||||||
|
|
||||||
|
let expected = vec![
|
||||||
|
Transaction {tx_type: TransactionType::Deposit, amount: 10001, client: 1, tx: 1},
|
||||||
|
Transaction {tx_type: TransactionType::Deposit, amount: 20010, client: 2, tx: 2},
|
||||||
|
Transaction {tx_type: TransactionType::Deposit, amount: 100100, client: 1, tx: 3},
|
||||||
|
Transaction {tx_type: TransactionType::Withdrawal, amount: 11000, client: 1, tx: 4},
|
||||||
|
Transaction {tx_type: TransactionType::Withdrawal, amount: 100110, client: 2, tx: 5},
|
||||||
|
];
|
||||||
|
let txs = parse(data.as_bytes()).collect::<Vec<Transaction>>().await;
|
||||||
|
assert_eq!(expected, txs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_amoutns_are_filtered() {
|
||||||
|
block_on(async {
|
||||||
|
let data = "\
|
||||||
|
type,client,tx,amount
|
||||||
|
deposit,1,1,99999999999999999
|
||||||
|
deposit,2,2,18446744073709551615
|
||||||
|
deposit,1,3,18446744073709551616
|
||||||
|
withdrawal,1,4,0
|
||||||
|
withdrawal,2,5,-1
|
||||||
|
withdrawal,1,6,-99999999999999999
|
||||||
|
withdrawal,1,6,-18446744073709551615
|
||||||
|
withdrawal,1,7,-18446744073709551616";
|
||||||
|
|
||||||
|
let expected = vec![
|
||||||
|
Transaction {tx_type: TransactionType::Withdrawal, amount: 0, client: 1, tx: 4},
|
||||||
|
];
|
||||||
|
let txs = parse(data.as_bytes()).collect::<Vec<Transaction>>().await;
|
||||||
|
println!("PARSE: {}", "0.1".parse::<f32>().unwrap());
|
||||||
|
|
||||||
|
assert_eq!(expected, txs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use serde::{Deserialize, Deserializer};
|
|
||||||
use serde::de;
|
use serde::de;
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
const PRECISION: u32 = 4;
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Deserialize)]
|
#[derive(Eq, PartialEq, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
@ -12,24 +13,31 @@ pub enum TransactionType {
|
|||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub tx_type: TransactionType,
|
pub tx_type: TransactionType,
|
||||||
pub client: usize,
|
pub client: u16,
|
||||||
pub tx: usize,
|
pub tx: usize,
|
||||||
/// Amount of the smallest unit, e.g. 0.0001 as per the specification
|
/// Amount of the smallest unit, e.g. 0.0001 as per the specification
|
||||||
#[serde(deserialize_with = "de_amount")]
|
#[serde(deserialize_with = "de_amount")]
|
||||||
pub amount: usize,
|
pub amount: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn de_amount<'de, D>(deserializer: D) -> Result<usize, D::Error> where D: Deserializer<'de> {
|
fn de_amount<'de, D>(deserializer: D) -> Result<usize, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
//TODO validate for input such as `.100` so it doesn't give 100
|
//TODO validate for input such as `.100` so it doesn't give 100
|
||||||
let deserialized = String::deserialize(deserializer)?;
|
let deserialized = String::deserialize(deserializer)?;
|
||||||
let mut splitted = deserialized.split('.');
|
let mut splitted = deserialized.split('.');
|
||||||
let mut ret: usize = 0;
|
let units = splitted
|
||||||
let mut factor = 4;
|
.next()
|
||||||
while let Some(s) = splitted.next() {
|
.map_or(Ok(0usize), |v| v.parse::<usize>())
|
||||||
ret += s.parse::<usize>().map_err(de::Error::custom)? * 10usize.pow(factor);
|
.map_err(de::Error::custom)?
|
||||||
if factor < 1 { break;}
|
.checked_mul(10usize.pow(PRECISION))
|
||||||
factor -= 4;
|
.ok_or_else(|| de::Error::custom("Value too large"))?;
|
||||||
};
|
//TODO improve this to avoid `format!`
|
||||||
|
let dec = splitted
|
||||||
|
.next()
|
||||||
|
.map_or(Ok(0usize), |v| format!("{:0<4.4}", v).parse::<usize>())
|
||||||
|
.map_err(de::Error::custom)?;
|
||||||
|
|
||||||
Ok(ret)
|
Ok(units + dec)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user