use std::collections::HashMap;
use bon::Builder;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Builder)]
pub struct AuthorizationDetail {
#[builder(start_fn, into)]
pub r#type: String,
#[serde(flatten)]
#[builder(field)]
pub fields: HashMap<String, Value>,
}
impl<S: authorization_detail_builder::State> AuthorizationDetailBuilder<S> {
pub fn with(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
self.fields.insert(key.into(), value.into());
self
}
}
impl TryFrom<Value> for AuthorizationDetail {
type Error = serde_json::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
serde_json::from_value(value)
}
}
#[cfg(test)]
mod tests {
use super::AuthorizationDetail;
use crate::oauth_form;
fn sample() -> Vec<AuthorizationDetail> {
vec![
AuthorizationDetail::builder("account_information")
.with(
"actions",
serde_json::json!(["list_accounts", "read_balances"]),
)
.build(),
AuthorizationDetail::builder("payment_initiation")
.with("actions", serde_json::json!(["initiate"]))
.with(
"instructedAmount",
serde_json::json!({ "currency": "EUR", "amount": "123.50" }),
)
.build(),
]
}
#[test]
fn form_value_is_a_json_array_round_trips() {
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
struct Req {
authorization_details: Vec<AuthorizationDetail>,
}
let req = Req {
authorization_details: sample(),
};
let form = oauth_form::to_string(&req).unwrap();
assert_eq!(form.matches("authorization_details=").count(), 1, "{form}");
assert!(form.contains("authorization_details=%5B%7B"), "{form}");
assert_eq!(oauth_form::from_str::<Req>(&form).unwrap(), req);
}
#[test]
fn json_value_is_a_native_array() {
let json = serde_json::to_value(sample()).unwrap();
assert!(json.is_array());
assert_eq!(json[0]["type"], "account_information");
assert_eq!(json[1]["instructedAmount"]["currency"], "EUR");
}
#[test]
fn try_from_value_requires_type() {
let ok = AuthorizationDetail::try_from(serde_json::json!({
"type": "x", "foo": 1
}))
.unwrap();
assert_eq!(ok.r#type, "x");
assert_eq!(ok.fields["foo"], serde_json::json!(1));
assert!(AuthorizationDetail::try_from(serde_json::json!({ "foo": 1 })).is_err());
}
}