use super::*;
#[test]
fn test_extension_scope_debug() {
let scope = ExtensionScope::Shared;
let debug = format!("{scope:?}");
assert!(debug.contains("Shared"));
}
#[test]
fn test_extension_scope_clone_copy_eq() {
let a = ExtensionScope::Client;
let b = a;
assert_eq!(a, b);
assert_ne!(a, ExtensionScope::Shared);
}
struct DummyBridge {
kind_str: &'static str,
}
impl DummyBridge {
const fn new(kind: &'static str) -> Self {
Self { kind_str: kind }
}
}
impl ExtensionStateBridge for DummyBridge {
fn kind(&self) -> &'static str {
self.kind_str
}
fn scope(&self) -> ExtensionScope {
ExtensionScope::Shared
}
fn snapshot(&self, _extensions: &ExtensionMap) -> Option<serde_json::Value> {
Some(serde_json::json!({"dummy": true}))
}
fn is_active(&self, _extensions: &ExtensionMap) -> bool {
false
}
}
#[test]
fn test_registry_new_is_empty() {
let reg = BridgeRegistry::new();
assert!(reg.kinds().is_empty());
}
#[test]
fn test_registry_default_is_empty() {
let reg = BridgeRegistry::default();
assert!(reg.kinds().is_empty());
}
#[test]
fn test_registry_register_and_get() {
let mut reg = BridgeRegistry::new();
reg.register(DummyBridge::new("test"));
assert!(reg.get("test").is_some());
assert_eq!(reg.get("test").unwrap().kind(), "test");
}
#[test]
fn test_registry_get_unknown_returns_none() {
let reg = BridgeRegistry::new();
assert!(reg.get("nonexistent").is_none());
}
#[test]
fn test_registry_kinds() {
let mut reg = BridgeRegistry::new();
reg.register(DummyBridge::new("beta"));
reg.register(DummyBridge::new("alpha"));
assert_eq!(reg.kinds(), vec!["alpha", "beta"]);
}
#[test]
fn test_registry_duplicate_overwrites() {
let mut reg = BridgeRegistry::new();
reg.register(DummyBridge::new("test"));
reg.register(DummyBridge::new("test"));
assert_eq!(reg.kinds().len(), 1);
}
#[test]
fn test_registry_debug() {
let mut reg = BridgeRegistry::new();
reg.register(DummyBridge::new("cmdline"));
let debug = format!("{reg:?}");
assert!(debug.contains("BridgeRegistry"));
assert!(debug.contains("cmdline"));
}
#[test]
fn test_trait_object_construction() {
let bridge: Box<dyn ExtensionStateBridge> = Box::new(DummyBridge::new("test"));
assert_eq!(bridge.kind(), "test");
assert_eq!(bridge.scope(), ExtensionScope::Shared);
assert!(!bridge.is_active(&ExtensionMap::new()));
}
#[test]
fn test_dummy_bridge_snapshot() {
let bridge = DummyBridge::new("test");
let map = ExtensionMap::new();
let snap = bridge.snapshot(&map);
assert!(snap.is_some());
assert_eq!(snap.unwrap(), serde_json::json!({"dummy": true}));
}
#[test]
fn test_on_mode_changed_default_noop() {
let bridge = DummyBridge::new("test");
let mut map = ExtensionMap::new();
bridge.on_mode_changed("vim:insert", "vim:normal", &mut map);
}
#[test]
fn test_tick_default_returns_false() {
let bridge = DummyBridge::new("test");
let mut client = ExtensionMap::new();
let mut shared = ExtensionMap::new();
let services = ServiceRegistry::new();
assert!(!bridge.tick(&mut client, &mut shared, &services));
}
#[test]
fn test_registry_values() {
let mut reg = BridgeRegistry::new();
reg.register(DummyBridge::new("alpha"));
reg.register(DummyBridge::new("beta"));
let mut kinds: Vec<&str> = reg.values().map(ExtensionStateBridge::kind).collect();
kinds.sort_unstable();
assert_eq!(kinds, vec!["alpha", "beta"]);
}
#[test]
fn test_registry_register_boxed() {
let mut reg = BridgeRegistry::new();
let boxed: Box<dyn ExtensionStateBridge> = Box::new(DummyBridge::new("boxed"));
reg.register_boxed(boxed);
assert!(reg.get("boxed").is_some());
assert_eq!(reg.get("boxed").unwrap().kind(), "boxed");
}
#[test]
fn test_bridge_provider_default_empty() {
let provider = BridgeProvider::default();
let bridges = provider.take_bridges();
assert!(bridges.is_empty());
}
#[test]
fn test_bridge_provider_register_and_take() {
let provider = BridgeProvider::default();
provider.register(DummyBridge::new("alpha"));
provider.register(DummyBridge::new("beta"));
let bridges = provider.take_bridges();
assert_eq!(bridges.len(), 2);
assert_eq!(bridges[0].kind(), "alpha");
assert_eq!(bridges[1].kind(), "beta");
let bridges2 = provider.take_bridges();
assert!(bridges2.is_empty());
}
#[test]
fn test_bridge_provider_service_trait() {
use {reovim_kernel::api::v1::ServiceRegistry, std::sync::Arc};
let registry = ServiceRegistry::new();
let provider = registry.get_or_create::<BridgeProvider>();
provider.register(DummyBridge::new("test"));
let provider2 = registry.get_or_create::<BridgeProvider>();
assert_eq!(Arc::as_ptr(&provider), Arc::as_ptr(&provider2));
let bridges = provider2.take_bridges();
assert_eq!(bridges.len(), 1);
}
#[test]
fn test_bridge_provider_debug() {
let provider = BridgeProvider::default();
provider.register(DummyBridge::new("test"));
let debug = format!("{provider:?}");
assert!(debug.contains("BridgeProvider"));
assert!(debug.contains("pending_bridges"));
}
#[test]
fn test_bridge_context_new() {
let shared = ExtensionMap::new();
let opp1 = ExtensionMap::new();
let opponents = vec![(ClientId::new(2), &opp1)];
let ctx = BridgeContext::new(ClientId::new(1), &shared, &opponents);
assert_eq!(ctx.client_id, ClientId::new(1));
assert_eq!(ctx.opponent_count(), 1);
}
#[test]
fn test_bridge_context_for_each_opponent_iterates_all() {
let shared = ExtensionMap::new();
let opp1 = ExtensionMap::new();
let opp2 = ExtensionMap::new();
let opponents = vec![(ClientId::new(2), &opp1), (ClientId::new(3), &opp2)];
let ctx = BridgeContext::new(ClientId::new(1), &shared, &opponents);
let mut ids = Vec::new();
ctx.for_each_opponent(|id, _ext| ids.push(id));
assert_eq!(ids, vec![ClientId::new(2), ClientId::new(3)]);
}
#[test]
fn test_bridge_context_for_each_opponent_empty() {
let shared = ExtensionMap::new();
let opponents: Vec<(ClientId, &ExtensionMap)> = vec![];
let ctx = BridgeContext::new(ClientId::new(1), &shared, &opponents);
let mut count = 0;
ctx.for_each_opponent(|_, _| count += 1);
assert_eq!(count, 0);
}
#[test]
fn test_bridge_context_opponent_count() {
let shared = ExtensionMap::new();
let opp1 = ExtensionMap::new();
let opponents = vec![(ClientId::new(5), &opp1)];
let ctx = BridgeContext::new(ClientId::new(1), &shared, &opponents);
assert_eq!(ctx.opponent_count(), 1);
let empty: Vec<(ClientId, &ExtensionMap)> = vec![];
let ctx2 = BridgeContext::new(ClientId::new(1), &shared, &empty);
assert_eq!(ctx2.opponent_count(), 0);
}
#[test]
fn test_bridge_context_shared_extensions_access() {
use crate::SessionExtension;
#[derive(Debug)]
struct SharedExt {
value: i32,
}
impl SessionExtension for SharedExt {
fn create() -> Self {
Self { value: 42 }
}
}
let mut shared = ExtensionMap::new();
shared.get_or_insert::<SharedExt>();
let opponents: Vec<(ClientId, &ExtensionMap)> = vec![];
let ctx = BridgeContext::new(ClientId::new(1), &shared, &opponents);
let ext = ctx.shared_extensions.get::<SharedExt>();
assert!(ext.is_some());
assert_eq!(ext.unwrap().value, 42);
}
#[test]
fn test_snapshot_with_context_default_delegates() {
let bridge = DummyBridge::new("test");
let map = ExtensionMap::new();
let shared = ExtensionMap::new();
let opponents: Vec<(ClientId, &ExtensionMap)> = vec![];
let ctx = BridgeContext::new(ClientId::new(1), &shared, &opponents);
let snap = bridge.snapshot_with_context(&map, &ctx);
let direct = bridge.snapshot(&map);
assert_eq!(snap, direct);
}
#[test]
fn test_snapshot_with_context_override_uses_context() {
use crate::SessionExtension;
#[derive(Debug)]
struct OpponentScore {
score: u32,
}
impl SessionExtension for OpponentScore {
fn create() -> Self {
Self { score: 0 }
}
}
struct MultiplayerBridge;
impl ExtensionStateBridge for MultiplayerBridge {
fn kind(&self) -> &'static str {
"multiplayer"
}
fn scope(&self) -> ExtensionScope {
ExtensionScope::Client
}
fn snapshot(&self, _ext: &ExtensionMap) -> Option<serde_json::Value> {
Some(serde_json::json!({"score": 0}))
}
fn is_active(&self, _ext: &ExtensionMap) -> bool {
true
}
fn snapshot_with_context(
&self,
_ext: &ExtensionMap,
context: &BridgeContext<'_>,
) -> Option<serde_json::Value> {
let mut opponent_scores = Vec::new();
context.for_each_opponent(|id, ext| {
if let Some(score) = ext.get::<OpponentScore>() {
opponent_scores
.push(serde_json::json!({"id": id.as_usize(), "score": score.score}));
}
});
Some(serde_json::json!({"opponents": opponent_scores}))
}
}
let mut opp_map = ExtensionMap::new();
let opp_score = opp_map.get_or_insert::<OpponentScore>();
opp_score.score = 999;
let shared = ExtensionMap::new();
let opponents = vec![(ClientId::new(2), &opp_map)];
let ctx = BridgeContext::new(ClientId::new(1), &shared, &opponents);
let bridge = MultiplayerBridge;
let own_map = ExtensionMap::new();
let snap = bridge.snapshot_with_context(&own_map, &ctx);
assert!(snap.is_some());
let json = snap.unwrap();
let opponents_arr = json["opponents"].as_array().unwrap();
assert_eq!(opponents_arr.len(), 1);
assert_eq!(opponents_arr[0]["id"], 2);
assert_eq!(opponents_arr[0]["score"], 999);
}
#[test]
fn test_registry_available_kinds_default_empty() {
let reg = BridgeRegistry::new();
assert!(reg.available_kinds().is_empty());
}
#[test]
fn test_registry_set_and_get_available_kinds() {
let mut reg = BridgeRegistry::new();
reg.set_available_kinds(vec!["cmdline", "whichkey", "completion"]);
assert_eq!(reg.available_kinds(), &["cmdline", "whichkey", "completion"]);
}
#[test]
fn test_registry_available_kinds_independent_of_bridges() {
let mut reg = BridgeRegistry::new();
reg.register(DummyBridge::new("alpha"));
reg.set_available_kinds(vec!["beta", "gamma"]);
assert_eq!(reg.kinds(), vec!["alpha"]);
assert_eq!(reg.available_kinds(), &["beta", "gamma"]);
}
#[test]
fn test_registry_available_kinds_overwrite() {
let mut reg = BridgeRegistry::new();
reg.set_available_kinds(vec!["old"]);
reg.set_available_kinds(vec!["new1", "new2"]);
assert_eq!(reg.available_kinds(), &["new1", "new2"]);
}