1 // This file is part of ICU4X. For terms of use, please see the file
2 // called LICENSE at the top level of the ICU4X source tree
3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5 //! Test utilities, primarily targeted to custom LiteMap stores.
6
7 use crate::store::*;
8 use crate::LiteMap;
9 use alloc::vec::Vec;
10 use core::fmt::Debug;
11
12 // Test code
13 #[allow(clippy::expect_used)]
check_equivalence<'a, K, V, S0, S1>(mut a: S0, mut b: S1) where K: Ord + Debug + PartialEq + 'a, V: Debug + PartialEq + 'a, S0: StoreMut<K, V> + StoreIterable<'a, K, V>, S1: StoreMut<K, V> + StoreIterable<'a, K, V>,14 fn check_equivalence<'a, K, V, S0, S1>(mut a: S0, mut b: S1)
15 where
16 K: Ord + Debug + PartialEq + 'a,
17 V: Debug + PartialEq + 'a,
18 S0: StoreMut<K, V> + StoreIterable<'a, K, V>,
19 S1: StoreMut<K, V> + StoreIterable<'a, K, V>,
20 {
21 let len = a.lm_len();
22 assert_eq!(len, b.lm_len());
23 if len == 0 {
24 assert!(a.lm_is_empty());
25 assert!(b.lm_is_empty());
26 }
27 for i in 0..len {
28 let a_kv = a.lm_get(i);
29 let b_kv = b.lm_get(i);
30 assert!(a_kv.is_some());
31 assert_eq!(a_kv, b_kv);
32 let a_kv_mut = a.lm_get_mut(i);
33 let b_kv_mut = b.lm_get_mut(i);
34 assert!(a_kv_mut.is_some());
35 assert_eq!(a_kv_mut, b_kv_mut);
36 }
37 for j in 0..len {
38 let needle = a.lm_get(j).expect("j is in range").0;
39 let a_binary = a.lm_binary_search_by(|k| k.cmp(needle));
40 let b_binary = a.lm_binary_search_by(|k| k.cmp(needle));
41 assert_eq!(Ok(j), a_binary);
42 assert_eq!(Ok(j), b_binary);
43 }
44 assert!(a.lm_get(len).is_none());
45 assert!(b.lm_get(len).is_none());
46 assert_eq!(a.lm_last(), b.lm_last());
47 }
48
49 // Test code
50 #[allow(clippy::expect_used)]
check_into_iter_equivalence<K, V, S0, S1>(a: S0, b: S1) where K: Ord + Debug + PartialEq, V: Debug + PartialEq, S0: StoreIntoIterator<K, V>, S1: StoreIntoIterator<K, V>,51 fn check_into_iter_equivalence<K, V, S0, S1>(a: S0, b: S1)
52 where
53 K: Ord + Debug + PartialEq,
54 V: Debug + PartialEq,
55 S0: StoreIntoIterator<K, V>,
56 S1: StoreIntoIterator<K, V>,
57 {
58 let a_vec = a.lm_into_iter().collect::<Vec<_>>();
59 let b_vec = b.lm_into_iter().collect::<Vec<_>>();
60 assert_eq!(a_vec, b_vec);
61 }
62
63 const SORTED_DATA: &[(u32, u64)] = &[
64 (106, 4816),
65 (147, 9864),
66 (188, 8588),
67 (252, 6031),
68 (434, 2518),
69 (574, 8500),
70 (607, 3756),
71 (619, 4965),
72 (663, 2669),
73 (724, 9211),
74 ];
75
76 const RANDOM_DATA: &[(u32, u64)] = &[
77 (546, 7490),
78 (273, 4999),
79 (167, 8078),
80 (176, 2101),
81 (373, 1304),
82 (339, 9613),
83 (561, 3620),
84 (301, 1214),
85 (483, 4453),
86 (704, 5359),
87 ];
88
89 // Test code
90 #[allow(clippy::expect_used)]
91 #[allow(clippy::panic)]
populate_litemap<S>(map: &mut LiteMap<u32, u64, S>) where S: StoreMut<u32, u64> + Debug,92 fn populate_litemap<S>(map: &mut LiteMap<u32, u64, S>)
93 where
94 S: StoreMut<u32, u64> + Debug,
95 {
96 assert_eq!(0, map.len());
97 assert!(map.is_empty());
98 for (k, v) in SORTED_DATA.iter() {
99 #[allow(clippy::single_match)] // for clarity
100 match map.try_append(*k, *v) {
101 Some(_) => panic!("appending sorted data: {k:?} to {map:?}"),
102 None => (), // OK
103 };
104 }
105 assert_eq!(10, map.len());
106 for (k, v) in RANDOM_DATA.iter() {
107 #[allow(clippy::single_match)] // for clarity
108 match map.try_append(*k, *v) {
109 Some(_) => (), // OK
110 None => panic!("cannot append random data: {k:?} to{map:?}"),
111 };
112 }
113 assert_eq!(10, map.len());
114 for (k, v) in RANDOM_DATA.iter() {
115 map.insert(*k, *v);
116 }
117 assert_eq!(20, map.len());
118 }
119
120 /// Tests that a litemap that uses the given store as backend has behavior consistent with the
121 /// reference impl.
122 ///
123 /// Call this function in a test with the store impl to test as a valid backend for LiteMap.
124 // Test code
125 #[allow(clippy::expect_used)]
check_store<'a, S>() where S: StoreConstEmpty<u32, u64> + StoreMut<u32, u64> + StoreIterable<'a, u32, u64> + StoreFromIterator<u32, u64> + Clone + Debug + PartialEq + 'a,126 pub fn check_store<'a, S>()
127 where
128 S: StoreConstEmpty<u32, u64>
129 + StoreMut<u32, u64>
130 + StoreIterable<'a, u32, u64>
131 + StoreFromIterator<u32, u64>
132 + Clone
133 + Debug
134 + PartialEq
135 + 'a,
136 {
137 let mut litemap_test: LiteMap<u32, u64, S> = LiteMap::new();
138 assert!(litemap_test.is_empty());
139 let mut litemap_std = LiteMap::<u32, u64>::new();
140 populate_litemap(&mut litemap_test);
141 populate_litemap(&mut litemap_std);
142 check_equivalence(litemap_test.clone().values, litemap_std.clone().values);
143
144 litemap_test.retain(|_, v| v % 2 == 0);
145 litemap_std.retain(|_, v| v % 2 == 0);
146 assert_eq!(11, litemap_test.len());
147 assert_eq!(11, litemap_std.len());
148 check_equivalence(litemap_test.clone().values, litemap_std.clone().values);
149
150 litemap_test
151 .remove(&175)
152 .ok_or(())
153 .expect_err("does not exist");
154 litemap_test.remove(&147).ok_or(()).expect("exists");
155 litemap_std
156 .remove(&175)
157 .ok_or(())
158 .expect_err("does not exist");
159 litemap_std.remove(&147).ok_or(()).expect("exists");
160
161 assert_eq!(10, litemap_test.len());
162 assert_eq!(10, litemap_std.len());
163 check_equivalence(litemap_test.clone().values, litemap_std.clone().values);
164
165 litemap_test.clear();
166 litemap_std.clear();
167 check_equivalence(litemap_test.values, litemap_std.values);
168 }
169
170 /// Similar to [`check_store`] function, but also checks the validitiy of [`StoreIterableMut`]
171 /// trait.
172 // Test code
173 #[allow(clippy::expect_used)]
check_store_full<'a, S>() where S: StoreConstEmpty<u32, u64> + StoreIterableMut<'a, u32, u64> + StoreIntoIterator<u32, u64> + StoreFromIterator<u32, u64> + Clone + Debug + PartialEq + 'a,174 pub fn check_store_full<'a, S>()
175 where
176 S: StoreConstEmpty<u32, u64>
177 + StoreIterableMut<'a, u32, u64>
178 + StoreIntoIterator<u32, u64>
179 + StoreFromIterator<u32, u64>
180 + Clone
181 + Debug
182 + PartialEq
183 + 'a,
184 {
185 let mut litemap_test: LiteMap<u32, u64, S> = LiteMap::new();
186 assert!(litemap_test.is_empty());
187 let mut litemap_std = LiteMap::<u32, u64>::new();
188 populate_litemap(&mut litemap_test);
189 populate_litemap(&mut litemap_std);
190 check_equivalence(litemap_test.clone().values, litemap_std.clone().values);
191 check_into_iter_equivalence(litemap_test.clone().values, litemap_std.clone().values);
192
193 let extras_test = litemap_test.clone();
194 let extras_test = litemap_test
195 .extend_from_litemap(extras_test)
196 .expect("duplicates");
197 assert_eq!(extras_test, litemap_test);
198 let extras_std = litemap_std.clone();
199 check_equivalence(litemap_test.clone().values, litemap_std.clone().values);
200 check_into_iter_equivalence(litemap_test.clone().values, litemap_std.clone().values);
201
202 litemap_test.retain(|_, v| v % 2 == 0);
203 litemap_std.retain(|_, v| v % 2 == 0);
204 assert_eq!(11, litemap_test.len());
205 assert_eq!(11, litemap_std.len());
206 check_equivalence(litemap_test.clone().values, litemap_std.clone().values);
207 check_into_iter_equivalence(litemap_test.clone().values, litemap_std.clone().values);
208
209 let extras_test = litemap_test
210 .extend_from_litemap(extras_test)
211 .expect("duplicates");
212 let extras_std = litemap_std
213 .extend_from_litemap(extras_std)
214 .expect("duplicates");
215 assert_eq!(11, extras_test.len());
216 assert_eq!(11, extras_std.len());
217 assert_eq!(20, litemap_test.len());
218 assert_eq!(20, litemap_std.len());
219 check_equivalence(litemap_test.clone().values, litemap_std.clone().values);
220 check_into_iter_equivalence(litemap_test.clone().values, litemap_std.clone().values);
221
222 litemap_test
223 .remove(&175)
224 .ok_or(())
225 .expect_err("does not exist");
226 litemap_test.remove(&176).ok_or(()).expect("exists");
227 litemap_std
228 .remove(&175)
229 .ok_or(())
230 .expect_err("does not exist");
231 litemap_std.remove(&176).ok_or(()).expect("exists");
232 assert_eq!(19, litemap_test.len());
233 assert_eq!(19, litemap_std.len());
234 check_equivalence(litemap_test.clone().values, litemap_std.clone().values);
235 check_into_iter_equivalence(litemap_test.clone().values, litemap_std.clone().values);
236
237 litemap_test.clear();
238 litemap_std.clear();
239 check_equivalence(litemap_test.clone().values, litemap_std.clone().values);
240 check_into_iter_equivalence(litemap_test.values, litemap_std.values);
241 }
242