diff --git a/src/cache.rs b/src/cache.rs index 32e2e30..4f53bba 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -136,11 +136,11 @@ impl Cache { /// Compares two Caches to check they have the same current content /// /// This is not a complete equality test: some attributes (sync status...) may differ - pub async fn has_same_contents_than(&self, other: &Self) -> Result> { + pub async fn has_same_observable_content_as(&self, other: &Self) -> Result> { let calendars_l = self.get_calendars().await?; let calendars_r = other.get_calendars().await?; - if keys_are_the_same(&calendars_l, &calendars_r) == false { + if crate::utils::keys_are_the_same(&calendars_l, &calendars_r) == false { log::debug!("Different keys for calendars"); return Ok(false); } @@ -153,54 +153,18 @@ impl Cache { None => return Err("should not happen, we've just tested keys are the same".into()), }; - let items_l = cal_l.get_items().await?; - let items_r = cal_r.get_items().await?; + // TODO: check calendars have the same names/ID/whatever + if cal_l.has_same_observable_content_as(&cal_r).await? == false { + log::debug!("Different calendars"); + return Ok(false) + } - if keys_are_the_same(&items_l, &items_r) == false { - log::debug!("Different keys for items"); - return Ok(false); - } - for (id_l, item_l) in items_l { - let item_r = match items_r.get(&id_l) { - Some(c) => c, - None => return Err("should not happen, we've just tested keys are the same".into()), - }; - if item_l.has_same_observable_content(&item_r) == false { - log::debug!("Different items for id {}:", id_l); - log::debug!("{:#?}", item_l); - log::debug!("{:#?}", item_r); - return Ok(false); - } - } } Ok(true) } } -fn keys_are_the_same(left: &HashMap, right: &HashMap) -> bool -where - T: Hash + Eq + Clone + std::fmt::Display, -{ - if left.len() != right.len() { - log::debug!("Count of keys mismatch: {} and {}", left.len(), right.len()); - return false; - } - let keys_l: HashSet = left.keys().cloned().collect(); - let keys_r: HashSet = right.keys().cloned().collect(); - let result = keys_l == keys_r; - if result == false { - log::debug!("Keys of a map mismatch"); - for key in keys_l { - log::debug!(" left: {}", key); - } - log::debug!("RIGHT:"); - for key in keys_r { - log::debug!(" right: {}", key); - } - } - result -} #[async_trait] impl CalDavSource for Cache { @@ -258,7 +222,7 @@ mod tests { let retrieved_cache = Cache::from_folder(&cache_path).unwrap(); assert_eq!(cache.backing_folder, retrieved_cache.backing_folder); - let test = cache.has_same_contents_than(&retrieved_cache).await; + let test = cache.has_same_observable_content_as(&retrieved_cache).await; println!("Equal? {:?}", test); assert_eq!(test.unwrap(), true); } diff --git a/src/calendar/cached_calendar.rs b/src/calendar/cached_calendar.rs index 6c0d67c..e180a08 100644 --- a/src/calendar/cached_calendar.rs +++ b/src/calendar/cached_calendar.rs @@ -51,6 +51,39 @@ impl CachedCalendar { self.items.insert(item.id().clone(), item); Ok(ss_clone) } + + /// Some kind of equality check + pub async fn has_same_observable_content_as(&self, other: &CachedCalendar) -> Result> { + if self.name != other.name + || self.id != other.id + || self.supported_components != other.supported_components { + log::debug!("Calendar properties mismatch"); + return Ok(false); + } + + + let items_l = self.get_items().await?; + let items_r = other.get_items().await?; + + if crate::utils::keys_are_the_same(&items_l, &items_r) == false { + log::debug!("Different keys for items"); + return Ok(false); + } + for (id_l, item_l) in items_l { + let item_r = match items_r.get(&id_l) { + Some(c) => c, + None => return Err("should not happen, we've just tested keys are the same".into()), + }; + if item_l.has_same_observable_content_as(&item_r) == false { + log::debug!("Different items for id {}:", id_l); + log::debug!("{:#?}", item_l); + log::debug!("{:#?}", item_r); + return Ok(false); + } + } + + Ok(true) + } } diff --git a/src/event.rs b/src/event.rs index 8dbe77d..44496cc 100644 --- a/src/event.rs +++ b/src/event.rs @@ -34,7 +34,7 @@ impl Event { self.sync_status = new_status; } - pub fn has_same_observable_content(&self, _other: &Event) -> bool { + pub fn has_same_observable_content_as(&self, _other: &Event) -> bool { unimplemented!(); } } diff --git a/src/item.rs b/src/item.rs index 6e44fef..08a38df 100644 --- a/src/item.rs +++ b/src/item.rs @@ -80,10 +80,10 @@ impl Item { } } - pub fn has_same_observable_content(&self, other: &Item) -> bool { + pub fn has_same_observable_content_as(&self, other: &Item) -> bool { match (self, other) { - (Item::Event(s), Item::Event(o)) => s.has_same_observable_content(o), - (Item::Task(s), Item::Task(o)) => s.has_same_observable_content(o), + (Item::Event(s), Item::Event(o)) => s.has_same_observable_content_as(o), + (Item::Task(s), Item::Task(o)) => s.has_same_observable_content_as(o), _ => false, } } diff --git a/src/provider.rs b/src/provider.rs index 646a2f6..b030562 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -63,7 +63,7 @@ where // Sync every remote calendar let cals_remote = self.remote.get_calendars().await?; for (cal_id, cal_remote) in cals_remote { - let cal_local = self.get_or_insert_local_counterpart_calendar(&cal_id).await; + let cal_local = self.get_or_insert_local_counterpart_calendar(&cal_id, cal_remote.clone()).await; if let Err(err) = Self::sync_calendar_pair(cal_local, cal_remote).await { log::warn!("Unable to sync calendar {}: {}, skipping this time.", cal_id, err); @@ -78,7 +78,7 @@ where continue; } - let cal_remote = self.get_or_insert_remote_counterpart_calendar(&cal_id).await; + let cal_remote = self.get_or_insert_remote_counterpart_calendar(&cal_id, cal_local.clone()).await; if let Err(err) = Self::sync_calendar_pair(cal_local, cal_remote).await { log::warn!("Unable to sync calendar {}: {}, skipping this time.", cal_id, err); @@ -89,7 +89,7 @@ where } - async fn get_or_insert_local_counterpart_calendar(&mut self, cal_id: &CalendarId) -> Arc> { + async fn get_or_insert_local_counterpart_calendar(&mut self, cal_id: &CalendarId, source_cal: Arc>) -> Arc> { loop { if let Some(cal) = self.local.get_calendar(&cal_id).await { break cal; @@ -97,10 +97,13 @@ where // This calendar does not exist locally yet, let's add it log::debug!("Adding a local calendar {}", cal_id); + let src = source_cal.lock().unwrap(); + let name = src.name().to_string(); + let supported_comps = src.supported_components(); if let Err(err) = self.local.create_calendar( cal_id.clone(), - String::from("new calendar"), - SupportedComponents::TODO, + name, + supported_comps, ).await { log::warn!("Unable to create local calendar {}: {}. Skipping it.", cal_id, err); continue; @@ -108,7 +111,7 @@ where } } - async fn get_or_insert_remote_counterpart_calendar(&mut self, cal_id: &CalendarId) -> Arc> { + async fn get_or_insert_remote_counterpart_calendar(&mut self, cal_id: &CalendarId, source_cal: Arc>) -> Arc> { loop { if let Some(cal) = self.remote.get_calendar(&cal_id).await { break cal; @@ -116,10 +119,13 @@ where // This calendar does not exist in the remote yet, let's add it log::debug!("Adding a remote calendar {}", cal_id); + let src = source_cal.lock().unwrap(); + let name = src.name().to_string(); + let supported_comps = src.supported_components(); if let Err(err) = self.remote.create_calendar( cal_id.clone(), - String::from("new calendar"), - SupportedComponents::TODO, + name, + supported_comps, ).await { log::warn!("Unable to create remote calendar {}: {}. Skipping it.", cal_id, err); continue; diff --git a/src/task.rs b/src/task.rs index a20649f..3e5a9ef 100644 --- a/src/task.rs +++ b/src/task.rs @@ -34,7 +34,7 @@ impl Task { pub fn completed(&self) -> bool { self.completed } pub fn sync_status(&self) -> &SyncStatus { &self.sync_status } - pub fn has_same_observable_content(&self, other: &Task) -> bool { + pub fn has_same_observable_content_as(&self, other: &Task) -> bool { self.id == other.id && self.name == other.name && self.completed == other.completed diff --git a/src/utils.rs b/src/utils.rs index 0dd0a5b..bd8a0ea 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,8 @@ ///! Some utility functions -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::sync::{Arc, Mutex}; +use std::hash::Hash; use minidom::Element; @@ -111,3 +112,30 @@ pub fn print_task(item: &Item) { _ => return, } } + + +/// Compare keys of two hashmaps for equality +pub fn keys_are_the_same(left: &HashMap, right: &HashMap) -> bool +where + T: Hash + Eq + Clone + std::fmt::Display, +{ + if left.len() != right.len() { + log::debug!("Count of keys mismatch: {} and {}", left.len(), right.len()); + return false; + } + + let keys_l: HashSet = left.keys().cloned().collect(); + let keys_r: HashSet = right.keys().cloned().collect(); + let result = keys_l == keys_r; + if result == false { + log::debug!("Keys of a map mismatch"); + for key in keys_l { + log::debug!(" left: {}", key); + } + log::debug!("RIGHT:"); + for key in keys_r { + log::debug!(" right: {}", key); + } + } + result +} diff --git a/tests/scenarii.rs b/tests/scenarii.rs index 0557664..972e0b3 100644 --- a/tests/scenarii.rs +++ b/tests/scenarii.rs @@ -83,13 +83,6 @@ pub fn scenarii_basic() -> Vec { let main_cal = CalendarId::from("https://some.calend.ar/main/".parse().unwrap()); - // - // - // - // - // TODO: add new calendars, with or without taks in them - // - tasks.push( ItemScenario { id: ItemId::random(), diff --git a/tests/sync.rs b/tests/sync.rs index e49da24..2e76821 100644 --- a/tests/sync.rs +++ b/tests/sync.rs @@ -57,15 +57,15 @@ impl TestFlavour { print_provider(&provider, "after sync").await; // Check the contents of both sources are the same after sync - assert!(provider.remote().has_same_contents_than(provider.local()).await.unwrap()); + assert!(provider.remote().has_same_observable_content_as(provider.local()).await.unwrap()); // But also explicitely check that every item is expected let expected_provider = scenarii::populate_test_provider_after_sync(&self.scenarii).await; println!("\n"); print_provider(&expected_provider, "expected after sync").await; - assert!(provider.local() .has_same_contents_than(expected_provider.local() ).await.unwrap()); - assert!(provider.remote().has_same_contents_than(expected_provider.remote()).await.unwrap()); + assert!(provider.local() .has_same_observable_content_as(expected_provider.local() ).await.unwrap()); + assert!(provider.remote().has_same_observable_content_as(expected_provider.remote()).await.unwrap()); } }