aboutsummaryrefslogtreecommitdiff
path: root/src/raw_input.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-12 15:54:19 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-12 15:54:19 +0300
commit4af28fbb6551cd33596096af422895c1998fa3e8 (patch)
tree06d92a8a1cf53a2d85129f0e6d3e9701a75eda1b /src/raw_input.rs
parent8375922c069a244133d083a0bb50273e134be6b1 (diff)
test: add ime input regressions
Diffstat (limited to 'src/raw_input.rs')
-rw-r--r--src/raw_input.rs97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/raw_input.rs b/src/raw_input.rs
index 0cf9d84b..aa231595 100644
--- a/src/raw_input.rs
+++ b/src/raw_input.rs
@@ -1007,6 +1007,103 @@ mod tests {
}
#[test]
+ fn chunked_cjk_utf8_waits_for_all_continuation_bytes() {
+ let (tx, mut rx) = mpsc::channel(8);
+ let mut buffer = Vec::new();
+ let bytes = "好".as_bytes();
+
+ drain_chunk(&mut buffer, &tx, &bytes[..1]);
+ assert_eq!(buffer, bytes[..1]);
+ assert!(collect_events(&mut rx).is_empty());
+ flush_incomplete_buffer(&mut buffer, &tx);
+ assert_eq!(buffer, bytes[..1]);
+ assert!(collect_events(&mut rx).is_empty());
+
+ drain_chunk(&mut buffer, &tx, &bytes[1..2]);
+ assert_eq!(buffer, bytes[..2]);
+ assert!(collect_events(&mut rx).is_empty());
+ flush_incomplete_buffer(&mut buffer, &tx);
+ assert_eq!(buffer, bytes[..2]);
+ assert!(collect_events(&mut rx).is_empty());
+
+ drain_chunk(&mut buffer, &tx, &bytes[2..]);
+ assert!(buffer.is_empty());
+ let events = collect_events(&mut rx);
+ assert_eq!(events.len(), 1);
+ assert_raw_key(
+ events.into_iter().next().unwrap(),
+ KeyCode::Char('好'),
+ KeyModifiers::empty(),
+ );
+ }
+
+ #[test]
+ fn chunked_four_byte_utf8_waits_for_all_continuation_bytes() {
+ let (tx, mut rx) = mpsc::channel(8);
+ let mut buffer = Vec::new();
+ let bytes = "🙂".as_bytes();
+
+ for split in 1..bytes.len() {
+ drain_chunk(&mut buffer, &tx, &bytes[split - 1..split]);
+ assert_eq!(buffer, bytes[..split]);
+ assert!(collect_events(&mut rx).is_empty());
+ flush_incomplete_buffer(&mut buffer, &tx);
+ assert_eq!(buffer, bytes[..split]);
+ assert!(collect_events(&mut rx).is_empty());
+ }
+
+ drain_chunk(&mut buffer, &tx, &bytes[bytes.len() - 1..]);
+ assert!(buffer.is_empty());
+ let events = collect_events(&mut rx);
+ assert_eq!(events.len(), 1);
+ assert_raw_key(
+ events.into_iter().next().unwrap(),
+ KeyCode::Char('🙂'),
+ KeyModifiers::empty(),
+ );
+ }
+
+ #[test]
+ fn long_multilingual_voice_like_burst_drains_without_truncation() {
+ let text = "你好,今天我们测试一段比较长的语音输入。こんにちは。안녕하세요.🙂".repeat(128);
+ assert!(
+ text.len() > 4096,
+ "test input should exceed the client read buffer"
+ );
+ let mut buffer = text.as_bytes().to_vec();
+
+ let chunks = drain_complete_input_bytes(&mut buffer);
+ let rebuilt: Vec<u8> = chunks.into_iter().flatten().collect();
+
+ assert!(buffer.is_empty());
+ assert_eq!(rebuilt, text.as_bytes());
+ }
+
+ #[test]
+ fn long_multilingual_burst_survives_one_byte_chunks_and_timeouts() {
+ let text = "中文かなカナ한글🙂,。".repeat(64);
+ let mut buffer = Vec::new();
+ let mut rebuilt = Vec::new();
+
+ for byte in text.as_bytes() {
+ buffer.push(*byte);
+ for chunk in drain_complete_input_bytes(&mut buffer) {
+ rebuilt.extend(chunk);
+ }
+ if !buffer.is_empty() {
+ assert_eq!(flush_incomplete_input_bytes(&mut buffer), None);
+ }
+ }
+
+ for chunk in drain_complete_input_bytes(&mut buffer) {
+ rebuilt.extend(chunk);
+ }
+
+ assert!(buffer.is_empty());
+ assert_eq!(rebuilt, text.as_bytes());
+ }
+
+ #[test]
fn parse_with_ranges_tracks_byte_offsets() {
use super::parse_raw_input_bytes_with_ranges;