Skip to main content

wabot_testing/
memory.rs

1//! An in-RAM chat memory that a test can read back. Port of
2//! `wabot-ts/src/testing/TestChatMemory.ts`.
3
4use async_trait::async_trait;
5use parking_lot::Mutex;
6use wabot_feature_chat_bot::{ChatItem, ChatMemory};
7
8/// Like `InMemoryChatMemory`, but it exposes the whole item list.
9///
10/// The production one only offers `find_last_items`, which is all the
11/// bot needs and not enough for a test that wants to assert on what a
12/// turn recorded.
13#[derive(Debug, Default)]
14pub struct TestChatMemory {
15    items: Mutex<Vec<ChatItem>>,
16}
17
18impl TestChatMemory {
19    pub fn new() -> Self {
20        Self::default()
21    }
22
23    pub fn all(&self) -> Vec<ChatItem> {
24        self.items.lock().clone()
25    }
26
27    /// Items recorded from `index` onwards — how a harness isolates
28    /// one turn from the history before it.
29    pub fn items_from(&self, index: usize) -> Vec<ChatItem> {
30        let items = self.items.lock();
31        items
32            .get(index..)
33            .map(<[ChatItem]>::to_vec)
34            .unwrap_or_default()
35    }
36
37    pub fn len(&self) -> usize {
38        self.items.lock().len()
39    }
40
41    pub fn is_empty(&self) -> bool {
42        self.items.lock().is_empty()
43    }
44
45    pub fn clear(&self) {
46        self.items.lock().clear();
47    }
48}
49
50#[async_trait]
51impl ChatMemory for TestChatMemory {
52    async fn find_last_items(&self, n: usize) -> Vec<ChatItem> {
53        let items = self.items.lock();
54        let start = items.len().saturating_sub(n);
55        items[start..].to_vec()
56    }
57
58    async fn create(&self, item: ChatItem) {
59        self.items.lock().push(item);
60    }
61}