1 /*
2 * Copyright (c) 2019, 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/debug.hpp"
37 #include "common/instance.hpp"
38 #include "common/linked_list.hpp"
39
40 #include "test_util.h"
41
42 struct EntryBase
43 {
44 EntryBase *mNext;
45 };
46
47 struct Entry : public EntryBase, ot::LinkedListEntry<Entry>
48 {
49 public:
EntryEntry50 Entry(const char *aName, uint16_t aId)
51 : mName(aName)
52 , mId(aId)
53 {
54 }
55
GetNameEntry56 const char *GetName(void) const { return mName; }
GetIdEntry57 uint16_t GetId(void) const { return mId; }
MatchesEntry58 bool Matches(const char *aName) const { return strcmp(mName, aName) == 0; }
MatchesEntry59 bool Matches(uint16_t aId) const { return mId == aId; }
60
61 private:
62 const char *mName;
63 uint16_t mId;
64 };
65
66 // This function verifies the content of the linked list matches a given list of entries.
VerifyLinkedListContent(const ot::LinkedList<Entry> * aList,...)67 void VerifyLinkedListContent(const ot::LinkedList<Entry> *aList, ...)
68 {
69 va_list args;
70 Entry * argEntry;
71 Entry * argPrev = nullptr;
72 const Entry *prev;
73 uint16_t unusedId = 100;
74
75 va_start(args, aList);
76
77 for (const Entry &entry : *aList)
78 {
79 argEntry = va_arg(args, Entry *);
80 VerifyOrQuit(argEntry != nullptr, "List contains more entries than expected");
81 VerifyOrQuit(argEntry == &entry, "List does not contain the same entry");
82 VerifyOrQuit(aList->Contains(*argEntry));
83 VerifyOrQuit(aList->ContainsMatching(argEntry->GetName()));
84 VerifyOrQuit(aList->ContainsMatching(argEntry->GetId()));
85
86 SuccessOrQuit(aList->Find(*argEntry, prev));
87 VerifyOrQuit(prev == argPrev, "List::Find() returned prev entry is incorrect");
88
89 VerifyOrQuit(aList->FindMatching(argEntry->GetName(), prev) == argEntry);
90 VerifyOrQuit(prev == argPrev, "List::FindMatching() returned prev entry is incorrect");
91
92 VerifyOrQuit(aList->FindMatching(argEntry->GetId(), prev) == argEntry);
93 VerifyOrQuit(prev == argPrev, "List::FindMatching() returned prev entry is incorrect");
94
95 argPrev = argEntry;
96 }
97
98 argEntry = va_arg(args, Entry *);
99 VerifyOrQuit(argEntry == nullptr, "List contains less entries than expected");
100
101 VerifyOrQuit(aList->GetTail() == argPrev);
102
103 VerifyOrQuit(!aList->ContainsMatching("none"), "succeeded for a missing entry");
104 VerifyOrQuit(!aList->ContainsMatching(unusedId), "succeeded for a missing entry");
105
106 VerifyOrQuit(aList->FindMatching("none", prev) == nullptr, "succeeded for a missing entry");
107 VerifyOrQuit(aList->FindMatching(unusedId, prev) == nullptr, "succeeded for a missing entry");
108 }
109
TestLinkedList(void)110 void TestLinkedList(void)
111 {
112 Entry a("a", 1), b("b", 2), c("c", 3), d("d", 4), e("e", 5);
113 Entry * prev;
114 ot::LinkedList<Entry> list;
115
116 VerifyOrQuit(list.IsEmpty(), "failed after init");
117 VerifyOrQuit(list.GetHead() == nullptr, "failed after init");
118 VerifyOrQuit(list.Pop() == nullptr, "failed when empty");
119 VerifyOrQuit(list.Find(a, prev) == ot::kErrorNotFound, "succeeded when empty");
120
121 VerifyLinkedListContent(&list, nullptr);
122
123 list.Push(a);
124 VerifyOrQuit(!list.IsEmpty());
125 VerifyLinkedListContent(&list, &a, nullptr);
126 VerifyOrQuit(list.Find(b, prev) == ot::kErrorNotFound, "succeeded for a missing entry");
127
128 SuccessOrQuit(list.Add(b));
129 VerifyLinkedListContent(&list, &b, &a, nullptr);
130 VerifyOrQuit(list.Find(c, prev) == ot::kErrorNotFound, "succeeded for a missing entry");
131
132 list.Push(c);
133 VerifyLinkedListContent(&list, &c, &b, &a, nullptr);
134
135 SuccessOrQuit(list.Add(d));
136 VerifyLinkedListContent(&list, &d, &c, &b, &a, nullptr);
137
138 SuccessOrQuit(list.Add(e));
139 VerifyLinkedListContent(&list, &e, &d, &c, &b, &a, nullptr);
140
141 VerifyOrQuit(list.Add(a) == ot::kErrorAlready, "did not detect duplicate");
142 VerifyOrQuit(list.Add(b) == ot::kErrorAlready, "did not detect duplicate");
143 VerifyOrQuit(list.Add(d) == ot::kErrorAlready, "did not detect duplicate");
144 VerifyOrQuit(list.Add(e) == ot::kErrorAlready, "did not detect duplicate");
145
146 VerifyOrQuit(list.Pop() == &e);
147 VerifyLinkedListContent(&list, &d, &c, &b, &a, nullptr);
148 VerifyOrQuit(list.Find(e, prev) == ot::kErrorNotFound, "succeeded for a missing entry");
149
150 VerifyOrQuit(list.FindMatching(d.GetName(), prev) == &d);
151 VerifyOrQuit(prev == nullptr);
152 VerifyOrQuit(list.FindMatching(c.GetId(), prev) == &c);
153 VerifyOrQuit(prev == &d);
154 VerifyOrQuit(list.FindMatching(b.GetName(), prev) == &b);
155 VerifyOrQuit(prev == &c);
156 VerifyOrQuit(list.FindMatching(a.GetId(), prev) == &a);
157 VerifyOrQuit(prev == &b);
158 VerifyOrQuit(list.FindMatching(e.GetId(), prev) == nullptr, "succeeded for a missing entry");
159 VerifyOrQuit(list.FindMatching(e.GetName(), prev) == nullptr, "succeeded for a missing entry");
160
161 list.SetHead(&e);
162 VerifyLinkedListContent(&list, &e, &d, &c, &b, &a, nullptr);
163
164 SuccessOrQuit(list.Remove(c));
165 VerifyLinkedListContent(&list, &e, &d, &b, &a, nullptr);
166
167 VerifyOrQuit(list.Remove(c) == ot::kErrorNotFound);
168 VerifyLinkedListContent(&list, &e, &d, &b, &a, nullptr);
169 VerifyOrQuit(list.Find(c, prev) == ot::kErrorNotFound, "succeeded for a missing entry");
170
171 SuccessOrQuit(list.Remove(e));
172 VerifyLinkedListContent(&list, &d, &b, &a, nullptr);
173 VerifyOrQuit(list.Find(e, prev) == ot::kErrorNotFound, "succeeded for a missing entry");
174
175 SuccessOrQuit(list.Remove(a));
176 VerifyLinkedListContent(&list, &d, &b, nullptr);
177 VerifyOrQuit(list.Find(a, prev) == ot::kErrorNotFound, "succeeded for a missing entry");
178
179 list.Push(a);
180 list.Push(c);
181 list.Push(e);
182 VerifyLinkedListContent(&list, &e, &c, &a, &d, &b, nullptr);
183
184 VerifyOrQuit(list.PopAfter(&a) == &d);
185 VerifyLinkedListContent(&list, &e, &c, &a, &b, nullptr);
186
187 VerifyOrQuit(list.PopAfter(&b) == nullptr);
188 VerifyLinkedListContent(&list, &e, &c, &a, &b, nullptr);
189
190 VerifyOrQuit(list.PopAfter(&e) == &c);
191 VerifyLinkedListContent(&list, &e, &a, &b, nullptr);
192
193 list.PushAfter(c, b);
194 VerifyLinkedListContent(&list, &e, &a, &b, &c, nullptr);
195
196 list.PushAfter(d, a);
197 VerifyLinkedListContent(&list, &e, &a, &d, &b, &c, nullptr);
198
199 VerifyOrQuit(list.PopAfter(nullptr) == &e);
200 VerifyLinkedListContent(&list, &a, &d, &b, &c, nullptr);
201
202 VerifyOrQuit(list.PopAfter(nullptr) == &a);
203 VerifyLinkedListContent(&list, &d, &b, &c, nullptr);
204
205 list.Push(e);
206 list.Push(a);
207 VerifyLinkedListContent(&list, &a, &e, &d, &b, &c, nullptr);
208
209 VerifyOrQuit(list.RemoveMatching(a.GetName()) == &a);
210 VerifyLinkedListContent(&list, &e, &d, &b, &c, nullptr);
211
212 VerifyOrQuit(list.RemoveMatching(c.GetId()) == &c);
213 VerifyLinkedListContent(&list, &e, &d, &b, nullptr);
214
215 VerifyOrQuit(list.RemoveMatching(c.GetId()) == nullptr, "succeeded for missing entry");
216 VerifyOrQuit(list.RemoveMatching(a.GetName()) == nullptr, "succeeded for missing entry");
217
218 VerifyOrQuit(list.RemoveMatching(d.GetId()) == &d);
219 VerifyLinkedListContent(&list, &e, &b, nullptr);
220
221 list.Clear();
222 VerifyOrQuit(list.IsEmpty(), "failed after Clear()");
223 VerifyOrQuit(list.PopAfter(nullptr) == nullptr);
224 VerifyLinkedListContent(&list, nullptr);
225 VerifyOrQuit(list.Find(a, prev) == ot::kErrorNotFound, "succeeded for a missing entry");
226 VerifyOrQuit(list.FindMatching(b.GetName(), prev) == nullptr, "succeeded when empty");
227 VerifyOrQuit(list.FindMatching(c.GetId(), prev) == nullptr, "succeeded when empty");
228 VerifyOrQuit(list.RemoveMatching(a.GetName()) == nullptr, "succeeded when empty");
229 VerifyOrQuit(list.Remove(a) == ot::kErrorNotFound, "succeeded when empty");
230 }
231
main(void)232 int main(void)
233 {
234 TestLinkedList();
235 printf("All tests passed\n");
236 return 0;
237 }
238