linera_views/test_utils/
test_views.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Some [`View`][`crate::views::View`]s that are easy to use with test cases.
5
6use std::{
7    collections::{HashMap, HashSet},
8    fmt::Debug,
9};
10
11use allocative::Allocative;
12
13use crate::{
14    self as linera_views,
15    bucket_queue_view::BucketQueueView,
16    collection_view::CollectionView,
17    context::MemoryContext,
18    log_view::LogView,
19    map_view::MapView,
20    queue_view::QueueView,
21    register_view::RegisterView,
22    set_view::SetView,
23    views::{ClonableView, RootView},
24    ViewError,
25};
26
27/// A [`View`][`crate::views::View`] to be used in test cases.
28pub trait TestView: RootView<Context = MemoryContext<()>> + ClonableView {
29    /// Representation of the view's state.
30    type State: Debug + Eq + Send;
31
32    /// Performs some initial changes to the view, staging them, and returning a representation of
33    /// the view's state.
34    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError>;
35
36    /// Stages some changes to the view that won't be persisted during the test.
37    ///
38    /// Assumes that the current view state is the initially staged changes. Returns the updated
39    /// state.
40    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError>;
41
42    /// Stages some changes to the view that will be persisted during the test.
43    ///
44    /// Assumes that the current view state is the initially staged changes. Returns the updated
45    /// state.
46    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError>;
47
48    /// Reads the view's current state.
49    async fn read(&self) -> Result<Self::State, ViewError>;
50}
51
52/// Wrapper to test with a [`RegisterView`].
53#[derive(RootView, ClonableView)]
54pub struct TestRegisterView<C> {
55    byte: RegisterView<C, u8>,
56}
57
58impl TestView for TestRegisterView<MemoryContext<()>> {
59    type State = u8;
60
61    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
62        let dummy_value = 82;
63        self.byte.set(dummy_value);
64        Ok(dummy_value)
65    }
66
67    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
68        let dummy_value = 209;
69        self.byte.set(dummy_value);
70        Ok(dummy_value)
71    }
72
73    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
74        let dummy_value = 15;
75        self.byte.set(dummy_value);
76        Ok(dummy_value)
77    }
78
79    async fn read(&self) -> Result<Self::State, ViewError> {
80        Ok(*self.byte.get())
81    }
82}
83
84const INITIAL_LOG_QUEUE_VIEW_CHANGES: &[u16] = &[1, 2, 3, 4, 5];
85
86/// Wrapper to test with a [`LogView`].
87#[derive(RootView, ClonableView)]
88pub struct TestLogView<C> {
89    log: LogView<C, u16>,
90}
91
92impl TestView for TestLogView<MemoryContext<()>> {
93    type State = Vec<u16>;
94
95    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
96        for value in INITIAL_LOG_QUEUE_VIEW_CHANGES {
97            self.log.push(*value);
98        }
99
100        Ok(INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec())
101    }
102
103    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
104        let new_values = [10_000, 20_000, 30_000];
105
106        for value in new_values {
107            self.log.push(value);
108        }
109
110        Ok(INITIAL_LOG_QUEUE_VIEW_CHANGES
111            .iter()
112            .copied()
113            .chain(new_values)
114            .collect())
115    }
116
117    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
118        let new_values = [201, 1, 50_050];
119
120        for value in new_values {
121            self.log.push(value);
122        }
123
124        Ok(INITIAL_LOG_QUEUE_VIEW_CHANGES
125            .iter()
126            .copied()
127            .chain(new_values)
128            .collect())
129    }
130
131    async fn read(&self) -> Result<Self::State, ViewError> {
132        self.log.read(..).await
133    }
134}
135
136const INITIAL_MAP_COLLECTION_VIEW_CHANGES: &[(i32, &str)] = &[
137    (0, "zero"),
138    (-1, "minus one"),
139    (2, "two"),
140    (-3, "minus three"),
141    (4, "four"),
142    (-5, "minus five"),
143];
144
145/// Wrapper to test with a [`MapView`].
146#[derive(RootView, ClonableView)]
147pub struct TestMapView<C> {
148    map: MapView<C, i32, String>,
149}
150
151impl TestView for TestMapView<MemoryContext<()>> {
152    type State = HashMap<i32, String>;
153
154    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
155        for (key, value) in INITIAL_MAP_COLLECTION_VIEW_CHANGES {
156            self.map.insert(key, value.to_string())?;
157        }
158
159        Ok(INITIAL_MAP_COLLECTION_VIEW_CHANGES
160            .iter()
161            .map(|(key, value)| (*key, value.to_string()))
162            .collect::<HashMap<_, _>>())
163    }
164
165    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
166        let new_entries = [(-1_000_000, "foo"), (2_000_000, "bar")]
167            .into_iter()
168            .map(|(key, value)| (key, value.to_owned()));
169
170        let entries_to_remove = [0, -3];
171
172        for (key, value) in new_entries.clone() {
173            self.map.insert(&key, value)?;
174        }
175
176        for key in entries_to_remove {
177            self.map.remove(&key)?;
178        }
179
180        let new_state = INITIAL_MAP_COLLECTION_VIEW_CHANGES
181            .iter()
182            .filter(|(key, _)| !entries_to_remove.contains(key))
183            .map(|(key, value)| (*key, value.to_string()))
184            .chain(new_entries)
185            .collect();
186
187        Ok(new_state)
188    }
189
190    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
191        let new_entries = [(1_234, "first new entry"), (-2_101_010, "second_new_entry")]
192            .into_iter()
193            .map(|(key, value)| (key, value.to_owned()));
194
195        let entries_to_remove = [-1, 2, 4];
196
197        for (key, value) in new_entries.clone() {
198            self.map.insert(&key, value)?;
199        }
200
201        for key in entries_to_remove {
202            self.map.remove(&key)?;
203        }
204
205        let new_state = INITIAL_MAP_COLLECTION_VIEW_CHANGES
206            .iter()
207            .filter(|(key, _)| !entries_to_remove.contains(key))
208            .map(|(key, value)| (*key, value.to_string()))
209            .chain(new_entries)
210            .collect();
211
212        Ok(new_state)
213    }
214
215    async fn read(&self) -> Result<Self::State, ViewError> {
216        let mut state = HashMap::new();
217        self.map
218            .for_each_index_value(|key, value| {
219                let value = value.into_owned();
220                state.insert(key, value);
221                Ok(())
222            })
223            .await?;
224        Ok(state)
225    }
226}
227
228/// Wrapper to test with a [`SetView`].
229#[derive(RootView, ClonableView)]
230pub struct TestSetView<C> {
231    set: SetView<C, i32>,
232}
233
234const INITIAL_SET_VIEW_CHANGES: &[i32] = &[0, -1, 2, -3, 4, -5];
235
236impl TestView for TestSetView<MemoryContext<()>> {
237    type State = HashSet<i32>;
238
239    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
240        for key in INITIAL_SET_VIEW_CHANGES {
241            self.set.insert(key)?;
242        }
243
244        Ok(INITIAL_SET_VIEW_CHANGES.iter().copied().collect())
245    }
246
247    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
248        let mut state = INITIAL_SET_VIEW_CHANGES
249            .iter()
250            .copied()
251            .collect::<HashSet<_>>();
252        let new_entries = [-1_000_000, 2_000_000];
253
254        let entries_to_remove = [0, -3];
255
256        for key in new_entries {
257            self.set.insert(&key)?;
258            state.insert(key);
259        }
260
261        for key in entries_to_remove {
262            self.set.remove(&key)?;
263            state.remove(&key);
264        }
265
266        Ok(state)
267    }
268
269    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
270        let mut state = INITIAL_SET_VIEW_CHANGES
271            .iter()
272            .copied()
273            .collect::<HashSet<_>>();
274        let new_entries = [1_234, -2_101_010];
275
276        let entries_to_remove = [-1, 2, 4];
277
278        for key in new_entries {
279            self.set.insert(&key)?;
280            state.insert(key);
281        }
282
283        for key in entries_to_remove {
284            self.set.remove(&key)?;
285            state.remove(&key);
286        }
287
288        Ok(state)
289    }
290
291    async fn read(&self) -> Result<Self::State, ViewError> {
292        let indices = self.set.indices().await?;
293        Ok(indices.into_iter().collect())
294    }
295}
296
297/// Wrapper to test with a [`CollectionView`].
298#[derive(RootView, ClonableView)]
299pub struct TestCollectionView<C> {
300    collection: CollectionView<C, i32, RegisterView<C, String>>,
301}
302
303impl TestView for TestCollectionView<MemoryContext<()>> {
304    type State = HashMap<i32, String>;
305
306    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
307        for (key, value) in INITIAL_MAP_COLLECTION_VIEW_CHANGES {
308            self.collection
309                .load_entry_mut(key)
310                .await?
311                .set(value.to_string());
312        }
313
314        Ok(INITIAL_MAP_COLLECTION_VIEW_CHANGES
315            .iter()
316            .map(|(key, value)| (*key, value.to_string()))
317            .collect::<HashMap<_, _>>())
318    }
319
320    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
321        let new_entries = [(-1_000_000, "foo"), (2_000_000, "bar")]
322            .into_iter()
323            .map(|(key, value)| (key, value.to_owned()));
324
325        let entries_to_remove = [0, -3];
326
327        for (key, value) in new_entries.clone() {
328            self.collection.load_entry_mut(&key).await?.set(value);
329        }
330
331        for key in entries_to_remove {
332            self.collection.remove_entry(&key)?;
333        }
334
335        let new_state = INITIAL_MAP_COLLECTION_VIEW_CHANGES
336            .iter()
337            .filter(|(key, _)| !entries_to_remove.contains(key))
338            .map(|(key, value)| (*key, value.to_string()))
339            .chain(new_entries)
340            .collect();
341
342        Ok(new_state)
343    }
344
345    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
346        let new_entries = [(1_234, "first new entry"), (-2_101_010, "second_new_entry")]
347            .into_iter()
348            .map(|(key, value)| (key, value.to_owned()));
349
350        let entries_to_remove = [-1, 2, 4];
351
352        for (key, value) in new_entries.clone() {
353            self.collection.load_entry_mut(&key).await?.set(value);
354        }
355
356        for key in entries_to_remove {
357            self.collection.remove_entry(&key)?;
358        }
359
360        let new_state = INITIAL_MAP_COLLECTION_VIEW_CHANGES
361            .iter()
362            .filter(|(key, _)| !entries_to_remove.contains(key))
363            .map(|(key, value)| (*key, value.to_string()))
364            .chain(new_entries)
365            .collect();
366
367        Ok(new_state)
368    }
369
370    async fn read(&self) -> Result<Self::State, ViewError> {
371        let indices = self.collection.indices().await?;
372        let mut state = HashMap::with_capacity(indices.len());
373
374        for index in indices {
375            if let Some(value) = self.collection.try_load_entry(&index).await? {
376                state.insert(index, value.get().clone());
377            }
378        }
379
380        Ok(state)
381    }
382}
383
384/// Wrapper to test with a [`QueueView`].
385#[derive(RootView, ClonableView)]
386pub struct TestQueueView<C> {
387    queue: QueueView<C, u16>,
388}
389
390impl TestView for TestQueueView<MemoryContext<()>> {
391    type State = Vec<u16>;
392
393    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
394        for value in INITIAL_LOG_QUEUE_VIEW_CHANGES {
395            self.queue.push_back(*value);
396        }
397
398        Ok(INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec())
399    }
400
401    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
402        let mut initial_state = INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec();
403        let new_values = [10_000, 20_000, 30_000];
404
405        for value in new_values {
406            self.queue.push_back(value);
407            initial_state.push(value);
408        }
409        self.queue.delete_front();
410        initial_state.remove(0);
411        self.queue.delete_front();
412        initial_state.remove(0);
413
414        Ok(initial_state)
415    }
416
417    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
418        let mut initial_state = INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec();
419        let new_values = [201, 1, 50_050, 203];
420
421        for value in new_values {
422            self.queue.push_back(value);
423            initial_state.push(value);
424        }
425        self.queue.delete_front();
426        initial_state.remove(0);
427
428        Ok(initial_state)
429    }
430
431    async fn read(&self) -> Result<Self::State, ViewError> {
432        self.queue.elements().await
433    }
434}
435
436/// Wrapper to test with a [`BucketQueueView`].
437#[derive(RootView, ClonableView, Allocative)]
438pub struct TestBucketQueueView<C> {
439    queue: BucketQueueView<C, u16, 2>,
440}
441
442impl TestView for TestBucketQueueView<MemoryContext<()>> {
443    type State = Vec<u16>;
444
445    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
446        for value in INITIAL_LOG_QUEUE_VIEW_CHANGES {
447            self.queue.push_back(*value);
448        }
449
450        Ok(INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec())
451    }
452
453    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
454        let mut initial_state = INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec();
455        let new_values = [10_000, 20_000, 30_000];
456
457        for value in new_values {
458            self.queue.push_back(value);
459            initial_state.push(value);
460        }
461        self.queue.delete_front().await?;
462        initial_state.remove(0);
463        self.queue.delete_front().await?;
464        initial_state.remove(0);
465
466        Ok(initial_state)
467    }
468
469    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
470        let mut initial_state = INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec();
471        let new_values = [201, 1, 50_050, 203];
472
473        for value in new_values {
474            self.queue.push_back(value);
475            initial_state.push(value);
476        }
477        self.queue.delete_front().await?;
478        initial_state.remove(0);
479
480        Ok(initial_state)
481    }
482
483    async fn read(&self) -> Result<Self::State, ViewError> {
484        self.queue.elements().await
485    }
486}