use crate::{
validation::{validate_asset_text, validate_decimal_text},
Result,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PaymentAmount {
value: String,
asset: String,
}
impl PaymentAmount {
pub fn value(&self) -> &str {
&self.value
}
pub fn asset(&self) -> &str {
&self.asset
}
pub fn new(value: impl Into<String>, asset: impl Into<String>) -> Result<Self> {
Self::new_with_label(value.into(), asset.into(), "Payment Amount")
}
pub(crate) fn new_with_label(
value: String,
asset: String,
label: &'static str,
) -> Result<Self> {
let amount = Self { value, asset };
amount.validate_with_label(label)?;
Ok(amount)
}
pub(crate) fn validate_with_label(&self, label: &'static str) -> Result<()> {
validate_decimal_text(&self.value, format_args!("{label}.value"))?;
validate_asset_text(&self.asset, "Payment Amount asset")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::PaykitError;
#[test]
fn payment_amount_accepts_decimal_value_and_asset() {
let amount = PaymentAmount::new("10.00", "usd").unwrap();
assert_eq!(amount.value, "10.00");
assert_eq!(amount.asset, "usd");
}
#[test]
fn payment_amount_rejects_invalid_value() {
let err = PaymentAmount::new("ten", "usd").unwrap_err();
assert!(matches!(err, PaykitError::Validation(msg) if msg.contains("decimal string")));
}
#[test]
fn payment_amount_rejects_empty_asset() {
let err = PaymentAmount::new("10.00", "").unwrap_err();
assert!(matches!(err, PaykitError::Validation(msg) if msg.contains("must not be empty")));
}
#[test]
fn payment_amount_rejects_control_character_asset() {
let err = PaymentAmount::new("10.00", "usd\n").unwrap_err();
assert!(matches!(err, PaykitError::Validation(msg) if msg.contains("control characters")));
}
#[test]
fn payment_amount_rejects_multiple_decimal_points() {
let err = PaymentAmount::new("1.2.3", "usd").unwrap_err();
assert!(matches!(err, PaykitError::Validation(msg) if msg.contains("decimal string")));
}
#[test]
fn payment_amount_rejects_lone_decimal_point() {
let err = PaymentAmount::new(".", "usd").unwrap_err();
assert!(matches!(err, PaykitError::Validation(msg) if msg.contains("at least one digit")));
}
#[test]
fn test_payment_amount_bare_decimal_point_currently_accepted() {
let leading = PaymentAmount::new(".5", "usd").unwrap();
assert_eq!(leading.value, ".5");
let trailing = PaymentAmount::new("10.", "usd").unwrap();
assert_eq!(trailing.value, "10.");
}
}