use std::collections::BTreeSet;
pub fn select_scope(
www_authenticate_scope: Option<&str>,
prm_scopes_supported: Option<&[String]>,
configured_scope: Option<&str>,
) -> Option<String> {
if let Some(s) = www_authenticate_scope {
let trimmed = s.trim();
if !trimmed.is_empty() {
return Some(trimmed.to_string());
}
}
if let Some(scopes) = prm_scopes_supported {
let joined = scopes
.iter()
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.collect::<Vec<_>>()
.join(" ");
if !joined.is_empty() {
return Some(joined);
}
}
configured_scope.and_then(|s| {
let trimmed = s.trim();
if trimmed.is_empty() {
None
} else {
Some(trimmed.to_string())
}
})
}
pub fn union_scopes(prior: Option<&str>, challenged: Option<&str>) -> Option<String> {
let mut set: BTreeSet<String> = BTreeSet::new();
for s in prior.into_iter().flat_map(|s| s.split_whitespace()) {
if !s.is_empty() {
set.insert(s.to_string());
}
}
for s in challenged.into_iter().flat_map(|s| s.split_whitespace()) {
if !s.is_empty() {
set.insert(s.to_string());
}
}
if set.is_empty() {
None
} else {
Some(set.into_iter().collect::<Vec<_>>().join(" "))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn select_scope_prefers_www_auth() {
let s = select_scope(Some("mcp:a"), Some(&["x".into()]), Some("y"));
assert_eq!(s.as_deref(), Some("mcp:a"));
}
#[test]
fn select_scope_falls_back_to_prm_scopes_supported() {
let s = select_scope(None, Some(&["a".into(), "b".into()]), Some("y"));
assert_eq!(s.as_deref(), Some("a b"));
}
#[test]
fn select_scope_falls_back_to_config() {
let s = select_scope(None, None, Some("y"));
assert_eq!(s.as_deref(), Some("y"));
}
#[test]
fn select_scope_returns_none_when_nothing_available() {
let s = select_scope(None, None, None);
assert!(s.is_none());
}
#[test]
fn select_scope_empty_strings_treated_as_absent() {
let s = select_scope(Some(""), Some(&[]), Some(""));
assert!(s.is_none());
}
#[test]
fn union_scopes_basic() {
assert_eq!(union_scopes(Some("a"), Some("b")).as_deref(), Some("a b"));
}
#[test]
fn union_scopes_dedupes() {
assert_eq!(
union_scopes(Some("a b"), Some("b c")).as_deref(),
Some("a b c")
);
}
#[test]
fn union_scopes_empty_inputs() {
assert!(union_scopes(None, None).is_none());
assert!(union_scopes(Some(""), Some("")).is_none());
assert_eq!(union_scopes(Some("x"), None).as_deref(), Some("x"));
assert_eq!(union_scopes(None, Some("y")).as_deref(), Some("y"));
}
}