feat(core): flesh out CardCore + CardKind
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,25 @@
|
|||||||
|
//! Card: number, holder, expiry (MonthYear), CVV, PIN, kind.
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
|
use crate::time::MonthYear;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
pub struct CardCore {}
|
pub struct CardCore {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub number: Option<Zeroizing<String>>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub holder: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub expiry: Option<MonthYear>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub cvv: Option<Zeroizing<String>>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub pin: Option<Zeroizing<String>>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub kind: CardKind,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
@@ -13,3 +31,38 @@ pub enum CardKind {
|
|||||||
Loyalty,
|
Loyalty,
|
||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn card_full_round_trip() {
|
||||||
|
let card = CardCore {
|
||||||
|
number: Some(Zeroizing::new("4111111111111111".into())),
|
||||||
|
holder: Some("Alice Doe".into()),
|
||||||
|
expiry: Some(MonthYear::new(12, 2030).unwrap()),
|
||||||
|
cvv: Some(Zeroizing::new("123".into())),
|
||||||
|
pin: Some(Zeroizing::new("0000".into())),
|
||||||
|
kind: CardKind::Credit,
|
||||||
|
};
|
||||||
|
let json = serde_json::to_string(&card).unwrap();
|
||||||
|
let parsed: CardCore = serde_json::from_str(&json).unwrap();
|
||||||
|
assert_eq!(parsed.holder.as_deref(), Some("Alice Doe"));
|
||||||
|
assert_eq!(parsed.kind, CardKind::Credit);
|
||||||
|
assert_eq!(parsed.expiry, Some(MonthYear::new(12, 2030).unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn card_kind_default_is_credit() {
|
||||||
|
let json = "{}";
|
||||||
|
let card: CardCore = serde_json::from_str(json).unwrap();
|
||||||
|
assert_eq!(card.kind, CardKind::Credit);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn card_kind_serializes_snake_case() {
|
||||||
|
let json = serde_json::to_string(&CardKind::Loyalty).unwrap();
|
||||||
|
assert_eq!(json, "\"loyalty\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user