1 /*
2 * Copyright (c) 2025 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
16 #include <gtest/gtest.h>
17 #include <string>
18 #include <vector>
19 #include <cstring>
20
21 #include "comm_log.h"
22 #include "softbus_adapter_mem.h"
23 #include "softbus_error_code.h"
24 #include "softbus_tlv_utils.h"
25
26 using namespace std;
27 using namespace testing::ext;
28
29 namespace OHOS {
30 class TlvFrame {
31 public:
32 int type_;
33 string value_;
34
TlvFrame(int type,string value)35 TlvFrame(int type, string value) : type_(type), value_(value) {}
36 };
37
38 class SoftBusTlvUtilsTest : public testing::Test {
39 public:
SetUpTestCase(void)40 static void SetUpTestCase(void) { }
TearDownTestCase(void)41 static void TearDownTestCase(void) { }
42 };
43
BytesToHexString(const uint8_t * data,uint32_t len)44 static string BytesToHexString(const uint8_t *data, uint32_t len)
45 {
46 std::stringstream hexStream;
47 for (uint32_t i = 0; i < len; i++) {
48 hexStream << "0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<uint32_t>(data[i]) << ", ";
49 }
50 return hexStream.str();
51 }
52
TLvFeatureTest(uint8_t tSize,uint8_t lSize,vector<TlvFrame> & testcases)53 static void TLvFeatureTest(uint8_t tSize, uint8_t lSize, vector<TlvFrame> &testcases)
54 {
55 COMM_LOGI(COMM_UTILS, "tSize=%{public}u, lSize=%{public}u", tSize, lSize);
56 int32_t ret;
57 TlvObject *sendObj = CreateTlvObject(tSize, lSize);
58 ASSERT_TRUE(sendObj != nullptr);
59 for (auto testcase: testcases) {
60 COMM_LOGI(COMM_UTILS, "t=%{public}d, l=%{public}d, v=%{public}s",
61 testcase.type_, (int)testcase.value_.length(), testcase.value_.c_str());
62 ret = AddTlvMember(sendObj, testcase.type_,
63 testcase.value_.length(), (const uint8_t *)testcase.value_.c_str());
64 EXPECT_EQ(ret, SOFTBUS_OK);
65 }
66 uint8_t *output = nullptr;
67 uint32_t outputSize = 0;
68 ret = GetTlvBinary(sendObj, &output, &outputSize);
69 EXPECT_EQ(ret, SOFTBUS_OK);
70 DestroyTlvObject(sendObj);
71
72 COMM_LOGI(COMM_UTILS, "output=%{public}s, outputSize=%{public}u",
73 BytesToHexString(output, outputSize).c_str(), outputSize);
74
75 uint32_t length = 0;
76 uint8_t *value = nullptr;
77 TlvObject *recvObj = CreateTlvObject(tSize, lSize);
78 ASSERT_TRUE(recvObj != nullptr);
79 ret = SetTlvBinary(recvObj, output, outputSize);
80 EXPECT_EQ(ret, SOFTBUS_OK);
81
82 for (auto testcase: testcases) {
83 ret = GetTlvMember(recvObj, testcase.type_, &length, &value);
84 EXPECT_EQ(ret, SOFTBUS_OK);
85 ASSERT_EQ(length, testcase.value_.length());
86 EXPECT_EQ(memcmp(value, testcase.value_.c_str(), length), 0);
87 }
88 DestroyTlvObject(recvObj);
89 SoftBusFree(output);
90 }
91
92 /**
93 * @tc.name: TlvUtilsNormalUsage
94 * @tc.desc: TlvUtilsNormalUsage
95 * @tc.type: FUNC
96 * @tc.require:
97 */
98 HWTEST_F(SoftBusTlvUtilsTest, TlvUtilsNormalUsage, TestSize.Level0)
99 {
100 COMM_LOGI(COMM_UTILS, "===TlvUtilsNormalUsage begin");
101 vector<vector<TlvFrame>> tlvFrameTestcases = {
102 // 1.only one tlv frame, length = 0
103 { TlvFrame(1, "") },
104 // 2.only one tlv frame, length > 0
105 { TlvFrame(1, "test1") },
106 // 3.many tlv frames, length = 0
107 { TlvFrame(1, ""), TlvFrame(2, ""), TlvFrame(3, "") },
108 // 4.many tlv frames, length >= 0
109 { TlvFrame(1, "test1"), TlvFrame(2, ""), TlvFrame(3, "test3") },
110 // 5.many tlv frames, all length > 0
111 { TlvFrame(1, "test1"), TlvFrame(2, "test2"), TlvFrame(3, "test3") },
112 };
113
114 for (auto frame: tlvFrameTestcases) {
115 TLvFeatureTest(UINT8_T, UINT8_T, frame);
116 TLvFeatureTest(UINT8_T, UINT16_T, frame);
117 TLvFeatureTest(UINT8_T, UINT32_T, frame);
118 TLvFeatureTest(UINT16_T, UINT8_T, frame);
119 TLvFeatureTest(UINT16_T, UINT16_T, frame);
120 TLvFeatureTest(UINT16_T, UINT32_T, frame);
121 TLvFeatureTest(UINT32_T, UINT8_T, frame);
122 TLvFeatureTest(UINT32_T, UINT16_T, frame);
123 TLvFeatureTest(UINT32_T, UINT32_T, frame);
124 }
125 COMM_LOGI(COMM_UTILS, "===TlvUtilsNormalUsage end");
126 }
127
128 /**
129 * @tc.name: TlvUtilsPackTlvTest
130 * @tc.desc: TlvUtilsPackTlvTest.
131 * @tc.type: FUNC
132 * @tc.require:
133 */
134 HWTEST_F(SoftBusTlvUtilsTest, TlvUtilsPackTlvTest, TestSize.Level0)
135 {
136 COMM_LOGI(COMM_UTILS, "===TlvUtilsPackTlvTest begin");
137 // mock ts=UINT16_T ls=UINT16_T
138 TlvFrame frame1 = TlvFrame(1024, "test1024");
139 TlvFrame frame2 = TlvFrame(2048, "test2048");
140 uint8_t tlvBytes[] = {
141 0x00, 0x04, 0x08, 0x00, 0x74, 0x65, 0x73, 0x74, 0x31, 0x30, 0x32, 0x34, // frame1
142 0x00, 0x08, 0x08, 0x00, 0x74, 0x65, 0x73, 0x74, 0x32, 0x30, 0x34, 0x38 // frame2
143 };
144 // usage1: add one tlv frame
145 TlvObject *obj = CreateTlvObject(UINT16_T, UINT16_T);
146 ASSERT_TRUE(obj != nullptr);
147 int32_t ret = AddTlvMember(obj, frame1.type_, frame1.value_.length(), (const uint8_t *)frame1.value_.c_str());
148 EXPECT_EQ(ret, SOFTBUS_OK);
149 uint8_t *output = nullptr;
150 uint32_t outputSize = 0;
151 ret = GetTlvBinary(obj, &output, &outputSize);
152 EXPECT_EQ(ret, SOFTBUS_OK);
153 COMM_LOGI(COMM_UTILS, "output=%{public}s, outputSize=%{public}u",
154 BytesToHexString(output, outputSize).c_str(), outputSize);
155 ASSERT_EQ(outputSize, 12); // 12: UINT16_T + UINT16_T + strlen("test1024")
156 EXPECT_EQ(memcmp(output, tlvBytes, outputSize), 0);
157 SoftBusFree(output);
158 output = nullptr;
159
160 // usage2: append one tlv frame after GetTlvBinary
161 ret = AddTlvMember(obj, frame2.type_, frame2.value_.length(), (const uint8_t *)frame2.value_.c_str());
162 EXPECT_EQ(ret, SOFTBUS_OK);
163 ret = GetTlvBinary(obj, &output, &outputSize);
164 EXPECT_EQ(ret, SOFTBUS_OK);
165 DestroyTlvObject(obj);
166
167 COMM_LOGI(COMM_UTILS, "output=%{public}s, outputSize=%{public}u",
168 BytesToHexString(output, outputSize).c_str(), outputSize);
169 ASSERT_EQ(outputSize, sizeof(tlvBytes));
170 EXPECT_EQ(memcmp(output, tlvBytes, outputSize), 0);
171 SoftBusFree(output);
172 output = nullptr;
173 // usage3: append new tlv frame after SetTlvBinary
174 obj = CreateTlvObject(UINT16_T, UINT16_T);
175 ASSERT_TRUE(obj != nullptr);
176 ret = SetTlvBinary(obj, tlvBytes, 12); // 12: UINT16_T + UINT16_T + strlen("test1024")
177 EXPECT_EQ(ret, SOFTBUS_OK);
178 ret = AddTlvMember(obj, frame2.type_, frame2.value_.length(), (const uint8_t *)frame2.value_.c_str());
179 EXPECT_EQ(ret, SOFTBUS_OK);
180 ret = GetTlvBinary(obj, &output, &outputSize);
181 EXPECT_EQ(ret, SOFTBUS_OK);
182 DestroyTlvObject(obj);
183
184 COMM_LOGI(COMM_UTILS, "output=%{public}s, outputSize=%{public}u",
185 BytesToHexString(output, outputSize).c_str(), outputSize);
186 ASSERT_EQ(outputSize, sizeof(tlvBytes));
187 EXPECT_EQ(memcmp(output, tlvBytes, outputSize), 0);
188 SoftBusFree(output);
189 output = nullptr;
190 COMM_LOGI(COMM_UTILS, "===TlvUtilsPackTlvTest end");
191 }
192
193 /**
194 * @tc.name: TlvUtilsUnpackTlvTest
195 * @tc.desc: TlvUtilsUnpackTlvTest
196 * @tc.type: FUNC
197 * @tc.require:
198 */
199 HWTEST_F(SoftBusTlvUtilsTest, TlvUtilsUnpackTlvTest, TestSize.Level0)
200 {
201 COMM_LOGI(COMM_UTILS, "===TlvUtilsUnpackTlvTest begin");
202 // mock ts=UINT16_T ls=UINT16_T
203 TlvFrame frame1 = TlvFrame(1024, "test1024");
204 TlvFrame frame2 = TlvFrame(2048, "test2048");
205 uint8_t tlvBytes[] = {
206 0x00, 0x04, 0x08, 0x00, 0x74, 0x65, 0x73, 0x74, 0x31, 0x30, 0x32, 0x34, // frame1
207 0x00, 0x08, 0x08, 0x00, 0x74, 0x65, 0x73, 0x74, 0x32, 0x30, 0x34, 0x38 // frame2
208 };
209 // usage 1: parse only one tlv frame
210 TlvObject *obj = CreateTlvObject(UINT16_T, UINT16_T);
211 ASSERT_TRUE(obj != nullptr);
212 int32_t ret = SetTlvBinary(obj, tlvBytes, 12); // 12: UINT16_T + UINT16_T + strlen("test1024")
213 EXPECT_EQ(ret, SOFTBUS_OK);
214 uint32_t length = 0;
215 uint8_t *value = nullptr;
216 ret = GetTlvMember(obj, frame1.type_, &length, &value);
217 EXPECT_EQ(ret, SOFTBUS_OK);
218 ASSERT_EQ(length, frame1.value_.length());
219 EXPECT_EQ(memcmp(value, frame1.value_.c_str(), length), 0);
220 DestroyTlvObject(obj);
221 // usage 2: parse two tlv frames
222 obj = CreateTlvObject(UINT16_T, UINT16_T);
223 ASSERT_TRUE(obj != nullptr);
224 ret = SetTlvBinary(obj, tlvBytes, sizeof(tlvBytes));
225 EXPECT_EQ(ret, SOFTBUS_OK);
226 ret = GetTlvMember(obj, frame1.type_, &length, &value);
227 EXPECT_EQ(ret, SOFTBUS_OK);
228 ASSERT_EQ(length, frame1.value_.length());
229 EXPECT_EQ(memcmp(value, frame1.value_.c_str(), length), 0);
230 ret = GetTlvMember(obj, frame2.type_, &length, &value);
231 EXPECT_EQ(ret, SOFTBUS_OK);
232 ASSERT_EQ(length, frame2.value_.length());
233 EXPECT_EQ(memcmp(value, frame2.value_.c_str(), length), 0);
234 DestroyTlvObject(obj);
235 COMM_LOGI(COMM_UTILS, "===TlvUtilsUnpackTlvTest end");
236 }
237
238 typedef struct {
239 uint32_t type;
240 union {
241 uint8_t u8;
242 uint16_t u16;
243 uint32_t u32;
244 uint64_t u64;
245 };
246 } TlvNumberFrame;
247
248 /**
249 * @tc.name: TlvUtilsPackNumberTest
250 * @tc.desc: TlvUtilsPackNumberTest
251 * @tc.type: FUNC
252 * @tc.require:
253 */
254 HWTEST_F(SoftBusTlvUtilsTest, TlvUtilsPackNumberTest, TestSize.Level0)
255 {
256 COMM_LOGI(COMM_UTILS, "===TlvUtilsPackNumberTest begin");
257 // mock ts=UINT16_T ls=UINT16_T
258 TlvNumberFrame tlvFrames[] = {
259 { .type = 0x08, .u8 = 0x1F },
260 { .type = 0x16, .u16 = 0x2FF },
261 { .type = 0x32, .u32 = 0x3FFF },
262 { .type = 0x64, .u64 = 0x4FFFF },
263 };
264 uint8_t tlvBytes[] = {
265 0x08, 0x00, 0x01, 0x00, 0x1F, // .type = 0x08, .u8 = 0x1F
266 0x16, 0x00, 0x02, 0x00, 0xFF, 0x02, // .type = 0x16, .u16 = 0x2FF
267 0x32, 0x00, 0x04, 0x00, 0xFF, 0x3F, 0x00, 0x00, // .type = 0x32, .u32 = 0x3FFF
268 0x64, 0x00, 0x08, 0x00, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 // .type = 0x64, .u64 = 0x4FFFF
269 };
270
271 TlvObject *obj = CreateTlvObject(UINT16_T, UINT16_T);
272 ASSERT_TRUE(obj != nullptr);
273
274 int32_t ret = AddTlvMemberU8(obj, tlvFrames[0].type, tlvFrames[0].u8);
275 EXPECT_EQ(ret, SOFTBUS_OK);
276 ret = AddTlvMemberU16(obj, tlvFrames[1].type, tlvFrames[1].u16);
277 EXPECT_EQ(ret, SOFTBUS_OK);
278 ret = AddTlvMemberU32(obj, tlvFrames[2].type, tlvFrames[2].u32);
279 EXPECT_EQ(ret, SOFTBUS_OK);
280 ret = AddTlvMemberU64(obj, tlvFrames[3].type, tlvFrames[3].u64);
281 EXPECT_EQ(ret, SOFTBUS_OK);
282
283 uint8_t *output = nullptr;
284 uint32_t outputSize = 0;
285 ret = GetTlvBinary(obj, &output, &outputSize);
286 EXPECT_EQ(ret, SOFTBUS_OK);
287 DestroyTlvObject(obj);
288
289 COMM_LOGI(COMM_UTILS, "output=%{public}s, outputSize=%{public}u",
290 BytesToHexString(output, outputSize).c_str(), outputSize);
291 ASSERT_EQ(outputSize, sizeof(tlvBytes));
292 EXPECT_EQ(memcmp(output, tlvBytes, outputSize), 0);
293 SoftBusFree(output);
294 output = nullptr;
295 COMM_LOGI(COMM_UTILS, "===TlvUtilsPackNumberTest end");
296 }
297
298 /**
299 * @tc.name: TlvUtilsUnpackNumberTest
300 * @tc.desc: TlvUtilsUnpackNumberTest
301 * @tc.type: FUNC
302 * @tc.require:
303 */
304 HWTEST_F(SoftBusTlvUtilsTest, TlvUtilsUnpackNumberTest, TestSize.Level0)
305 {
306 COMM_LOGI(COMM_UTILS, "===TlvUtilsUnpackNumberTest begin");
307 // mock ts=UINT16_T ls=UINT16_T
308 TlvNumberFrame tlvFrames[] = {
309 { .type = 0x08, .u8 = 0x1F },
310 { .type = 0x16, .u16 = 0x2FF },
311 { .type = 0x32, .u32 = 0x3FFF },
312 { .type = 0x64, .u64 = 0x4FFFF },
313 };
314 uint8_t tlvBytes[] = {
315 0x08, 0x00, 0x01, 0x00, 0x1F, // .type = 0x08, .u8 = 0x1F
316 0x16, 0x00, 0x02, 0x00, 0xFF, 0x02, // .type = 0x16, .u16 = 0x2FF
317 0x32, 0x00, 0x04, 0x00, 0xFF, 0x3F, 0x00, 0x00, // .type = 0x32, .u32 = 0x3FFF
318 0x64, 0x00, 0x08, 0x00, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 // .type = 0x64, .u64 = 0x4FFFF
319 };
320
321 TlvObject *obj = CreateTlvObject(UINT16_T, UINT16_T);
322 ASSERT_TRUE(obj != nullptr);
323 int32_t ret = SetTlvBinary(obj, tlvBytes, sizeof(tlvBytes));
324 EXPECT_EQ(ret, SOFTBUS_OK);
325
326 uint8_t u8 = 0;
327 ret = GetTlvMemberU8(obj, tlvFrames[0].type, &u8);
328 EXPECT_EQ(ret, SOFTBUS_OK);
329 EXPECT_EQ(u8, tlvFrames[0].u8);
330 uint16_t u16 = 0;
331 ret = GetTlvMemberU16(obj, tlvFrames[1].type, &u16);
332 EXPECT_EQ(ret, SOFTBUS_OK);
333 EXPECT_EQ(u16, tlvFrames[1].u16);
334 uint32_t u32 = 0;
335 ret = GetTlvMemberU32(obj, tlvFrames[2].type, &u32);
336 EXPECT_EQ(ret, SOFTBUS_OK);
337 EXPECT_EQ(u32, tlvFrames[2].u32);
338 uint64_t u64 = 0;
339 ret = GetTlvMemberU64(obj, tlvFrames[3].type, &u64);
340 EXPECT_EQ(ret, SOFTBUS_OK);
341 EXPECT_EQ(u64, tlvFrames[3].u64);
342
343 DestroyTlvObject(obj);
344 COMM_LOGI(COMM_UTILS, "===TlvUtilsUnpackNumberTest end");
345 }
346
347 /**
348 * @tc.name: GetTlvMemberWithBuffer
349 * @tc.desc: GetTlvMemberWithBuffer
350 * @tc.type: FUNC
351 * @tc.require:
352 */
353 HWTEST_F(SoftBusTlvUtilsTest, TlvUtilsGetTlvMemberWithBufferTest, TestSize.Level0)
354 {
355 COMM_LOGI(COMM_UTILS, "===TlvUtilsGetTlvMemberWithBufferTest begin");
356 // mock ts=UINT16_T ls=UINT16_T
357 const uint32_t type1 = 1;
358 const uint8_t value1[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
359 const uint32_t type2 = 2;
360 const char value2[] = "test1024";
361 const uint32_t type3 = 3;
362 uint8_t tlvBytes[] = {
363 0x01, 0x00, 0x06, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // type=1, len=6 MAC
364 0x02, 0x00, 0x08, 0x00, 0x74, 0x65, 0x73, 0x74, 0x31, 0x30, 0x32, 0x34, // type=2, len=6, NAME
365 0x03, 0x00, 0x00, 0x00, // type=3, len=0, empty
366 };
367
368 TlvObject *obj = CreateTlvObject(UINT16_T, UINT16_T);
369 ASSERT_TRUE(obj != nullptr);
370 int32_t ret = SetTlvBinary(obj, tlvBytes, sizeof(tlvBytes));
371 EXPECT_EQ(ret, SOFTBUS_OK);
372
373 uint8_t mac[6]; // 6: mac size
374 ret = GetTlvMemberWithSpecifiedBuffer(obj, type1, mac, sizeof(mac));
375 EXPECT_EQ(ret, SOFTBUS_OK);
376 EXPECT_EQ(memcmp(value1, mac, sizeof(mac)), 0);
377
378 uint8_t name[16] = {}; // 16: max name len
379 uint32_t nameSize = sizeof(name);
380 ret = GetTlvMemberWithEstimatedBuffer(obj, type2, name, &nameSize);
381 EXPECT_EQ(ret, SOFTBUS_OK);
382 for (uint32_t i = 0; i < nameSize; i++) {
383 GTEST_LOG_(INFO) << "name=" << name[i];
384 }
385 EXPECT_EQ(memcmp(value2, name, nameSize), 0);
386
387 uint32_t empty = 0;
388 uint8_t emptyBuf[16]; // 16: not use
389 ret = GetTlvMemberWithEstimatedBuffer(obj, type3, emptyBuf, &empty);
390 EXPECT_EQ(ret, SOFTBUS_OK);
391 EXPECT_EQ(empty, 0);
392
393 DestroyTlvObject(obj);
394 COMM_LOGI(COMM_UTILS, "===TlvUtilsGetTlvMemberWithBufferTest end");
395 }
396
397 /**
398 * @tc.name: TlvUtilsExceptionDataTest
399 * @tc.desc: TlvUtilsExceptionDataTest
400 * @tc.type: FUNC
401 * @tc.require:
402 */
403 HWTEST_F(SoftBusTlvUtilsTest, TlvUtilsExceptionDataTest, TestSize.Level0)
404 {
405 COMM_LOGI(COMM_UTILS, "===TlvUtilsExceptionDataTest begin");
406 // mock ts=UINT16_T ls=UINT16_T
407 uint8_t tlvBytes[] = {
408 0x01, 0x00, 0x08, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // type=1, len=8, value=6
409 };
410
411 TlvObject *obj = CreateTlvObject(UINT16_T, UINT16_T);
412 ASSERT_TRUE(obj != nullptr);
413 int32_t ret = SetTlvBinary(obj, tlvBytes, sizeof(tlvBytes));
414 EXPECT_EQ(ret, SOFTBUS_NO_ENOUGH_DATA);
415
416 DestroyTlvObject(obj);
417 COMM_LOGI(COMM_UTILS, "===TlvUtilsExceptionDataTest end");
418 }
419 } // namespace OHOS
420