1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "safe_map.h"
16
17 #include <array>
18 #include <future>
19 #include <gtest/gtest.h>
20 #include <iostream>
21 #include <thread>
22 #include <chrono> // std::chrono::seconds
23 using namespace testing::ext;
24 using namespace std;
25
26 namespace OHOS {
27 namespace {
28 class UtilsSafeMap : public testing::Test {
29 };
30
31 /*
32 * @tc.name: testUtilsCopyAndAssign001
33 * @tc.desc: single thread test the normal feature insert and erase and EnsureInsert
34 */
35 HWTEST_F(UtilsSafeMap, testUtilsCopyAndAssign001, TestSize.Level0)
36 {
37 SafeMap<string, int> demoData;
38 // insert new
39 demoData.Insert("A", 1);
40 ASSERT_FALSE(demoData.IsEmpty());
41 ASSERT_EQ(demoData.Size(), 1);
42
43 SafeMap<string, int> newdemo = demoData;
44 int tar = -1;
45 ASSERT_TRUE(newdemo.Find("A", tar));
46 ASSERT_EQ(1, tar);
47
48 tar = -1;
49 SafeMap<string, int> newdemo2;
50 newdemo2 = demoData;
51 ASSERT_TRUE(newdemo2.Find("A", tar));
52 ASSERT_EQ(1, tar);
53 }
54
55 /*
56 * @tc.name: testUtilsoperator001
57 * @tc.desc: SafeMap
58 */
59 HWTEST_F(UtilsSafeMap, testUtilsoperator001, TestSize.Level0)
60 {
61 SafeMap<string, int> demoData;
62 // insert new
63 demoData.Insert("A", 1);
64 ASSERT_FALSE(demoData.IsEmpty());
65 ASSERT_EQ(demoData.Size(), 1);
66 ASSERT_EQ(demoData.ReadVal("A"), 1);
67
68 SafeMap<string, int> newdemo = demoData;
69 ASSERT_EQ(newdemo.ReadVal("A"), 1);
70
71 int tar = -1;
72 newdemo.Insert("B", 6);
73 ASSERT_TRUE(newdemo.Find("B", tar));
74 ASSERT_EQ(6, tar);
75
76 SafeMap<string, int> newdemo2;
77 newdemo2 = newdemo;
78 ASSERT_EQ(newdemo2.ReadVal("A"), 1);
79 }
80
81 /*
82 * @tc.name: testUtilsNormalFeatureInsert001
83 * @tc.desc: SafeMap
84 */
85 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureInsert001, TestSize.Level0)
86 {
87 SafeMap<string, int> demoData;
88 ASSERT_TRUE(demoData.IsEmpty());
89 // insert new
90 demoData.Insert("A", 1);
91 ASSERT_FALSE(demoData.IsEmpty());
92 ASSERT_EQ(demoData.Size(), 1);
93
94 // insert copy one should fail
95 ASSERT_FALSE(demoData.Insert("A", 2));
96 ASSERT_EQ(demoData.Size(), 1);
97 }
98
99 /*
100 * @tc.name: testUtilsNormalFeatureEnsureInsert001
101 * @tc.desc: SafeMap
102 */
103 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureEnsureInsert001, TestSize.Level0)
104 {
105 SafeMap<string, int> demoData;
106 ASSERT_TRUE(demoData.IsEmpty());
107
108 demoData.Insert("A", 1);
109 demoData.EnsureInsert("B", 2);
110
111 ASSERT_FALSE(demoData.IsEmpty());
112 ASSERT_EQ(demoData.Size(), 2);
113 // insert copy one and new one
114 demoData.EnsureInsert("B", 5);
115 demoData.EnsureInsert("C", 6);
116
117 ASSERT_EQ(demoData.Size(), 3);
118 }
119
120 /*
121 * @tc.name: testUtilsNormalFeatureFind001
122 * @tc.desc: SafeMap
123 */
124 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureFind001, TestSize.Level0)
125 {
126 SafeMap<string, int> demoData;
127 ASSERT_TRUE(demoData.IsEmpty());
128
129 demoData.Insert("A", 1);
130 demoData.Insert("B", 10000);
131 demoData.EnsureInsert("B", 2);
132 demoData.EnsureInsert("C", 6);
133
134 ASSERT_FALSE(demoData.IsEmpty());
135 ASSERT_EQ(demoData.Size(), 3);
136
137 int i = 0;
138 ASSERT_TRUE(demoData.Find("A", i));
139 ASSERT_EQ(i, 1);
140 ASSERT_TRUE(demoData.Find("B", i));
141 ASSERT_EQ(i, 2);
142
143 ASSERT_TRUE(demoData.Find("C", i));
144 ASSERT_EQ(i, 6);
145 }
146
147 /*
148 * @tc.name: testUtilsNormalFeatureFindAndSet001
149 * @tc.desc: SafeMap
150 */
151 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureFindAndSet001, TestSize.Level0)
152 {
153 SafeMap<string, int> demoData;
154 ASSERT_TRUE(demoData.IsEmpty());
155
156 demoData.Insert("A", 1);
157 demoData.EnsureInsert("B", 2);
158
159 int oldvalue = 0;
160 int newvalue = 3;
161 ASSERT_TRUE(demoData.FindOldAndSetNew("A", oldvalue, newvalue));
162 // old value
163 ASSERT_EQ(oldvalue, 1);
164
165 newvalue = 4;
166 ASSERT_TRUE(demoData.FindOldAndSetNew("B", oldvalue, newvalue));
167 // old value
168 ASSERT_EQ(oldvalue, 2);
169 int i = -1;
170 ASSERT_TRUE(demoData.Find("A", i));
171 // new value
172 ASSERT_EQ(i, 3);
173 ASSERT_TRUE(demoData.Find("B", i));
174 // new value
175 ASSERT_EQ(i, 4);
176 }
177
178 /*
179 * @tc.name: testUtilsNormalFeatureEraseAndClear001
180 * @tc.desc: SafeMap
181 */
182 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureEraseAndClear001, TestSize.Level0)
183 {
184 SafeMap<string, int> demoData;
185 ASSERT_TRUE(demoData.IsEmpty());
186
187 demoData.Insert("A", 1);
188 demoData.EnsureInsert("B", 2);
189
190 ASSERT_EQ(demoData.Size(), 2);
191 demoData.Erase("A");
192 ASSERT_EQ(demoData.Size(), 1);
193
194 demoData.Clear();
195 ASSERT_EQ(demoData.Size(), 0);
196 }
197
198 /*
199 * @tc.name: testUtilsNormalFeatureIterate001
200 * @tc.desc: Using Iterate to change the second parameter of SafeMap
201 */
Callback(const std::string str,int & value)202 void Callback(const std::string str, int& value)
203 {
204 value++;
205 }
206
207 HWTEST_F(UtilsSafeMap, testUtilsNormalFeatureIterate001, TestSize.Level0)
208 {
209 SafeMap<string, int> demoData;
210 ASSERT_TRUE(demoData.IsEmpty());
211
212 demoData.Insert("A", 1);
213 demoData.Insert("B", 2);
214 demoData.Insert("C", 3);
215 demoData.Insert("D", 4);
216 demoData.Iterate(Callback);
217
218 ASSERT_EQ(demoData.Size(), 4);
219 ASSERT_EQ(demoData.ReadVal("A"), 2);
220 ASSERT_EQ(demoData.ReadVal("B"), 3);
221 ASSERT_EQ(demoData.ReadVal("C"), 4);
222 ASSERT_EQ(demoData.ReadVal("D"), 5);
223 }
224
225 /*
226 * @tc.name: testUtilsConcurrentIterate001
227 * @tc.desc: 100 threads test in iterate operation to rewrite a SafeMap.
228 */
229 const int THREAD_NUM = 100;
230 const int DATA_NUM = 10;
231 HWTEST_F(UtilsSafeMap, testUtilsConcurrentIterate001, TestSize.Level0)
232 {
233 SafeMap<string, int> demoData;
234 for (int i = 0; i < DATA_NUM; i++) {
235 demoData.Insert("A" + std::to_string(i), 0);
236 }
237 std::thread threads[THREAD_NUM];
238
239 ASSERT_NO_THROW({
240 auto lamfuncIterate = [](SafeMap<string, int>& data, const int& cnt,
__anonf4da918c0202(SafeMap<string, int>& data, const int& cnt, const std::chrono::system_clock::time_point& absTime) 241 const std::chrono::system_clock::time_point& absTime) {
242 auto callback_it = [cnt](const string data, int& value) {
243 value = cnt;
244 };
245 std::this_thread::sleep_until(absTime);
246 data.Iterate(callback_it);
247 };
248
249 using std::chrono::system_clock;
250
251 std::time_t timeT = system_clock::to_time_t(system_clock::now());
252 timeT += 2;
253
254 for (int i = 0; i < THREAD_NUM; ++i) {
255 threads[i] = std::thread(lamfuncIterate, std::ref(demoData), i, system_clock::from_time_t(timeT));
256 }
257
258 std::this_thread::sleep_for(std::chrono::seconds(3));
259 for (auto& t : threads) {
260 t.join();
261 }
262
263 for (int i = 0; i < DATA_NUM - 1; i++) {
264 ASSERT_EQ(demoData.ReadVal("A" + std::to_string(i)), demoData.ReadVal("A" + std::to_string(i + 1)));
265 }
266 });
267 }
268
269 /*
270 * @tc.name: testUtilsConcurrentWriteAndRead001
271 * @tc.desc: 100 threads test in writein to the same key of the map, while read at same time and no throw
272 */
273 HWTEST_F(UtilsSafeMap, testUtilsConcurrentWriteAndRead001, TestSize.Level0)
274 {
275 SafeMap<string, int> demoData;
276 std::thread threads[THREAD_NUM];
277 std::thread checkThread[THREAD_NUM];
278 ASSERT_NO_THROW({
279 auto lamfuncInsert = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0402(SafeMap<string, int>& data, const string& key, const int& value, const std::chrono::system_clock::time_point& absTime) 280 const int& value, const std::chrono::system_clock::time_point& absTime) {
281 std::this_thread::sleep_until(absTime);
282 data.EnsureInsert(key, value);
283 };
284
285 auto lamfuncCheck = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0502(SafeMap<string, int>& data, const string& key, std::chrono::system_clock::time_point absTime) 286 std::chrono::system_clock::time_point absTime) {
287 std::this_thread::sleep_until(absTime);
288 thread_local int i = -1;
289 data.Find(key, i);
290 };
291
292 using std::chrono::system_clock;
293
294 std::time_t timeT = system_clock::to_time_t(system_clock::now());
295 timeT += 2;
296 string key("A");
297
298 for (int i = 0; i < THREAD_NUM; ++i) {
299 threads[i] = std::thread(lamfuncInsert, std::ref(demoData), key, i, system_clock::from_time_t(timeT));
300 checkThread[i] = std::thread(lamfuncCheck, std::ref(demoData), key, system_clock::from_time_t(timeT));
301 }
302
303 std::this_thread::sleep_for(std::chrono::seconds(3));
304 for (auto& t : threads) {
305 t.join();
306 }
307
308 for (auto& t : checkThread) {
309 t.join();
310 }
311 });
312 }
313
314 /*
315 * @tc.name: testUtilsConcurrentWriteAndFind001
316 * @tc.desc: 100 threads test in writein to the corresponding key of the map,
317 * while read at same time and check the results
318 */
319 HWTEST_F(UtilsSafeMap, testUtilsConcurrentWriteAndFind001, TestSize.Level0)
320 {
321 SafeMap<string, int> demoData;
322 std::thread threads[THREAD_NUM];
323 std::vector<std::future<int>> vcfi;
324
325 ASSERT_NO_THROW({
326 auto lamfuncInsert = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0602(SafeMap<string, int>& data, const string& key, const int& value, const std::chrono::system_clock::time_point& absTime) 327 const int& value, const std::chrono::system_clock::time_point& absTime) {
328 std::this_thread::sleep_until(absTime);
329 data.EnsureInsert(key, value);
330 };
331
332 auto lamfuncCheckLoop = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0702(SafeMap<string, int>& data, const string& key, std::chrono::system_clock::time_point absTime) 333 std::chrono::system_clock::time_point absTime) {
334 std::this_thread::sleep_until(absTime);
335 thread_local int i = -1;
336 while (!data.Find(key, i)) {
337 std::this_thread::sleep_for(std::chrono::microseconds(10));
338 }
339 return i;
340 };
341
342 using std::chrono::system_clock;
343
344 std::time_t timeT = system_clock::to_time_t(system_clock::now());
345 timeT += 2;
346 string key("A");
347
348 for (int i = 0; i < THREAD_NUM; ++i) {
349 threads[i] = std::thread(lamfuncInsert, std::ref(demoData),
350 key + std::to_string(i), i, system_clock::from_time_t(timeT));
351 vcfi.push_back(std::async(std::launch::async, lamfuncCheckLoop,
352 std::ref(demoData), key + std::to_string(i), system_clock::from_time_t(timeT)));
353 }
354
355 std::this_thread::sleep_for(std::chrono::seconds(4));
356 for (auto& t : threads) {
357 t.join();
358 }
359
360 vector<int> result;
361
362 for (auto& t : vcfi) {
363 result.push_back(t.get());
364 }
365
366 std::sort(result.begin(), result.end());
367
368 for (int i = 0; i < THREAD_NUM; ++i) {
369 ASSERT_EQ(i, result[i]);
370 }
371 });
372 }
373
ResultCompare(std::vector<std::future<int>> & vcfi,SafeMap<string,int> & demoData)374 static void ResultCompare(std::vector<std::future<int>>& vcfi, SafeMap<string, int>& demoData)
375 {
376 vector<int> result;
377 for (auto& t : vcfi) {
378 result.push_back(t.get());
379 }
380
381 std::sort(result.begin(), result.end());
382
383 for (int i = 0; i < THREAD_NUM; ++i) {
384 ASSERT_EQ(i, result[i]);
385 }
386
387 int t = 0;
388 result.clear();
389 for (int i = 0; i < THREAD_NUM; ++i) {
390 t = -1;
391 ASSERT_TRUE(demoData.Find("A" + std::to_string(i), t));
392 result.push_back(t);
393 }
394
395 std::sort(result.begin(), result.end());
396
397 for (int i = 0; i < THREAD_NUM; ++i) {
398 ASSERT_EQ(i + 1, result[i]);
399 }
400 }
401
402 /*
403 * @tc.name: testUtilsConcurrentWriteAndFindAndSet001
404 * @tc.desc: 100 threads test in writein to the corresponding key of the map,
405 * while findandfix at same time and check the results
406 */
407 HWTEST_F(UtilsSafeMap, testUtilsConcurrentWriteAndFindAndSet001, TestSize.Level0)
408 {
409 SafeMap<string, int> demoData;
410 std::thread threads[THREAD_NUM];
411 std::vector<std::future<int>> vcfi;
412
413 ASSERT_NO_THROW({
414 auto lamfuncInsert = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0802(SafeMap<string, int>& data, const string& key, const int& value, const std::chrono::system_clock::time_point& absTime) 415 const int& value, const std::chrono::system_clock::time_point& absTime) {
416 std::this_thread::sleep_until(absTime);
417 data.EnsureInsert(key, value);
418 };
419
420 auto lamfuncCheckLoop = [](SafeMap<string, int>& data, const string& key,
__anonf4da918c0902(SafeMap<string, int>& data, const string& key, const int& newvalue, std::chrono::system_clock::time_point absTime) 421 const int& newvalue, std::chrono::system_clock::time_point absTime) {
422 std::this_thread::sleep_until(absTime);
423 thread_local int i = -1;
424 while (!data.FindOldAndSetNew(key, i, newvalue)) {
425 std::this_thread::sleep_for(std::chrono::microseconds(10));
426 }
427 return i;
428 };
429
430 using std::chrono::system_clock;
431
432 std::time_t timeT = system_clock::to_time_t(system_clock::now());
433 timeT += 2;
434 string key("A");
435
436 for (int i = 0; i < THREAD_NUM; ++i) {
437 threads[i] = std::thread(lamfuncInsert, std::ref(demoData),
438 key + std::to_string(i), i, system_clock::from_time_t(timeT));
439 vcfi.push_back(std::async(std::launch::async, lamfuncCheckLoop,
440 std::ref(demoData), key + std::to_string(i), i + 1, system_clock::from_time_t(timeT)));
441 }
442
443 std::this_thread::sleep_for(std::chrono::seconds(4));
444 for (auto& t : threads) {
445 t.join();
446 }
447
448 ResultCompare(vcfi, demoData);
449 });
450 }
451 } // namespace
452 } // namespace OHOS