diff --git a/core/chanora_core/src/lib.rs b/core/chanora_core/src/lib.rs index 77ed1fc..883aaf6 100644 --- a/core/chanora_core/src/lib.rs +++ b/core/chanora_core/src/lib.rs @@ -174,6 +174,10 @@ fn normalize_channel_password(password: Option) -> Option { .filter(|p| !p.is_empty()) } +fn should_dispatch_text_message(message: &str, target: &MessageTarget) -> bool { + !message.trim().is_empty() || matches!(target, MessageTarget::Poke(_)) +} + /// The top-level Chanora session. Owns at most one active server /// connection (DEC-006). #[derive(Clone)] @@ -673,7 +677,7 @@ impl ChanoraSession { message: String, target: MessageTarget, ) -> Result<(), CoreError> { - if message.trim().is_empty() { + if !should_dispatch_text_message(&message, &target) { return Ok(()); } let guard = self.inner.lock().await; @@ -2535,6 +2539,38 @@ mod tests { ); } + #[test] + fn empty_poke_messages_are_dispatchable() { + assert!(super::should_dispatch_text_message( + "", + &MessageTarget::Poke(42) + )); + assert!(super::should_dispatch_text_message( + " \t ", + &MessageTarget::Poke(42) + )); + } + + #[test] + fn empty_non_poke_messages_remain_suppressed() { + assert!(!super::should_dispatch_text_message( + "", + &MessageTarget::Server + )); + assert!(!super::should_dispatch_text_message( + " ", + &MessageTarget::Channel + )); + assert!(!super::should_dispatch_text_message( + "", + &MessageTarget::Client(42) + )); + assert!(super::should_dispatch_text_message( + "hello", + &MessageTarget::Channel + )); + } + #[tokio::test] async fn empty_address_is_rejected() { let s = ChanoraSession::new();