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,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;
|
||||
assert_eq!(expected, txs);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_csv_with_whitespaces_is_parsed() {
|
||||
block_on(async {
|
||||
@ -57,9 +64,62 @@ deposit, 1, 3, 2.0
|
||||
withdrawal, 1, 4, 1.5
|
||||
withdrawal, 2, 5, 3.0";
|
||||
|
||||
let txs = parse(data.as_bytes());
|
||||
let result: Vec<Transaction> = txs.collect::<Vec<Transaction>>().await;
|
||||
result.iter().for_each(|t| eprintln!("{:?}", t));
|
||||
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;
|
||||
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::{Deserialize, Deserializer};
|
||||
const PRECISION: u32 = 4;
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
@ -12,24 +13,31 @@ pub enum TransactionType {
|
||||
pub struct Transaction {
|
||||
#[serde(rename = "type")]
|
||||
pub tx_type: TransactionType,
|
||||
pub client: usize,
|
||||
pub client: u16,
|
||||
pub tx: usize,
|
||||
/// Amount of the smallest unit, e.g. 0.0001 as per the specification
|
||||
#[serde(deserialize_with = "de_amount")]
|
||||
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
|
||||
let deserialized = String::deserialize(deserializer)?;
|
||||
let mut splitted = deserialized.split('.');
|
||||
let mut ret: usize = 0;
|
||||
let mut factor = 4;
|
||||
while let Some(s) = splitted.next() {
|
||||
ret += s.parse::<usize>().map_err(de::Error::custom)? * 10usize.pow(factor);
|
||||
if factor < 1 { break;}
|
||||
factor -= 4;
|
||||
};
|
||||
let units = splitted
|
||||
.next()
|
||||
.map_or(Ok(0usize), |v| v.parse::<usize>())
|
||||
.map_err(de::Error::custom)?
|
||||
.checked_mul(10usize.pow(PRECISION))
|
||||
.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