1 /*
2 * Copyright (c) 2021, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdarg.h>
30 #include <string.h>
31
32 #include "test_platform.h"
33
34 #include <openthread/config.h>
35
36 #include "common/array.hpp"
37 #include "common/debug.hpp"
38 #include "common/equatable.hpp"
39 #include "common/type_traits.hpp"
40 #include "instance/instance.hpp"
41
42 #include "test_util.h"
43
44 namespace ot {
45
TestArray(void)46 void TestArray(void)
47 {
48 constexpr uint16_t kMaxSize = 10;
49 constexpr uint16_t kStartValue = 100;
50
51 Array<uint16_t, kMaxSize> array;
52 uint8_t index;
53 uint16_t seed;
54
55 // All methods after constructor
56 VerifyOrQuit(array.IsEmpty());
57 VerifyOrQuit(!array.IsFull());
58 VerifyOrQuit(array.GetLength() == 0);
59 VerifyOrQuit(array.GetMaxSize() == kMaxSize);
60 VerifyOrQuit(array.At(0) == nullptr);
61 VerifyOrQuit(array.Front() == nullptr);
62 VerifyOrQuit(array.Back() == nullptr);
63 VerifyOrQuit(array.PopBack() == nullptr);
64
65 seed = kStartValue;
66
67 for (uint8_t len = 1; len <= kMaxSize; len++)
68 {
69 for (uint8_t iter = 0; iter < 2; iter++)
70 {
71 // On `iter == 0` use `PushBack(aEntry)` and on `iter == 1`
72 // `PushBack()` version which returns a pointer to the newly
73 // added entry.
74
75 if (iter == 0)
76 {
77 SuccessOrQuit(array.PushBack(seed + len));
78 }
79 else
80 {
81 uint16_t *entry = array.PushBack();
82
83 VerifyOrQuit(entry != nullptr);
84 *entry = seed + len;
85 }
86
87 VerifyOrQuit(!array.IsEmpty());
88 VerifyOrQuit(array.IsFull() == (len == kMaxSize));
89 VerifyOrQuit(array.GetLength() == len);
90
91 VerifyOrQuit(array.Front() != nullptr);
92 VerifyOrQuit(*array.Front() == seed + 1);
93 VerifyOrQuit(array.Back() != nullptr);
94 VerifyOrQuit(*array.Back() == seed + len);
95
96 for (index = 0; index < len; index++)
97 {
98 VerifyOrQuit(array[index] == seed + index + 1);
99 VerifyOrQuit(array.At(index) != nullptr);
100 VerifyOrQuit(*array.At(index) == seed + index + 1);
101
102 VerifyOrQuit(array.Contains(seed + index + 1));
103 VerifyOrQuit(array.Find(seed + index + 1) == &array[index]);
104
105 VerifyOrQuit(!array.Contains(seed));
106 VerifyOrQuit(array.Find(seed) == nullptr);
107 }
108
109 index = 0;
110
111 for (uint16_t value : array)
112 {
113 VerifyOrQuit(value == array[index]);
114 index++;
115 }
116
117 index = 0;
118
119 for (uint16_t &entry : array)
120 {
121 // Uddate the value stored at the entry
122 entry++;
123
124 VerifyOrQuit(entry == array[index]);
125 VerifyOrQuit(array.IndexOf(entry) == index);
126
127 index++;
128 }
129
130 seed++;
131
132 // On `iter == 0` we verify `PopBack()` and remove the
133 // last entry. It will be added again from next `iter`
134 // loop (on `iter == 1`).
135
136 if (iter == 0)
137 {
138 uint16_t *entry = array.PopBack();
139
140 VerifyOrQuit(entry != nullptr);
141 VerifyOrQuit(*entry == seed + len);
142 VerifyOrQuit(array.GetLength() == len - 1);
143 }
144 }
145 }
146
147 VerifyOrQuit(array.IsFull());
148 VerifyOrQuit(array.PushBack(0) == kErrorNoBufs);
149 VerifyOrQuit(array.PushBack() == nullptr);
150
151 for (uint8_t len = kMaxSize; len >= 1; len--)
152 {
153 uint16_t *entry;
154
155 VerifyOrQuit(array.GetLength() == len);
156 VerifyOrQuit(array.Back() == &array[len - 1]);
157
158 entry = array.PopBack();
159 VerifyOrQuit(entry != nullptr);
160 VerifyOrQuit(*entry == seed + len);
161
162 VerifyOrQuit(array.GetLength() == len - 1);
163 VerifyOrQuit(!array.IsFull());
164 }
165
166 VerifyOrQuit(array.IsEmpty());
167
168 SuccessOrQuit(array.PushBack(seed));
169 VerifyOrQuit(!array.IsEmpty());
170
171 array.Clear();
172 VerifyOrQuit(array.IsEmpty());
173 }
174
TestArrayCopyAndFindMatching(void)175 void TestArrayCopyAndFindMatching(void)
176 {
177 constexpr uint16_t kMaxSize = 10;
178
179 enum MatchMode : uint8_t
180 {
181 kMatchAll,
182 kMatchNone,
183 kMatchOddYear,
184 kMatchEvenYear,
185 };
186
187 struct Entry : public Unequatable<Entry>
188 {
189 Entry(void) = default;
190
191 Entry(const char *aName, uint16_t aYear)
192 : mName(aName)
193 , mYear(aYear)
194 {
195 }
196
197 bool operator==(const Entry &aOther) const { return (mName == aOther.mName) && (mYear == aOther.mYear); }
198 bool Matches(const char *aName) const { return strcmp(aName, mName) == 0; }
199 bool Matches(uint16_t aYear) const { return aYear == mYear; }
200
201 bool Matches(MatchMode aMatchMode) const
202 {
203 bool matches = false;
204
205 switch (aMatchMode)
206 {
207 case kMatchAll:
208 matches = true;
209 break;
210 case kMatchNone:
211 matches = false;
212 break;
213 case kMatchOddYear:
214 matches = ((mYear % 2) != 0);
215 break;
216 case kMatchEvenYear:
217 matches = ((mYear % 2) == 0);
218 break;
219 }
220
221 return matches;
222 }
223
224 const char *mName;
225 uint16_t mYear;
226 };
227
228 static const MatchMode kMatchModes[] = {kMatchAll, kMatchNone, kMatchEvenYear, kMatchOddYear};
229
230 static const char *kMatchModeStrings[] = {
231 "kMatchAll",
232 "kMatchNone",
233 "kMatchOddYear",
234 "kMatchEvenYear",
235 };
236
237 Entry ps1("PS", 1994);
238 Entry ps2("PS2", 1999);
239 Entry ps3("PS3", 2006);
240 Entry ps4("PS4", 2013);
241 Entry ps5("PS5", 2020);
242
243 Array<Entry, kMaxSize> array1;
244 Array<Entry, kMaxSize> array2;
245 Array<Entry, kMaxSize> array3(array1);
246
247 VerifyOrQuit(array1.IsEmpty());
248 VerifyOrQuit(array2.IsEmpty());
249 VerifyOrQuit(array3.IsEmpty());
250
251 SuccessOrQuit(array1.PushBack(ps1));
252 SuccessOrQuit(array1.PushBack(ps2));
253 SuccessOrQuit(array1.PushBack(ps3));
254 SuccessOrQuit(array1.PushBack(ps4));
255 VerifyOrQuit(array1.GetLength() == 4);
256
257 SuccessOrQuit(array2.PushBack(ps3));
258 SuccessOrQuit(array2.PushBack(ps5));
259 VerifyOrQuit(array2.GetLength() == 2);
260
261 array3 = array2 = array1;
262
263 VerifyOrQuit(array1.GetLength() == 4);
264 VerifyOrQuit(array2.GetLength() == 4);
265 VerifyOrQuit(array3.GetLength() == 4);
266
267 for (uint8_t index = 0; index < array1.GetLength(); index++)
268 {
269 VerifyOrQuit(array1[index] == array2[index]);
270 VerifyOrQuit(array1[index] == array3[index]);
271 }
272
273 array3.Clear();
274
275 array1 = array3;
276 VerifyOrQuit(array1.IsEmpty());
277 VerifyOrQuit(array1.GetLength() == 0);
278
279 {
280 Array<Entry, kMaxSize> array4(array2);
281
282 VerifyOrQuit(array4.GetLength() == 4);
283
284 for (uint8_t index = 0; index < array1.GetLength(); index++)
285 {
286 VerifyOrQuit(array2[index] == array4[index]);
287 }
288 }
289
290 SuccessOrQuit(array2.PushBack(ps5));
291 VerifyOrQuit(array2.GetLength() == 5);
292
293 for (const Entry &entry : array2)
294 {
295 Entry *match;
296
297 printf("- Name:%-3s Year:%d\n", entry.mName, entry.mYear);
298
299 match = array2.FindMatching(entry.mName);
300 VerifyOrQuit(match != nullptr);
301 VerifyOrQuit(match == &entry);
302 VerifyOrQuit(array2.ContainsMatching(entry.mName));
303
304 match = array2.FindMatching(entry.mYear);
305 VerifyOrQuit(match != nullptr);
306 VerifyOrQuit(match == &entry);
307 VerifyOrQuit(array2.ContainsMatching(entry.mYear));
308 }
309
310 VerifyOrQuit(array2.FindMatching("PS6") == nullptr);
311 VerifyOrQuit(!array2.ContainsMatching("PS6"));
312 VerifyOrQuit(array2.FindMatching(static_cast<uint16_t>(2001)) == nullptr);
313 VerifyOrQuit(!array2.ContainsMatching(static_cast<uint16_t>(2001)));
314
315 // Test removing of entries at every index.
316
317 array1 = array2;
318
319 for (const Entry &entryToRemove : array1)
320 {
321 Entry *match;
322
323 // Test `Remove()`
324
325 array2 = array1;
326 match = array2.Find(entryToRemove);
327 VerifyOrQuit(match != nullptr);
328 array2.Remove(*match);
329
330 VerifyOrQuit(array2.GetLength() == array1.GetLength() - 1);
331
332 for (const Entry &entry : array2)
333 {
334 VerifyOrQuit(entry != entryToRemove);
335 VerifyOrQuit(array1.Contains(entry));
336 }
337
338 // Test `RemoveMatching()`
339
340 array2 = array1;
341 array2.RemoveMatching(entryToRemove.mName);
342
343 printf("\n- - - - - - - - - - - - - - - - - - - - - - - - ");
344 printf("\nArray after `RemoveMatching()` on entry %s\n", entryToRemove.mName);
345
346 VerifyOrQuit(array2.GetLength() == array1.GetLength() - 1);
347
348 for (const Entry &entry : array2)
349 {
350 printf("- Name:%-3s Year:%d\n", entry.mName, entry.mYear);
351 VerifyOrQuit(entry != entryToRemove);
352 VerifyOrQuit(array1.Contains(entry));
353 }
354
355 // Test `RemoveMatchin()` with a non-existing match
356
357 array2.RemoveMatching(entryToRemove.mName);
358 VerifyOrQuit(array2.GetLength() == array1.GetLength() - 1);
359
360 // Test `RemoveAllMatching()` removing a single matching entry.
361
362 array2 = array1;
363 array2.RemoveAllMatching(entryToRemove.mName);
364
365 VerifyOrQuit(array2.GetLength() == array1.GetLength() - 1);
366
367 for (const Entry &entry : array2)
368 {
369 VerifyOrQuit(entry != entryToRemove);
370 VerifyOrQuit(array1.Contains(entry));
371 }
372
373 array2.RemoveAllMatching(entryToRemove.mName);
374 VerifyOrQuit(array2.GetLength() == array1.GetLength() - 1);
375
376 // Test `RemoveAllMatching()` using different match modes
377 // removing different subsets.
378
379 for (MatchMode matchMode : kMatchModes)
380 {
381 array3 = array2;
382
383 array3.RemoveAllMatching(matchMode);
384
385 printf("\nArray after `RemoveAllMatching(%s)\n", kMatchModeStrings[matchMode]);
386
387 for (const Entry &entry : array3)
388 {
389 VerifyOrQuit(!entry.Matches(matchMode));
390 VerifyOrQuit(array2.Contains(entry));
391 printf("- Name:%-3s Year:%d\n", entry.mName, entry.mYear);
392 }
393
394 for (const Entry &entry : array2)
395 {
396 if (!entry.Matches(matchMode))
397 {
398 VerifyOrQuit(array2.Contains(entry));
399 }
400 }
401
402 array3.RemoveAllMatching(kMatchAll);
403 VerifyOrQuit(array3.IsEmpty());
404 }
405 }
406
407 printf("\n");
408 }
409
TestArrayIndexType(void)410 void TestArrayIndexType(void)
411 {
412 typedef Array<uint16_t, 255> Array1;
413 typedef Array<uint16_t, 256> Array2;
414 typedef Array<uint16_t, 100, uint16_t> Array3;
415
416 static_assert(TypeTraits::IsSame<Array1::IndexType, uint8_t>::kValue, "Array1::IndexType is incorrect");
417 static_assert(TypeTraits::IsSame<Array2::IndexType, uint16_t>::kValue, "Array2::IndexType is incorrect");
418 static_assert(TypeTraits::IsSame<Array3::IndexType, uint16_t>::kValue, "Array3::IndexType is incorrect");
419 }
420
421 } // namespace ot
422
main(void)423 int main(void)
424 {
425 ot::TestArray();
426 ot::TestArrayCopyAndFindMatching();
427 ot::TestArrayIndexType();
428
429 printf("All tests passed\n");
430 return 0;
431 }
432