|
4 | 4 | // SPDX-License-Identifier: AGPL-3.0-only |
5 | 5 | // Please see LICENSE in the repository root for full details. |
6 | 6 |
|
7 | | -use std::{borrow::Cow, collections::HashMap}; |
| 7 | +use std::borrow::Cow; |
8 | 8 |
|
9 | 9 | use chrono::Duration; |
| 10 | +use indexmap::IndexMap; |
10 | 11 | use language_tags::LanguageTag; |
11 | 12 | use mas_iana::{ |
12 | 13 | jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg}, |
@@ -45,18 +46,18 @@ impl<T> Localized<T> { |
45 | 46 | } |
46 | 47 |
|
47 | 48 | fn deserialize( |
48 | | - map: &mut HashMap<String, HashMap<Option<LanguageTag>, Value>>, |
| 49 | + map: &mut IndexMap<String, IndexMap<Option<LanguageTag>, Value>>, |
49 | 50 | field_name: &'static str, |
50 | 51 | ) -> Result<Option<Self>, serde_json::Error> |
51 | 52 | where |
52 | 53 | T: DeserializeOwned, |
53 | 54 | { |
54 | | - let Some(map) = map.remove(field_name) else { |
| 55 | + let Some(map) = map.shift_remove(field_name) else { |
55 | 56 | return Ok(None); |
56 | 57 | }; |
57 | 58 |
|
58 | 59 | let mut non_localized = None; |
59 | | - let mut localized = HashMap::with_capacity(map.len() - 1); |
| 60 | + let mut localized = IndexMap::with_capacity(map.len() - 1); |
60 | 61 |
|
61 | 62 | for (k, v) in map { |
62 | 63 | let value = serde_json::from_value(v)?; |
@@ -347,8 +348,8 @@ impl<'de> Deserialize<'de> for ClientMetadataLocalizedFields { |
347 | 348 | where |
348 | 349 | D: serde::Deserializer<'de>, |
349 | 350 | { |
350 | | - let map = HashMap::<Cow<'de, str>, Value>::deserialize(deserializer)?; |
351 | | - let mut new_map: HashMap<String, HashMap<Option<LanguageTag>, Value>> = HashMap::new(); |
| 351 | + let map = IndexMap::<Cow<'de, str>, Value>::deserialize(deserializer)?; |
| 352 | + let mut new_map: IndexMap<String, IndexMap<Option<LanguageTag>, Value>> = IndexMap::new(); |
352 | 353 |
|
353 | 354 | for (k, v) in map { |
354 | 355 | let (prefix, lang) = if let Some((prefix, lang)) = k.split_once('#') { |
@@ -389,6 +390,8 @@ impl<'de> Deserialize<'de> for ClientMetadataLocalizedFields { |
389 | 390 |
|
390 | 391 | #[cfg(test)] |
391 | 392 | mod tests { |
| 393 | + use insta::assert_yaml_snapshot; |
| 394 | + |
392 | 395 | use super::*; |
393 | 396 |
|
394 | 397 | #[test] |
@@ -461,16 +464,28 @@ mod tests { |
461 | 464 | .validate() |
462 | 465 | .unwrap(); |
463 | 466 |
|
464 | | - assert_eq!( |
465 | | - serde_json::to_value(metadata).unwrap(), |
466 | | - serde_json::json!({ |
467 | | - "redirect_uris": ["http://localhost/oidc"], |
468 | | - "client_name": "Postbox", |
469 | | - "client_name#fr": "Boîte à lettres", |
470 | | - "client_uri": "https://localhost/", |
471 | | - "client_uri#fr": "https://localhost/fr", |
472 | | - "client_uri#de": "https://localhost/de", |
473 | | - }) |
474 | | - ); |
| 467 | + assert_yaml_snapshot!(metadata, @r###" |
| 468 | + redirect_uris: |
| 469 | + - "http://localhost/oidc" |
| 470 | + client_name: Postbox |
| 471 | + "client_name#fr": Boîte à lettres |
| 472 | + client_uri: "https://localhost/" |
| 473 | + "client_uri#fr": "https://localhost/fr" |
| 474 | + "client_uri#de": "https://localhost/de" |
| 475 | + "###); |
| 476 | + |
| 477 | + // Do a roundtrip, we should get the same metadata back with the same order |
| 478 | + let metadata: ClientMetadata = |
| 479 | + serde_json::from_value(serde_json::to_value(metadata).unwrap()).unwrap(); |
| 480 | + let metadata = metadata.validate().unwrap(); |
| 481 | + assert_yaml_snapshot!(metadata, @r###" |
| 482 | + redirect_uris: |
| 483 | + - "http://localhost/oidc" |
| 484 | + client_name: Postbox |
| 485 | + "client_name#fr": Boîte à lettres |
| 486 | + client_uri: "https://localhost/" |
| 487 | + "client_uri#fr": "https://localhost/fr" |
| 488 | + "client_uri#de": "https://localhost/de" |
| 489 | + "###); |
475 | 490 | } |
476 | 491 | } |
0 commit comments