-
Notifications
You must be signed in to change notification settings - Fork 57
fix(yadio): canonicalise currency codes to uppercase #896
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,7 +47,9 @@ impl YadioProvider { | |
| .btc | ||
| .into_iter() | ||
| .filter_map(|(code, value)| match value { | ||
| Some(v) if v.is_finite() && v > 0.0 => Some((code, Quote::PerBtc(v))), | ||
| Some(v) if v.is_finite() && v > 0.0 => { | ||
| Some((code.to_uppercase(), Quote::PerBtc(v))) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity | 🟡 Minor | 📋 Context for the maintainer Re: CodeRabbit's duplicate-key comment — here is what the change actually does to that case, which its analysis stops short of. Not a request for a change in this PR; posting because the finding above it is CodeRabbit is right that 🔍 Pre-PR path for a case-variant duplicateBoth keys survived the adapter, then let currency = currency.to_uppercase();
match quote {
Quote::PerBtc(v) => direct.entry(currency).or_default().push((*id, *v)),Consequences, both real:
This is the same class of bug #859 documents as already having been hit once, in So the change trades a deterministic double-count for a nondeterministic pick. On Which is why I would not block on it: fixing collision precedence in this one
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Consistency & Maintainability | 🔵 Nit | 🧷 Do not change in this PR
ISO-4217 codes are ASCII by definition, and Neither cost is worth acting on here, because the four siblings Flagging it so it is on the record: if it is ever revisited, all five change |
||
| } | ||
| _ => None, | ||
| }) | ||
| .collect()) | ||
|
|
@@ -111,6 +113,18 @@ mod tests { | |
| assert_eq!(quotes.get("GBP"), Some(&Quote::PerBtc(50_000.0))); | ||
| } | ||
|
|
||
| #[test] | ||
| fn canonicalises_lowercase_currency_codes() { | ||
| let body = r#"{"BTC": {"usd": 75000.0, "eur": 65000.0}}"#; | ||
| let quotes = YadioProvider::parse(body).unwrap(); | ||
| assert_eq!(quotes.get("USD"), Some(&Quote::PerBtc(75_000.0))); | ||
| assert_eq!(quotes.get("EUR"), Some(&Quote::PerBtc(65_000.0))); | ||
| assert!( | ||
| !quotes.contains_key("usd"), | ||
| "raw lowercase key must not survive" | ||
| ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Test Precision | 🔵 Nit | ⚡ Quick win Pin the map size, and cover mixed case. CodeRabbit already asked for the missing assert_eq!(quotes.len(), 2, "only the two canonical keys survive");Separately, an all-lowercase input is the weakest possible probe for this fix. let body = r#"{"BTC": {"usd": 75000.0, "Eur": 65000.0}}"#;This is a nit — the fix is a stdlib call, so the risk of it being wrong is ~0. It
Comment on lines
+125
to
+128
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Test Precision | 🔵 Nit | ⚡ Quick win This assertion is now dead weight — the size assertion you added on line 122 already proves it. assert_eq!(quotes.len(), 2, "only the two canonical keys survive");
assert_eq!(quotes.get("USD"), Some(&Quote::PerBtc(75_000.0)));
assert_eq!(quotes.get("EUR"), Some(&Quote::PerBtc(65_000.0)));Three assertions pin the map to exactly That is precisely why the size form was suggested over CodeRabbit's Your call: if you prefer to keep it as executable prose naming the bug the |
||
| } | ||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| #[test] | ||
| fn parse_error_is_returned() { | ||
| let err = YadioProvider::parse("not json").unwrap_err(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Consistency & Maintainability | 🔵 Nit | ⚡ Quick win
Add the "why" comment — every sibling that canonicalises carries one, and Yadio is the case that most needs it.
The four adapters that already do this each explain themselves at the call site:
blockchain.rs// Codes arrive uppercase already; canonicalise anyway so the adapter honours §6.6 even if the API drifts.coingecko.rs// CoinGecko ships lowercase codes — canonicalise (§6.6).currency_api.rs// currency-api ships lowercase codes — canonicalise (§6.6).yadio.rsblockchain.rsis the exact analogue — upstream ships uppercase there too — and#859 quoted its comment as the model for this fix precisely because, without it,
the next reader sees a
to_uppercase()on data that is already uppercase and hasno way to tell it is deliberate rather than redundant. That is also what makes the
rustfmt-forced block form here read as arbitrary; the comment justifies the braces.
💡 Suggested change
The module header would carry it well too —
coingecko.rs:5andcurrency_api.rs:15both state the casing contract in//!docs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i just made the suggested changes
Thank you