cosmwasm_std/testing/
storage.rs

1use alloc::collections::BTreeMap;
2use core::fmt;
3#[cfg(feature = "iterator")]
4use core::iter;
5#[cfg(feature = "iterator")]
6use core::ops::{Bound, RangeBounds};
7
8#[cfg(feature = "iterator")]
9use crate::iterator::{Order, Record};
10use crate::prelude::*;
11use crate::traits::Storage;
12
13#[derive(Default)]
14pub struct MockStorage {
15    data: BTreeMap<Vec<u8>, Vec<u8>>,
16}
17
18impl MockStorage {
19    pub fn new() -> Self {
20        MockStorage::default()
21    }
22}
23
24impl Storage for MockStorage {
25    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
26        self.data.get(key).cloned()
27    }
28
29    fn set(&mut self, key: &[u8], value: &[u8]) {
30        if value.is_empty() {
31            panic!("TL;DR: Value must not be empty in Storage::set but in most cases you can use Storage::remove instead. Long story: Getting empty values from storage is not well supported at the moment. Some of our internal interfaces cannot differentiate between a non-existent key and an empty value. Right now, you cannot rely on the behaviour of empty values. To protect you from trouble later on, we stop here. Sorry for the inconvenience! We highly welcome you to contribute to CosmWasm, making this more solid one way or the other.");
32        }
33
34        self.data.insert(key.to_vec(), value.to_vec());
35    }
36
37    fn remove(&mut self, key: &[u8]) {
38        self.data.remove(key);
39    }
40
41    #[cfg(feature = "iterator")]
42    /// range allows iteration over a set of keys, either forwards or backwards
43    /// uses standard rust range notation, and eg db.range(b"foo"..b"bar") also works reverse
44    fn range<'a>(
45        &'a self,
46        start: Option<&[u8]>,
47        end: Option<&[u8]>,
48        order: Order,
49    ) -> Box<dyn Iterator<Item = Record> + 'a> {
50        let bounds = range_bounds(start, end);
51
52        // BTreeMap.range panics if range is start > end.
53        // However, this cases represent just empty range and we treat it as such.
54        match (bounds.start_bound(), bounds.end_bound()) {
55            (Bound::Included(start), Bound::Excluded(end)) if start > end => {
56                return Box::new(iter::empty());
57            }
58            _ => {}
59        }
60
61        let iter = self.data.range(bounds);
62        match order {
63            Order::Ascending => Box::new(iter.map(clone_item)),
64            Order::Descending => Box::new(iter.rev().map(clone_item)),
65        }
66    }
67}
68
69/// This debug implementation is made for inspecting storages in unit testing.
70/// It is made for human readability only and the output can change at any time.
71impl fmt::Debug for MockStorage {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        write!(f, "MemoryStorage ({} entries)", self.data.len())?;
74        f.write_str(" {\n")?;
75        for (key, value) in &self.data {
76            f.write_str("  0x")?;
77            for byte in key {
78                write!(f, "{byte:02x}")?;
79            }
80            f.write_str(": 0x")?;
81            for byte in value {
82                write!(f, "{byte:02x}")?;
83            }
84            f.write_str("\n")?;
85        }
86        f.write_str("}")?;
87        Ok(())
88    }
89}
90
91#[cfg(feature = "iterator")]
92fn range_bounds(start: Option<&[u8]>, end: Option<&[u8]>) -> impl RangeBounds<Vec<u8>> {
93    (
94        start.map_or(Bound::Unbounded, |x| Bound::Included(x.to_vec())),
95        end.map_or(Bound::Unbounded, |x| Bound::Excluded(x.to_vec())),
96    )
97}
98
99#[cfg(feature = "iterator")]
100/// The BTreeMap specific key-value pair reference type, as returned by BTreeMap<Vec<u8>, Vec<u8>>::range.
101/// This is internal as it can change any time if the map implementation is swapped out.
102type BTreeMapRecordRef<'a> = (&'a Vec<u8>, &'a Vec<u8>);
103
104#[cfg(feature = "iterator")]
105fn clone_item(item_ref: BTreeMapRecordRef) -> Record {
106    let (key, value) = item_ref;
107    (key.clone(), value.clone())
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn get_and_set() {
116        let mut store = MockStorage::new();
117        assert_eq!(store.get(b"foo"), None);
118        store.set(b"foo", b"bar");
119        assert_eq!(store.get(b"foo"), Some(b"bar".to_vec()));
120        assert_eq!(store.get(b"food"), None);
121    }
122
123    #[test]
124    #[should_panic(
125        expected = "Getting empty values from storage is not well supported at the moment."
126    )]
127    fn set_panics_for_empty() {
128        let mut store = MockStorage::new();
129        store.set(b"foo", b"");
130    }
131
132    #[test]
133    fn delete() {
134        let mut store = MockStorage::new();
135        store.set(b"foo", b"bar");
136        store.set(b"food", b"bank");
137        store.remove(b"foo");
138
139        assert_eq!(store.get(b"foo"), None);
140        assert_eq!(store.get(b"food"), Some(b"bank".to_vec()));
141    }
142
143    #[test]
144    #[cfg(feature = "iterator")]
145    fn iterator() {
146        let mut store = MockStorage::new();
147        store.set(b"foo", b"bar");
148
149        // ensure we had previously set "foo" = "bar"
150        assert_eq!(store.get(b"foo"), Some(b"bar".to_vec()));
151        assert_eq!(store.range(None, None, Order::Ascending).count(), 1);
152
153        // setup - add some data, and delete part of it as well
154        store.set(b"ant", b"hill");
155        store.set(b"ze", b"bra");
156
157        // noise that should be ignored
158        store.set(b"bye", b"bye");
159        store.remove(b"bye");
160
161        // unbounded
162        {
163            let iter = store.range(None, None, Order::Ascending);
164            let elements: Vec<Record> = iter.collect();
165            assert_eq!(
166                elements,
167                vec![
168                    (b"ant".to_vec(), b"hill".to_vec()),
169                    (b"foo".to_vec(), b"bar".to_vec()),
170                    (b"ze".to_vec(), b"bra".to_vec()),
171                ]
172            );
173        }
174
175        // unbounded (descending)
176        {
177            let iter = store.range(None, None, Order::Descending);
178            let elements: Vec<Record> = iter.collect();
179            assert_eq!(
180                elements,
181                vec![
182                    (b"ze".to_vec(), b"bra".to_vec()),
183                    (b"foo".to_vec(), b"bar".to_vec()),
184                    (b"ant".to_vec(), b"hill".to_vec()),
185                ]
186            );
187        }
188
189        // bounded
190        {
191            let iter = store.range(Some(b"f"), Some(b"n"), Order::Ascending);
192            let elements: Vec<Record> = iter.collect();
193            assert_eq!(elements, vec![(b"foo".to_vec(), b"bar".to_vec())]);
194        }
195
196        // bounded (descending)
197        {
198            let iter = store.range(Some(b"air"), Some(b"loop"), Order::Descending);
199            let elements: Vec<Record> = iter.collect();
200            assert_eq!(
201                elements,
202                vec![
203                    (b"foo".to_vec(), b"bar".to_vec()),
204                    (b"ant".to_vec(), b"hill".to_vec()),
205                ]
206            );
207        }
208
209        // bounded empty [a, a)
210        {
211            let iter = store.range(Some(b"foo"), Some(b"foo"), Order::Ascending);
212            let elements: Vec<Record> = iter.collect();
213            assert_eq!(elements, vec![]);
214        }
215
216        // bounded empty [a, a) (descending)
217        {
218            let iter = store.range(Some(b"foo"), Some(b"foo"), Order::Descending);
219            let elements: Vec<Record> = iter.collect();
220            assert_eq!(elements, vec![]);
221        }
222
223        // bounded empty [a, b) with b < a
224        {
225            let iter = store.range(Some(b"z"), Some(b"a"), Order::Ascending);
226            let elements: Vec<Record> = iter.collect();
227            assert_eq!(elements, vec![]);
228        }
229
230        // bounded empty [a, b) with b < a (descending)
231        {
232            let iter = store.range(Some(b"z"), Some(b"a"), Order::Descending);
233            let elements: Vec<Record> = iter.collect();
234            assert_eq!(elements, vec![]);
235        }
236
237        // right unbounded
238        {
239            let iter = store.range(Some(b"f"), None, Order::Ascending);
240            let elements: Vec<Record> = iter.collect();
241            assert_eq!(
242                elements,
243                vec![
244                    (b"foo".to_vec(), b"bar".to_vec()),
245                    (b"ze".to_vec(), b"bra".to_vec()),
246                ]
247            );
248        }
249
250        // right unbounded (descending)
251        {
252            let iter = store.range(Some(b"f"), None, Order::Descending);
253            let elements: Vec<Record> = iter.collect();
254            assert_eq!(
255                elements,
256                vec![
257                    (b"ze".to_vec(), b"bra".to_vec()),
258                    (b"foo".to_vec(), b"bar".to_vec()),
259                ]
260            );
261        }
262
263        // left unbounded
264        {
265            let iter = store.range(None, Some(b"f"), Order::Ascending);
266            let elements: Vec<Record> = iter.collect();
267            assert_eq!(elements, vec![(b"ant".to_vec(), b"hill".to_vec()),]);
268        }
269
270        // left unbounded (descending)
271        {
272            let iter = store.range(None, Some(b"no"), Order::Descending);
273            let elements: Vec<Record> = iter.collect();
274            assert_eq!(
275                elements,
276                vec![
277                    (b"foo".to_vec(), b"bar".to_vec()),
278                    (b"ant".to_vec(), b"hill".to_vec()),
279                ]
280            );
281        }
282    }
283
284    #[test]
285    fn memory_storage_implements_debug() {
286        let store = MockStorage::new();
287        assert_eq!(
288            format!("{store:?}"),
289            "MemoryStorage (0 entries) {\n\
290            }"
291        );
292
293        // With one element
294        let mut store = MockStorage::new();
295        store.set(&[0x00, 0xAB, 0xDD], &[0xFF, 0xD5]);
296        assert_eq!(
297            format!("{store:?}"),
298            "MemoryStorage (1 entries) {\n\
299            \x20\x200x00abdd: 0xffd5\n\
300            }"
301        );
302
303        // Sorted by key
304        let mut store = MockStorage::new();
305        store.set(&[0x00, 0xAB, 0xDD], &[0xFF, 0xD5]);
306        store.set(&[0x00, 0xAB, 0xEE], &[0xFF, 0xD5]);
307        store.set(&[0x00, 0xAB, 0xCC], &[0xFF, 0xD5]);
308        assert_eq!(
309            format!("{store:?}"),
310            "MemoryStorage (3 entries) {\n\
311            \x20\x200x00abcc: 0xffd5\n\
312            \x20\x200x00abdd: 0xffd5\n\
313            \x20\x200x00abee: 0xffd5\n\
314            }"
315        );
316
317        // Different lengths
318        let mut store = MockStorage::new();
319        store.set(&[0xAA], &[0x11]);
320        store.set(&[0xAA, 0xBB], &[0x11, 0x22]);
321        store.set(&[0xAA, 0xBB, 0xCC], &[0x11, 0x22, 0x33]);
322        store.set(&[0xAA, 0xBB, 0xCC, 0xDD], &[0x11, 0x22, 0x33, 0x44]);
323        assert_eq!(
324            format!("{store:?}"),
325            "MemoryStorage (4 entries) {\n\
326            \x20\x200xaa: 0x11\n\
327            \x20\x200xaabb: 0x1122\n\
328            \x20\x200xaabbcc: 0x112233\n\
329            \x20\x200xaabbccdd: 0x11223344\n\
330            }"
331        );
332    }
333}