|
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)?; |
@@ -350,8 +351,8 @@ impl<'de> Deserialize<'de> for ClientMetadataLocalizedFields { |
350 | 351 | where |
351 | 352 | D: serde::Deserializer<'de>, |
352 | 353 | { |
353 | | - let map = HashMap::<Cow<'de, str>, Value>::deserialize(deserializer)?; |
354 | | - let mut new_map: HashMap<String, HashMap<Option<LanguageTag>, Value>> = HashMap::new(); |
| 354 | + let map = IndexMap::<Cow<'de, str>, Value>::deserialize(deserializer)?; |
| 355 | + let mut new_map: IndexMap<String, IndexMap<Option<LanguageTag>, Value>> = IndexMap::new(); |
355 | 356 |
|
356 | 357 | for (k, v) in map { |
357 | 358 | let (prefix, lang) = if let Some((prefix, lang)) = k.split_once('#') { |
@@ -392,6 +393,8 @@ impl<'de> Deserialize<'de> for ClientMetadataLocalizedFields { |
392 | 393 |
|
393 | 394 | #[cfg(test)] |
394 | 395 | mod tests { |
| 396 | + use insta::assert_yaml_snapshot; |
| 397 | + |
395 | 398 | use super::*; |
396 | 399 |
|
397 | 400 | #[test] |
@@ -464,16 +467,28 @@ mod tests { |
464 | 467 | .validate() |
465 | 468 | .unwrap(); |
466 | 469 |
|
467 | | - assert_eq!( |
468 | | - serde_json::to_value(metadata).unwrap(), |
469 | | - serde_json::json!({ |
470 | | - "redirect_uris": ["http://localhost/oidc"], |
471 | | - "client_name": "Postbox", |
472 | | - "client_name#fr": "Boîte à lettres", |
473 | | - "client_uri": "https://localhost/", |
474 | | - "client_uri#fr": "https://localhost/fr", |
475 | | - "client_uri#de": "https://localhost/de", |
476 | | - }) |
477 | | - ); |
| 470 | + assert_yaml_snapshot!(metadata, @r###" |
| 471 | + redirect_uris: |
| 472 | + - "http://localhost/oidc" |
| 473 | + client_name: Postbox |
| 474 | + "client_name#fr": Boîte à lettres |
| 475 | + client_uri: "https://localhost/" |
| 476 | + "client_uri#fr": "https://localhost/fr" |
| 477 | + "client_uri#de": "https://localhost/de" |
| 478 | + "###); |
| 479 | + |
| 480 | + // Do a roundtrip, we should get the same metadata back with the same order |
| 481 | + let metadata: ClientMetadata = |
| 482 | + serde_json::from_value(serde_json::to_value(metadata).unwrap()).unwrap(); |
| 483 | + let metadata = metadata.validate().unwrap(); |
| 484 | + assert_yaml_snapshot!(metadata, @r###" |
| 485 | + redirect_uris: |
| 486 | + - "http://localhost/oidc" |
| 487 | + client_name: Postbox |
| 488 | + "client_name#fr": Boîte à lettres |
| 489 | + client_uri: "https://localhost/" |
| 490 | + "client_uri#fr": "https://localhost/fr" |
| 491 | + "client_uri#de": "https://localhost/de" |
| 492 | + "###); |
478 | 493 | } |
479 | 494 | } |
0 commit comments