#![allow(clippy::pedantic, clippy::nursery, missing_docs)]
use std::collections::HashMap;
use std::sync::Mutex;
use crate::principal::PersonaSource;
pub struct TestAttribution {
pub persona_id: String,
}
#[derive(Default)]
pub struct TestPersonas {
active: Mutex<HashMap<String, bool>>,
ties: Mutex<HashMap<String, Vec<(String, bool)>>>,
codes: Mutex<HashMap<String, String>>,
aliases: Mutex<HashMap<String, String>>,
}
impl TestPersonas {
pub async fn attribute(
&self,
identity: polyc_proto::proto::polychrome::persona::v1::ExternalIdentity,
conversation_id: String,
_role: String,
_now_ms: u64,
) -> Result<TestAttribution, polyc_persona::PersonaError> {
let persona_id = identity.external_id.clone();
self.active
.lock()
.expect("test persona map")
.entry(persona_id.clone())
.or_insert(false);
let mut ties = self.ties.lock().expect("test tie map");
let held = ties.entry(persona_id.clone()).or_default();
if !held.iter().any(|(conv, _)| conv == &conversation_id) {
held.push((conversation_id, false));
}
Ok(TestAttribution { persona_id })
}
pub async fn attribute_persona(
&self,
persona_id: String,
conversation_id: String,
_role: String,
_now_ms: u64,
) -> Result<(), polyc_persona::PersonaError> {
let mut ties = self.ties.lock().expect("test tie map");
let held = ties.entry(persona_id).or_default();
if !held.iter().any(|(conv, _)| conv == &conversation_id) {
held.push((conversation_id, false));
}
Ok(())
}
pub async fn start_link(
&self,
identity: polyc_proto::proto::polychrome::persona::v1::ExternalIdentity,
code: String,
_ttl_ms: u64,
_now_ms: u64,
) -> Result<(), polyc_persona::PersonaError> {
self.codes
.lock()
.expect("test link codes")
.insert(code, identity.external_id);
Ok(())
}
pub async fn complete_link(
&self,
code: String,
survivor: polyc_proto::proto::polychrome::persona::v1::ExternalIdentity,
_now_ms: u64,
) -> Result<(), polyc_persona::PersonaError> {
let Some(absorbed) = self.codes.lock().expect("test link codes").remove(&code) else {
return Ok(());
};
let survivor_id = survivor.external_id;
let absorbed_ties = self
.ties
.lock()
.expect("test tie map")
.remove(&absorbed)
.unwrap_or_default();
{
let mut ties = self.ties.lock().expect("test tie map");
let held = ties.entry(survivor_id.clone()).or_default();
for (conversation_id, hidden) in absorbed_ties {
if !held.iter().any(|(conv, _)| conv == &conversation_id) {
held.push((conversation_id, hidden));
}
}
}
self.active
.lock()
.expect("test persona map")
.remove(&absorbed);
self.aliases
.lock()
.expect("test alias map")
.insert(absorbed, survivor_id);
Ok(())
}
pub async fn remove_access(
&self,
_actor: String,
target: polyc_proto::proto::polychrome::persona::v1::ExternalIdentity,
_now_ms: u64,
) -> Result<(), polyc_persona::PersonaError> {
self.active
.lock()
.expect("test persona map")
.remove(&target.external_id);
Ok(())
}
pub async fn set_search_visibility(
&self,
persona_id: String,
conversation_id: String,
hidden: bool,
_actor: String,
_now_ms: u64,
) -> Result<(), polyc_persona::PersonaError> {
if let Some(held) = self.ties.lock().expect("test tie map").get_mut(&persona_id)
&& let Some(tie) = held.iter_mut().find(|(conv, _)| conv == &conversation_id)
{
tie.1 = hidden;
}
Ok(())
}
pub fn grant(&self, persona_id: &str, admin: bool) {
self.active
.lock()
.expect("test persona map")
.insert(persona_id.to_owned(), admin);
}
}
#[async_trait::async_trait]
impl PersonaSource for TestPersonas {
async fn active_persona(
&self,
persona_id: String,
) -> Result<Option<polyc_persona::ActivePersona>, polyc_persona::PersonaError> {
let canonical = self
.aliases
.lock()
.expect("test alias map")
.get(&persona_id)
.cloned()
.unwrap_or(persona_id);
Ok(self
.active
.lock()
.expect("test persona map")
.get(&canonical)
.map(|admin| polyc_persona::ActivePersona {
persona_id: canonical.clone(),
admin: *admin,
provisional: false,
}))
}
async fn participations(
&self,
persona_id: String,
) -> Result<
Vec<polyc_proto::proto::polychrome::persona::v1::Participation>,
polyc_persona::PersonaError,
> {
Ok(self
.ties
.lock()
.expect("test tie map")
.get(&persona_id)
.map(|held| {
held.iter()
.map(|(conversation_id, _)| {
polyc_proto::proto::polychrome::persona::v1::Participation {
conversation_id: conversation_id.clone(),
role: "initiator".to_owned(),
first_at_ms: 0,
via_persona_id: String::new(),
__buffa_unknown_fields: buffa::UnknownFields::default(),
}
})
.collect()
})
.unwrap_or_default())
}
async fn participation_scope(
&self,
persona_id: String,
cap: usize,
) -> Result<polyc_persona::ScopeResolution, polyc_persona::PersonaError> {
let held = self
.ties
.lock()
.expect("test tie map")
.get(&persona_id)
.cloned()
.unwrap_or_default();
if held.len() > cap {
return Ok(polyc_persona::ScopeResolution::RefusedOverCap { count: held.len() });
}
Ok(polyc_persona::ScopeResolution::Resolved {
conversation_ids: held
.into_iter()
.filter_map(|(conv, hidden)| (!hidden).then_some(conv))
.collect(),
})
}
async fn usage_rollup_index(&self) -> Result<Vec<String>, polyc_persona::PersonaError> {
Ok(Vec::new())
}
async fn reference_snapshot(
&self,
_persona_id: String,
) -> Result<Option<polyc_persona::PersonaReferenceSnapshot>, polyc_persona::PersonaError> {
Ok(None)
}
}