diff --git a/crates/loro-core/src/fuzz/recursive.rs b/crates/loro-core/src/fuzz/recursive.rs index 38172f78..55f188d0 100644 --- a/crates/loro-core/src/fuzz/recursive.rs +++ b/crates/loro-core/src/fuzz/recursive.rs @@ -909,6 +909,40 @@ mod failed_tests { ) } + #[test] + fn unknown() { + test_multi_sites( + 5, + &mut [ + Map { + site: 0, + container_idx: 0, + key: 0, + value: Container(C::Map), + }, + SyncAll, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Container(C::List), + }, + Map { + site: 1, + container_idx: 1, + key: 255, + value: Container(C::List), + }, + Map { + site: 4, + container_idx: 1, + key: 9, + value: Null, + }, + ], + ) + } + #[test] fn path_issue() { test_multi_sites( diff --git a/crates/loro-core/src/hierarchy.rs b/crates/loro-core/src/hierarchy.rs index c0ea042d..73e79f73 100644 --- a/crates/loro-core/src/hierarchy.rs +++ b/crates/loro-core/src/hierarchy.rs @@ -128,13 +128,13 @@ impl Hierarchy { reg: &ContainerRegistry, descendant: &ContainerID, target: Option<&ContainerID>, - ) -> Path { + ) -> Option { if let ContainerID::Root { name, .. } = descendant { - return vec![Index::Key(name.into())]; + return Some(vec![Index::Key(name.into())]); } if target.map(|x| x == descendant).unwrap_or(false) { - return vec![]; + return Some(vec![]); } let mut path = Path::default(); @@ -155,7 +155,7 @@ impl Hierarchy { name, container_type: _, } => path.push(Index::Key(name.clone())), - _ => unreachable!(), + _ => return None, } } @@ -167,7 +167,7 @@ impl Hierarchy { } path.reverse(); - path + Some(path) } pub fn should_notify(&self, container_id: &ContainerID) -> bool { @@ -211,7 +211,7 @@ impl Hierarchy { // otherwise, the paths to children may be incorrect when the parents are affected by some of the events let mut event_and_paths = raw_events .into_iter() - .map(|x| (self.get_path(reg, &x.container_id, None), x)) + .filter_map(|x| self.get_path(reg, &x.container_id, None).map(|y| (y, x))) .collect::>(); event_and_paths.sort_by_cached_key(|x| x.0.len()); for (path, event) in event_and_paths { @@ -220,7 +220,9 @@ impl Hierarchy { } pub fn notify(&mut self, raw_event: RawEvent, reg: &ContainerRegistry) { - let absolute_path = self.get_path(reg, &raw_event.container_id, None); + let Some(absolute_path) = self.get_path(reg, &raw_event.container_id, None) else { + return; + }; self.notify_with_path(raw_event, absolute_path); } diff --git a/deno.jsonc b/deno.jsonc index ba83326e..578ca056 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,6 +1,8 @@ { "tasks": { "build": "cargo build", + // to debug a single test use + // UST_BACKTRACE=full DEBUG=* cargo test --package loro-core --lib --features test_utils --features wasm -- fuzz::recursive::failed_tests::unknown --exact --nocapture &> debug.log "test": "RUST_BACKTRACE=full cargo nextest run --features=test_utils", "test-all": "deno task test & deno task quick-fuzz & deno task test-wasm", "test-prop": "RUSTFLAGS='--cfg=proptest' cargo nextest run --features=test_utils",