use super::{ClientRegistration, authorization_model};
use crate::domain::{ProtocolVersion, ReleaseDate};
const ALL: &[ProtocolVersion] = &ProtocolVersion::KNOWN;
#[test]
fn the_table_covers_every_revision() {
assert!(ALL.contains(&ProtocolVersion::latest_known()));
assert!(ALL.contains(&ProtocolVersion::earliest_known()));
}
#[test]
fn a_revision_published_after_this_build_gets_no_authorization_behaviour() {
let unknown = ProtocolVersion::Unknown(ReleaseDate::V2026_07_28);
let model = authorization_model(unknown);
assert!(!model.specified);
assert_eq!(model.client_registration, ClientRegistration::None);
assert!(!model.protected_resource_metadata);
assert!(!model.resource_indicators_required);
assert!(!model.audience_bound());
}
#[test]
fn only_2024_11_05_lacks_an_authorization_framework() {
for version in ALL {
let expected = *version != ProtocolVersion::V2024_11_05;
assert_eq!(
authorization_model(*version).specified,
expected,
"{version} specified={expected} is wrong",
);
}
}
#[test]
fn protected_resource_metadata_arrives_in_2025_06_18() {
for version in ALL {
let expected = matches!(
version,
ProtocolVersion::V2025_06_18
| ProtocolVersion::V2025_11_25
| ProtocolVersion::V2026_07_28
);
assert_eq!(
authorization_model(*version).protected_resource_metadata,
expected,
"{version} protected_resource_metadata={expected} is wrong",
);
}
}
#[test]
fn resource_indicators_are_required_from_2025_06_18() {
for version in ALL {
let expected = matches!(
version,
ProtocolVersion::V2025_06_18
| ProtocolVersion::V2025_11_25
| ProtocolVersion::V2026_07_28
);
assert_eq!(
authorization_model(*version).resource_indicators_required,
expected,
"{version} resource_indicators_required={expected} is wrong",
);
}
}
#[test]
fn oidc_discovery_arrives_in_2025_11_25() {
for version in ALL {
let expected = matches!(
version,
ProtocolVersion::V2025_11_25 | ProtocolVersion::V2026_07_28
);
assert_eq!(
authorization_model(*version).oidc_discovery,
expected,
"{version} oidc_discovery={expected} is wrong",
);
}
}
#[test]
fn incremental_scope_consent_arrives_in_2025_11_25() {
for version in ALL {
let expected = matches!(
version,
ProtocolVersion::V2025_11_25 | ProtocolVersion::V2026_07_28
);
assert_eq!(
authorization_model(*version).incremental_scope_consent,
expected,
"{version} incremental_scope_consent={expected} is wrong",
);
}
}
#[test]
fn the_issuer_requirement_arrives_in_2026_07_28() {
for version in ALL {
let expected = *version == ProtocolVersion::V2026_07_28;
assert_eq!(
authorization_model(*version).issuer_parameter,
expected,
"{version} issuer_parameter={expected} is wrong",
);
}
}
#[test]
fn credentials_become_issuer_bound_in_2026_07_28() {
for version in ALL {
let expected = *version == ProtocolVersion::V2026_07_28;
assert_eq!(
authorization_model(*version).credentials_bound_to_issuer,
expected,
"{version} credentials_bound_to_issuer={expected} is wrong",
);
}
}
#[test]
fn registration_progresses_from_dynamic_to_metadata_documents() {
let expected = [
(ProtocolVersion::V2024_11_05, ClientRegistration::None),
(ProtocolVersion::V2025_03_26, ClientRegistration::Dynamic),
(ProtocolVersion::V2025_06_18, ClientRegistration::Dynamic),
(
ProtocolVersion::V2025_11_25,
ClientRegistration::DynamicOrMetadataDocument,
),
(
ProtocolVersion::V2026_07_28,
ClientRegistration::MetadataDocument,
),
];
for (version, want) in expected {
assert_eq!(
authorization_model(version).client_registration,
want,
"{version} has the wrong registration mechanism",
);
}
}
#[test]
fn a_revision_with_no_framework_registers_with_nothing() {
let registration = authorization_model(ProtocolVersion::V2024_11_05).client_registration;
assert_eq!(registration.preferred(), None);
assert_eq!(registration.fallback(), None);
assert!(!registration.supports_dynamic());
assert!(!registration.supports_metadata_document());
}
#[test]
fn metadata_documents_are_preferred_wherever_they_exist() {
for version in [ProtocolVersion::V2025_11_25, ProtocolVersion::V2026_07_28] {
assert_eq!(
authorization_model(version).client_registration.preferred(),
Some(ClientRegistration::MetadataDocument),
"{version} should lead with a metadata document",
);
}
}
#[test]
fn dynamic_registration_is_the_fallback_not_the_removal() {
let latest = authorization_model(ProtocolVersion::V2026_07_28);
assert!(latest.client_registration.supports_dynamic());
assert_eq!(
latest.client_registration.fallback(),
Some(ClientRegistration::Dynamic)
);
}
#[test]
fn the_walk_never_names_a_mechanism_the_revision_lacks() -> Result<(), TestError> {
for version in ALL {
let registration = authorization_model(*version).client_registration;
for (step, mechanism) in [
("preferred", registration.preferred()),
("fallback", registration.fallback()),
] {
let Some(mechanism) = mechanism else {
continue;
};
let supported = match mechanism {
ClientRegistration::Dynamic => registration.supports_dynamic(),
_ => registration.supports_metadata_document(),
};
if !supported {
return Err(TestError::WalkNamesAnUnsupportedMechanism {
version: *version,
step,
mechanism,
});
}
}
}
Ok(())
}
#[test]
fn a_fallback_is_only_offered_where_a_preference_was() {
for version in ALL {
let registration = authorization_model(*version).client_registration;
if registration.preferred() == Some(ClientRegistration::Dynamic) {
assert_eq!(
registration.fallback(),
None,
"{version} has one mechanism but offers a second",
);
}
}
}
#[test]
fn application_type_is_required_only_for_2026_07_28() {
for version in ALL {
let expected = *version == ProtocolVersion::V2026_07_28;
assert_eq!(
authorization_model(*version)
.client_registration
.application_type_required(),
expected,
"{version} application_type_required={expected} is wrong",
);
}
}
#[test]
fn audience_binding_follows_the_framework_not_the_metadata() {
for version in ALL {
let model = authorization_model(*version);
assert_eq!(
model.audience_bound(),
model.specified,
"{version} audience_bound must follow specified",
);
}
assert!(authorization_model(ProtocolVersion::V2025_03_26).audience_bound());
assert!(!authorization_model(ProtocolVersion::V2024_11_05).audience_bound());
}
#[test]
fn the_derives_agree_and_declaration_order_is_chronological() {
let chronological = [
ClientRegistration::None,
ClientRegistration::Dynamic,
ClientRegistration::DynamicOrMetadataDocument,
ClientRegistration::MetadataDocument,
];
let mut sorted = chronological;
sorted.sort();
assert_eq!(
sorted, chronological,
"the declaration order no longer matches the derivation order",
);
for a in sorted {
for b in sorted {
assert_eq!(
Some(a.cmp(&b)),
a.partial_cmp(&b),
"{a:?} and {b:?} disagree between the two derivations",
);
}
}
}
#[derive(Debug, thiserror::Error)]
enum TestError {
#[error("{version} offers {mechanism:?} as its {step}, which it does not support")]
WalkNamesAnUnsupportedMechanism {
version: ProtocolVersion,
step: &'static str,
mechanism: ClientRegistration,
},
}