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/instance.hpp"
39 #include "common/type_traits.hpp"
40 
41 #include "test_util.h"
42 
43 namespace ot {
44 
TestArray(void)45 void TestArray(void)
46 {
47     constexpr uint16_t kMaxSize    = 10;
48     constexpr uint16_t kStartValue = 100;
49 
50     Array<uint16_t, kMaxSize> array;
51     uint8_t                   index;
52     uint16_t                  seed;
53 
54     // All methods after constructor
55     VerifyOrQuit(array.IsEmpty());
56     VerifyOrQuit(!array.IsFull());
57     VerifyOrQuit(array.GetLength() == 0);
58     VerifyOrQuit(array.GetMaxSize() == kMaxSize);
59     VerifyOrQuit(array.At(0) == nullptr);
60     VerifyOrQuit(array.Front() == nullptr);
61     VerifyOrQuit(array.Back() == nullptr);
62     VerifyOrQuit(array.PopBack() == nullptr);
63 
64     seed = kStartValue;
65 
66     for (uint8_t len = 1; len <= kMaxSize; len++)
67     {
68         for (uint8_t iter = 0; iter < 2; iter++)
69         {
70             // On `iter == 0` use `PushBack(aEntry)` and on `iter == 1`
71             // `PushBack()` version which returns a pointer to the newly
72             // added entry.
73 
74             if (iter == 0)
75             {
76                 SuccessOrQuit(array.PushBack(seed + len));
77             }
78             else
79             {
80                 uint16_t *entry = array.PushBack();
81 
82                 VerifyOrQuit(entry != nullptr);
83                 *entry = seed + len;
84             }
85 
86             VerifyOrQuit(!array.IsEmpty());
87             VerifyOrQuit(array.IsFull() == (len == kMaxSize));
88             VerifyOrQuit(array.GetLength() == len);
89 
90             VerifyOrQuit(array.Front() != nullptr);
91             VerifyOrQuit(*array.Front() == seed + 1);
92             VerifyOrQuit(array.Back() != nullptr);
93             VerifyOrQuit(*array.Back() == seed + len);
94 
95             for (index = 0; index < len; index++)
96             {
97                 VerifyOrQuit(array[index] == seed + index + 1);
98                 VerifyOrQuit(array.At(index) != nullptr);
99                 VerifyOrQuit(*array.At(index) == seed + index + 1);
100 
101                 VerifyOrQuit(array.Contains(seed + index + 1));
102                 VerifyOrQuit(array.Find(seed + index + 1) == &array[index]);
103 
104                 VerifyOrQuit(!array.Contains(seed));
105                 VerifyOrQuit(array.Find(seed) == nullptr);
106             }
107 
108             index = 0;
109 
110             for (uint16_t value : array)
111             {
112                 VerifyOrQuit(value == array[index]);
113                 index++;
114             }
115 
116             index = 0;
117 
118             for (uint16_t &entry : array)
119             {
120                 // Uddate the value stored at the entry
121                 entry++;
122 
123                 VerifyOrQuit(entry == array[index]);
124                 VerifyOrQuit(array.IndexOf(entry) == index);
125 
126                 index++;
127             }
128 
129             seed++;
130 
131             // On `iter == 0` we verify `PopBack()` and remove the
132             // last entry. It will be added again from next `iter`
133             // loop (on `iter == 1`).
134 
135             if (iter == 0)
136             {
137                 uint16_t *entry = array.PopBack();
138 
139                 VerifyOrQuit(entry != nullptr);
140                 VerifyOrQuit(*entry == seed + len);
141                 VerifyOrQuit(array.GetLength() == len - 1);
142             }
143         }
144     }
145 
146     VerifyOrQuit(array.IsFull());
147     VerifyOrQuit(array.PushBack(0) == kErrorNoBufs);
148     VerifyOrQuit(array.PushBack() == nullptr);
149 
150     for (uint8_t len = kMaxSize; len >= 1; len--)
151     {
152         uint16_t *entry;
153 
154         VerifyOrQuit(array.GetLength() == len);
155         VerifyOrQuit(array.Back() == &array[len - 1]);
156 
157         entry = array.PopBack();
158         VerifyOrQuit(entry != nullptr);
159         VerifyOrQuit(*entry == seed + len);
160 
161         VerifyOrQuit(array.GetLength() == len - 1);
162         VerifyOrQuit(!array.IsFull());
163     }
164 
165     VerifyOrQuit(array.IsEmpty());
166 
167     SuccessOrQuit(array.PushBack(seed));
168     VerifyOrQuit(!array.IsEmpty());
169 
170     array.Clear();
171     VerifyOrQuit(array.IsEmpty());
172 }
173 
TestArrayCopyAndFindMatching(void)174 void TestArrayCopyAndFindMatching(void)
175 {
176     constexpr uint16_t kMaxSize = 10;
177 
178     struct Entry
179     {
180         Entry(void) = default;
181 
182         Entry(const char *aName, uint16_t aYear)
183             : mName(aName)
184             , mYear(aYear)
185         {
186         }
187 
188         bool operator==(const Entry &aOther) { return (mName == aOther.mName) && (mYear == aOther.mYear); }
189         bool Matches(const char *aName) const { return strcmp(aName, mName) == 0; }
190         bool Matches(uint16_t aYear) const { return aYear == mYear; }
191 
192         const char *mName;
193         uint16_t    mYear;
194     };
195 
196     Entry ps1("PS", 1994);
197     Entry ps2("PS2", 2000);
198     Entry ps3("PS3", 2006);
199     Entry ps4("PS4", 2013);
200     Entry ps5("PS5", 2020);
201 
202     Array<Entry, kMaxSize> array1;
203     Array<Entry, kMaxSize> array2;
204     Array<Entry, kMaxSize> array3(array1);
205 
206     VerifyOrQuit(array1.IsEmpty());
207     VerifyOrQuit(array2.IsEmpty());
208     VerifyOrQuit(array3.IsEmpty());
209 
210     SuccessOrQuit(array1.PushBack(ps1));
211     SuccessOrQuit(array1.PushBack(ps2));
212     SuccessOrQuit(array1.PushBack(ps3));
213     SuccessOrQuit(array1.PushBack(ps4));
214     VerifyOrQuit(array1.GetLength() == 4);
215 
216     SuccessOrQuit(array2.PushBack(ps3));
217     SuccessOrQuit(array2.PushBack(ps5));
218     VerifyOrQuit(array2.GetLength() == 2);
219 
220     array3 = array2 = array1;
221 
222     VerifyOrQuit(array1.GetLength() == 4);
223     VerifyOrQuit(array2.GetLength() == 4);
224     VerifyOrQuit(array3.GetLength() == 4);
225 
226     for (uint8_t index = 0; index < array1.GetLength(); index++)
227     {
228         VerifyOrQuit(array1[index] == array2[index]);
229         VerifyOrQuit(array1[index] == array3[index]);
230     }
231 
232     array3.Clear();
233 
234     array1 = array3;
235     VerifyOrQuit(array1.IsEmpty());
236     VerifyOrQuit(array1.GetLength() == 0);
237 
238     {
239         Array<Entry, kMaxSize> array4(array2);
240 
241         VerifyOrQuit(array4.GetLength() == 4);
242 
243         for (uint8_t index = 0; index < array1.GetLength(); index++)
244         {
245             VerifyOrQuit(array2[index] == array4[index]);
246         }
247     }
248 
249     SuccessOrQuit(array2.PushBack(ps5));
250     VerifyOrQuit(array2.GetLength() == 5);
251 
252     for (const Entry &entry : array2)
253     {
254         Entry *match;
255 
256         printf("- Name:%-3s Year:%d\n", entry.mName, entry.mYear);
257 
258         match = array2.FindMatching(entry.mName);
259         VerifyOrQuit(match != nullptr);
260         VerifyOrQuit(match == &entry);
261         VerifyOrQuit(array2.ContainsMatching(entry.mName));
262 
263         match = array2.FindMatching(entry.mYear);
264         VerifyOrQuit(match != nullptr);
265         VerifyOrQuit(match == &entry);
266         VerifyOrQuit(array2.ContainsMatching(entry.mYear));
267     }
268 
269     VerifyOrQuit(array2.FindMatching("PS6") == nullptr);
270     VerifyOrQuit(!array2.ContainsMatching("PS6"));
271     VerifyOrQuit(array2.FindMatching(static_cast<uint16_t>(2001)) == nullptr);
272     VerifyOrQuit(!array2.ContainsMatching(static_cast<uint16_t>(2001)));
273 
274     printf("\n");
275 }
276 
TestArrayIndexType(void)277 void TestArrayIndexType(void)
278 {
279     typedef Array<uint16_t, 255>           Array1;
280     typedef Array<uint16_t, 256>           Array2;
281     typedef Array<uint16_t, 100, uint16_t> Array3;
282 
283     static_assert(TypeTraits::IsSame<Array1::IndexType, uint8_t>::kValue, "Array1::IndexType is incorrect");
284     static_assert(TypeTraits::IsSame<Array2::IndexType, uint16_t>::kValue, "Array2::IndexType is incorrect");
285     static_assert(TypeTraits::IsSame<Array3::IndexType, uint16_t>::kValue, "Array3::IndexType is incorrect");
286 }
287 
288 } // namespace ot
289 
main(void)290 int main(void)
291 {
292     ot::TestArray();
293     ot::TestArrayCopyAndFindMatching();
294     ot::TestArrayIndexType();
295 
296     printf("All tests passed\n");
297     return 0;
298 }
299