Skip to main content

max / makenotwork

2.9 KB · 83 lines History Blame Raw
1 //! Stripe id parsing at the boundary between our database and Stripe's API.
2 //! These ids come out of our own rows, so a parse failure means our data is
3 //! wrong, and the classification matters: `Internal` pages us, `BadRequest`
4 //! would blame the creator for our own corrupted column.
5
6 use super::*;
7
8 #[test]
9 fn account_id_parsing_rejects_nothing_at_all() {
10 // Same dead guard as `parse_subscription_id`. `stripe_shared::AccountId`
11 // derives `FromStr` with `type Err = Infallible`, so every value parses
12 // and the `Invalid Stripe account ID` branch cannot be reached. The doc
13 // comment above reasons carefully about classifying the failure as
14 // `Internal` rather than `BadRequest`; there is no failure to classify.
15 //
16 // The consequence is not academic: an empty `users.stripe_account_id`
17 // becomes an empty connected-account header on a live charge instead of
18 // an error we can see.
19 assert!(StripeClient::parse_account_id("acct_1A2b3C4d5E6f7G8h").is_ok());
20 for anything in ["", "cus_123", "not an id", "acct_"] {
21 assert!(
22 StripeClient::parse_account_id(anything).is_ok(),
23 "{anything:?} parses today; if this now fails, the guard became real \
24 and the test should assert the new contract"
25 );
26 }
27 }
28
29 // ── sum_in_currency, the filter behind `get_balance` ──
30
31 use crate::currency::SettlementCurrency;
32
33 /// The entries a connected account holding three currencies would carry.
34 fn mixed() -> Vec<(stripe_types::Currency, i64)> {
35 vec![
36 (SettlementCurrency::Usd.to_stripe(), 1_000),
37 (SettlementCurrency::Gbp.to_stripe(), 2_500),
38 (SettlementCurrency::Usd.to_stripe(), 250),
39 (SettlementCurrency::Eur.to_stripe(), 9_999),
40 ]
41 }
42
43 #[test]
44 fn sums_every_entry_in_the_wanted_currency() {
45 let entries = mixed();
46 let total = sum_in_currency(
47 entries.iter().map(|(c, a)| (c, *a)),
48 &SettlementCurrency::Usd.to_stripe(),
49 );
50 assert_eq!(total, 1_250, "both USD entries, and only those");
51 }
52
53 #[test]
54 fn ignores_every_entry_in_another_currency() {
55 let entries = mixed();
56 for currency in SettlementCurrency::ALL {
57 let total = sum_in_currency(entries.iter().map(|(c, a)| (c, *a)), &currency.to_stripe());
58 let expected = match currency {
59 SettlementCurrency::Usd => 1_250,
60 SettlementCurrency::Gbp => 2_500,
61 SettlementCurrency::Eur => 9_999,
62 _ => 0,
63 };
64 assert_eq!(
65 total, expected,
66 "{currency} must see its own money and nobody else's"
67 );
68 }
69 }
70
71 #[test]
72 fn a_currency_the_account_does_not_hold_is_zero_rather_than_everything() {
73 let entries = mixed();
74 let total = sum_in_currency(
75 entries.iter().map(|(c, a)| (c, *a)),
76 &SettlementCurrency::Nzd.to_stripe(),
77 );
78 assert_eq!(
79 total, 0,
80 "an inverted filter would report 13,749 NZD cents the account never held"
81 );
82 }
83