Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / transport / retransmit / tests / TestCache.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *
5  *    Licensed under the Apache License, Version 2.0 (the "License");
6  *    you may not use this file except in compliance with the License.
7  *    You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *    Unless required by applicable law or agreed to in writing, software
12  *    distributed under the License is distributed on an "AS IS" BASIS,
13  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *    See the License for the specific language governing permissions and
15  *    limitations under the License.
16  */
17
18 #include "TestRetransmit.h"
19
20 #include <support/UnitTestRegistration.h>
21 #include <transport/retransmit/Cache.h>
22
23 #include <bitset>
24 #include <nlunit-test.h>
25
26 // Helpers for simple payload management
27 namespace {
28 constexpr int kMaxPayloadValue = 100;
29
30 /**
31  * Derived cache class containing some test helper methods.
32  */
33 template <typename KeyType, typename PayloadType, size_t N>
34 class TestableCache : public chip::Retransmit::Cache<KeyType, PayloadType, N>
35 {
36 public:
37     /**
38      * Convenience add when types are trivially copyable, so no actual
39      * reference needs to be created.
40      */
41     template <typename = std::enable_if<std::is_trivially_copyable<PayloadType>::value, int>>
42     CHIP_ERROR AddValue(const KeyType & key, PayloadType payload)
43     {
44         return chip::Retransmit::Cache<KeyType, PayloadType, N>::Add(key, payload);
45     }
46 };
47
48 class IntPayloadTracker
49 {
50 public:
51     void Init(nlTestSuite * suite) { mSuite = suite; }
52
53     void Acquire(int value)
54     {
55         NL_TEST_ASSERT(mSuite, (value > 0) && value < kMaxPayloadValue);
56         mAquired.set(static_cast<size_t>(value));
57     }
58
59     void Release(int value)
60     {
61         NL_TEST_ASSERT(mSuite, (value > 0) && value < kMaxPayloadValue);
62         NL_TEST_ASSERT(mSuite, mAquired.test(static_cast<size_t>(value)));
63         mAquired.reset(static_cast<size_t>(value));
64     }
65
66     size_t Count() const { return mAquired.count(); }
67
68     bool IsAquired(int value) const { return mAquired.test(static_cast<size_t>(value)); }
69
70 private:
71     nlTestSuite * mSuite;
72     std::bitset<kMaxPayloadValue> mAquired;
73 };
74
75 IntPayloadTracker gPayloadTracker;
76
77 /**
78  * Helper class defining a matches method for things divisible by a
79  * specific value.
80  */
81 class DivisibleBy
82 {
83 public:
84     DivisibleBy(int value) : mValue(value) {}
85
86     bool Matches(int x) const { return (x % mValue) == 0; }
87
88 private:
89     const int mValue;
90 };
91
92 } // namespace
93
94 template <>
95 int chip::Retransmit::Lifetime<int>::Acquire(int & value)
96 {
97     gPayloadTracker.Acquire(value);
98     return value;
99 }
100
101 template <>
102 void chip::Retransmit::Lifetime<int>::Release(int & value)
103 {
104     gPayloadTracker.Release(value);
105     value = 0; // make sure it is not used anymore
106 }
107
108 namespace {
109
110 void TestNoOp(nlTestSuite * inSuite, void * inContext)
111 {
112     // unused address cache should not do any aquire/release at any time
113     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
114     {
115         TestableCache<int, int, 20> test;
116         NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
117     }
118     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
119 }
120
121 void TestDestructorFree(nlTestSuite * inSuite, void * inContext)
122 {
123     {
124         TestableCache<int, int, 20> test;
125
126         NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
127
128         NL_TEST_ASSERT(inSuite, test.AddValue(1, 1) == CHIP_NO_ERROR);
129         NL_TEST_ASSERT(inSuite, test.AddValue(2, 2) == CHIP_NO_ERROR);
130
131         NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 2);
132     }
133
134     // destructor should release the items
135     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
136 }
137
138 void OutOfSpace(nlTestSuite * inSuite, void * inContext)
139 {
140     {
141         TestableCache<int, int, 4> test;
142
143         NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
144
145         NL_TEST_ASSERT(inSuite, test.AddValue(1, 1) == CHIP_NO_ERROR);
146         NL_TEST_ASSERT(inSuite, test.AddValue(2, 2) == CHIP_NO_ERROR);
147         NL_TEST_ASSERT(inSuite, test.AddValue(3, 4) == CHIP_NO_ERROR);
148         NL_TEST_ASSERT(inSuite, test.AddValue(4, 6) == CHIP_NO_ERROR);
149         NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 4);
150
151         NL_TEST_ASSERT(inSuite, test.AddValue(5, 8) == CHIP_ERROR_NO_MEMORY);
152         NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 4);
153
154         NL_TEST_ASSERT(inSuite, test.AddValue(6, 10) == CHIP_ERROR_NO_MEMORY);
155         NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 4);
156     }
157     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
158 }
159
160 void AddRemove(nlTestSuite * inSuite, void * inContext)
161 {
162     TestableCache<int, int, 3> test;
163
164     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
165
166     NL_TEST_ASSERT(inSuite, test.AddValue(1, 1) == CHIP_NO_ERROR);
167     NL_TEST_ASSERT(inSuite, test.AddValue(2, 2) == CHIP_NO_ERROR);
168     NL_TEST_ASSERT(inSuite, test.AddValue(3, 4) == CHIP_NO_ERROR);
169     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 3);
170
171     NL_TEST_ASSERT(inSuite, test.AddValue(10, 8) == CHIP_ERROR_NO_MEMORY);
172     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 3);
173
174     NL_TEST_ASSERT(inSuite, test.Remove(2) == CHIP_NO_ERROR);
175     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 2);
176
177     NL_TEST_ASSERT(inSuite, test.AddValue(10, 8) == CHIP_NO_ERROR);
178     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 3);
179
180     NL_TEST_ASSERT(inSuite, test.Remove(14) == CHIP_ERROR_KEY_NOT_FOUND);
181     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 3);
182
183     NL_TEST_ASSERT(inSuite, test.Remove(1) == CHIP_NO_ERROR);
184     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 2);
185
186     NL_TEST_ASSERT(inSuite, test.Remove(3) == CHIP_NO_ERROR);
187     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 1);
188
189     NL_TEST_ASSERT(inSuite, test.Remove(3) == CHIP_ERROR_KEY_NOT_FOUND);
190     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 1);
191
192     NL_TEST_ASSERT(inSuite, test.Remove(10) == CHIP_NO_ERROR);
193     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
194
195     NL_TEST_ASSERT(inSuite, test.Remove(10) == CHIP_ERROR_KEY_NOT_FOUND);
196     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
197 }
198
199 void RemoveMatching(nlTestSuite * inSuite, void * inContext)
200 {
201     TestableCache<int, int, 4> test;
202
203     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
204
205     NL_TEST_ASSERT(inSuite, test.AddValue(1, 1) == CHIP_NO_ERROR);
206     NL_TEST_ASSERT(inSuite, test.AddValue(2, 2) == CHIP_NO_ERROR);
207     NL_TEST_ASSERT(inSuite, test.AddValue(3, 4) == CHIP_NO_ERROR);
208     NL_TEST_ASSERT(inSuite, test.AddValue(4, 8) == CHIP_NO_ERROR);
209     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 4);
210
211     test.RemoveMatching(DivisibleBy(2));
212     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 2);
213
214     // keys 1 and 3 remain
215     NL_TEST_ASSERT(inSuite, gPayloadTracker.IsAquired(1));
216     NL_TEST_ASSERT(inSuite, gPayloadTracker.IsAquired(4));
217
218     NL_TEST_ASSERT(inSuite, test.Remove(3) == CHIP_NO_ERROR);
219     NL_TEST_ASSERT(inSuite, gPayloadTracker.IsAquired(1));
220     NL_TEST_ASSERT(inSuite, !gPayloadTracker.IsAquired(4));
221 }
222
223 void FindMatching(nlTestSuite * inSuite, void * inContext)
224 {
225     TestableCache<int, int, 4> test;
226
227     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 0);
228
229     NL_TEST_ASSERT(inSuite, test.AddValue(1, 1) == CHIP_NO_ERROR);
230     NL_TEST_ASSERT(inSuite, test.AddValue(2, 2) == CHIP_NO_ERROR);
231     NL_TEST_ASSERT(inSuite, test.AddValue(3, 4) == CHIP_NO_ERROR);
232     NL_TEST_ASSERT(inSuite, test.AddValue(4, 8) == CHIP_NO_ERROR);
233     NL_TEST_ASSERT(inSuite, gPayloadTracker.Count() == 4);
234
235     const int * key;
236     const int * value;
237
238     NL_TEST_ASSERT(inSuite, test.Find(DivisibleBy(20), &key, &value) == false);
239     NL_TEST_ASSERT(inSuite, key == nullptr);
240     NL_TEST_ASSERT(inSuite, value == nullptr);
241
242     // This relies on linear add. May need changing if implementation changes
243     NL_TEST_ASSERT(inSuite, test.Find(DivisibleBy(2), &key, &value) == true);
244     NL_TEST_ASSERT(inSuite, *key == 2);
245     NL_TEST_ASSERT(inSuite, *value == 2);
246
247     NL_TEST_ASSERT(inSuite, test.Remove(*key) == CHIP_NO_ERROR);
248
249     NL_TEST_ASSERT(inSuite, test.Find(DivisibleBy(2), &key, &value) == true);
250     NL_TEST_ASSERT(inSuite, *key == 4);
251     NL_TEST_ASSERT(inSuite, *value == 8);
252
253     NL_TEST_ASSERT(inSuite, test.Remove(*key) == CHIP_NO_ERROR);
254     NL_TEST_ASSERT(inSuite, test.Find(DivisibleBy(2), &key, &value) == false);
255     NL_TEST_ASSERT(inSuite, key == nullptr);
256     NL_TEST_ASSERT(inSuite, value == nullptr);
257 }
258
259 } // namespace
260
261 // clang-format off
262 static const nlTest sTests[] =
263 {
264     NL_TEST_DEF("NoOp", TestNoOp),
265     NL_TEST_DEF("DestructorFree", TestDestructorFree),
266     NL_TEST_DEF("OutOfSpace", OutOfSpace),
267     NL_TEST_DEF("AddRemove", AddRemove),
268     NL_TEST_DEF("RemoveMatching", RemoveMatching),
269     NL_TEST_DEF("FindMatching", FindMatching),
270     NL_TEST_SENTINEL()
271 };
272 // clang-format on
273
274 int TestCache(void)
275 {
276     nlTestSuite theSuite = { "Retransmit-Cache", &sTests[0], nullptr, nullptr };
277     gPayloadTracker.Init(&theSuite);
278     nlTestRunner(&theSuite, nullptr);
279     return nlTestRunnerStats(&theSuite);
280 }
281
282 CHIP_REGISTER_TEST_SUITE(TestCache)