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
16#include "gtest/gtest.h"
17
18#include <cstddef>
19#include <string>
20
21#include "utils/aie_guard.h"
22#include "utils/aie_macros.h"
23#include "utils/encdec/include/data_decoder.h"
24#include "utils/encdec/include/data_encoder.h"
25#include "utils/encdec/include/encdec_facade.h"
26#include "utils/log/aie_log.h"
27
28using namespace OHOS::AI;
29using namespace testing::ext;
30namespace {
31constexpr size_t ARRAY_LEN = 10;
32constexpr int g_int = 12;
33constexpr char g_char = 'd';
34constexpr float g_float = 0.99f;
35constexpr long long g_long = 123456789L;
36const std::string g_string = "random string";
37const std::string g_emptyString = "";
38
39typedef struct {
40    char foo;
41    int bar;
42} StructWithPadding; // definition of struct with padding(blank memory) between members
43
44typedef struct {
45    int foo;
46    StructWithPadding bar;
47} NestedStruct;
48
49typedef struct {
50    size_t objectsNum;
51    StructWithPadding* objects;
52} StructWithPointer;
53
54typedef struct {
55    size_t foo;
56    int barArray[ARRAY_LEN];
57} StructWithArray;
58
59template<typename Type>
60bool CompareData(const Type &input, const Type &output)
61{
62    return input == output;
63}
64
65bool CompareData(const StructWithPadding &input, const StructWithPadding &output)
66{
67    return (input.foo == output.foo) && (input.bar == output.bar);
68}
69
70bool CompareData(const NestedStruct &input, const NestedStruct &output)
71{
72    return (input.foo == output.foo) && CompareData(input.bar, output.bar);
73}
74
75bool CompareData(const StructWithPointer &input, const StructWithPointer &output)
76{
77    if (input.objectsNum != output.objectsNum) {
78        return false;
79    }
80    for (unsigned int i = 0; i < input.objectsNum; ++i) {
81        if (!CompareData(input.objects[i], output.objects[i])) {
82            return false;
83        }
84    }
85    return true;
86}
87
88bool CompareData(const StructWithArray &input, const StructWithArray &output)
89{
90    if (input.foo != output.foo) {
91        return false;
92    }
93    for (unsigned int i = 0; i < ARRAY_LEN; ++i) {
94        if (!CompareData(input.barArray[i], output.barArray[i])) {
95            return false;
96        }
97    }
98    return true;
99}
100
101StructWithPadding GenStructWithPadding(const int myNum, const char myChar)
102{
103    StructWithPadding structWithPadding = {
104        .foo = myChar,
105        .bar = myNum
106    };
107    return structWithPadding;
108}
109
110NestedStruct GenNestedStruct()
111{
112    NestedStruct nestedStruct = {
113        .foo = g_int,
114        .bar = GenStructWithPadding(g_int, g_char)
115    };
116    return nestedStruct;
117}
118
119StructWithPointer GenStructWithPointer(const size_t objectsNum)
120{
121    StructWithPointer structWithPointer {
122        .objectsNum = objectsNum
123    };
124    if (objectsNum > 0) {
125        AIE_NEW(structWithPointer.objects, StructWithPadding[objectsNum]);
126        for (size_t i = 0; i < objectsNum; ++i) {
127            structWithPointer.objects[i] = GenStructWithPadding(g_int, g_char);
128        }
129    }
130    return structWithPointer;
131}
132
133void ReleaseStructWithPointer(StructWithPointer &structWithPointer)
134{
135    AIE_DELETE_ARRAY(structWithPointer.objects);
136}
137
138StructWithArray GenStructWithArray(const size_t num)
139{
140    StructWithArray structWithArray {
141        .foo = num
142    };
143    for (size_t i = 0; i < num && i < ARRAY_LEN; ++i) {
144        structWithArray.barArray[i] = g_int;
145    }
146    return structWithArray;
147}
148
149void PolluteData(DataInfo &dataInfo)
150{
151    *(reinterpret_cast<size_t*>(dataInfo.data + dataInfo.length - sizeof(size_t))) = 0U;
152}
153
154void BasicTypesCheck(bool normalMode = true)
155{
156    DataInfo dataInfo {};
157    int retCode = EncdecFacade::ProcessEncode(dataInfo, g_int, g_char, g_float, g_long, g_string, g_emptyString);
158    MallocPointerGuard<unsigned char> dataInfoGuard(dataInfo.data);
159    ASSERT_EQ(retCode, RETCODE_SUCCESS);
160    if (!normalMode) {
161        PolluteData(dataInfo);
162    }
163    int outInt {};
164    char outChar {};
165    float outFloat {};
166    long long outLong {};
167    std::string outString {};
168    std::string outEmptyString {};
169
170    retCode = EncdecFacade::ProcessDecode(dataInfo, outInt, outChar, outFloat, outLong, outString,
171        outEmptyString);
172    if (normalMode) {
173        ASSERT_EQ(retCode, RETCODE_SUCCESS);
174        ASSERT_TRUE(CompareData(g_int, outInt));
175        ASSERT_TRUE(CompareData(g_char, outChar));
176        ASSERT_TRUE(CompareData(g_float, outFloat));
177        ASSERT_TRUE(CompareData(g_long, outLong));
178        ASSERT_TRUE(CompareData(g_string, outString));
179        ASSERT_TRUE(CompareData(g_emptyString, outEmptyString));
180    } else {
181        ASSERT_NE(retCode, RETCODE_SUCCESS);
182    }
183}
184
185void StructCheck(bool normalMode = true)
186{
187    DataInfo dataInfo {};
188    StructWithPadding structWithPadding = GenStructWithPadding(g_int, g_char);
189    NestedStruct nestedStruct = GenNestedStruct();
190    StructWithArray structWithArray = GenStructWithArray(ARRAY_LEN);
191
192    int retCode = EncdecFacade::ProcessEncode(dataInfo, structWithPadding, nestedStruct, structWithArray);
193    MallocPointerGuard<unsigned char> dataInfoGuard(dataInfo.data);
194    ASSERT_EQ(retCode, RETCODE_SUCCESS);
195    if (!normalMode) {
196        PolluteData(dataInfo);
197    }
198    StructWithPadding outStructWithPadding {};
199    NestedStruct outNestedStruct {};
200    StructWithArray outStructWithArray {};
201
202    retCode = EncdecFacade::ProcessDecode(dataInfo, outStructWithPadding, outNestedStruct, outStructWithArray);
203    if (normalMode) {
204        ASSERT_EQ(retCode, RETCODE_SUCCESS);
205        ASSERT_TRUE(CompareData(structWithPadding, outStructWithPadding));
206        ASSERT_TRUE(CompareData(nestedStruct, outNestedStruct));
207        ASSERT_TRUE(CompareData(structWithArray, outStructWithArray));
208    } else {
209        ASSERT_NE(retCode, RETCODE_SUCCESS);
210    }
211}
212
213void StructWithPointerCheck(bool normalMode = true)
214{
215    for (size_t classNum = 0; classNum <= ARRAY_LEN; ++classNum) {
216        HILOGD ("[Test]Normal test StructWithPointer, classNum = %d.************", classNum);
217        StructWithPointer structWithPointer = GenStructWithPointer(classNum);
218        DataInfo dataInfo {};
219        int retCode = EncdecFacade::ProcessEncode(dataInfo, structWithPointer);
220        MallocPointerGuard<unsigned char> dataInfoGuard(dataInfo.data);
221        ASSERT_EQ(retCode, RETCODE_SUCCESS);
222        if (!normalMode) {
223            PolluteData(dataInfo);
224        }
225        StructWithPointer res {};
226        retCode = EncdecFacade::ProcessDecode(dataInfo, res);
227        if (normalMode) {
228            ASSERT_EQ(retCode, RETCODE_SUCCESS);
229            ASSERT_TRUE(CompareData(structWithPointer, res));
230            ReleaseStructWithPointer(res);
231        } else {
232            ASSERT_NE(retCode, RETCODE_SUCCESS);
233        }
234        ReleaseStructWithPointer(structWithPointer);
235    }
236}
237}
238
239namespace OHOS {
240namespace AI {
241template<>
242int DataEncoder::EncodeOneParameter(const StructWithPointer &val)
243{
244    if (RecursiveEncode(val.objectsNum) != RETCODE_SUCCESS) {
245        HILOGE("[EncdecTest]Serialize memory error.");
246        return RETCODE_FAILURE;
247    }
248    for (size_t i = 0; i < val.objectsNum; ++i) {
249        if (RecursiveEncode(val.objects[i]) != RETCODE_SUCCESS) {
250            HILOGE("[EncdecTest]Serialize memory error.");
251            return RETCODE_FAILURE;
252        }
253    }
254    return RETCODE_SUCCESS;
255}
256
257template<>
258int DataDecoder::DecodeOneParameter(StructWithPointer &val)
259{
260    if (RecursiveDecode(val.objectsNum) != RETCODE_SUCCESS) {
261        HILOGE("[EncdecTest]Unserialize failed.");
262        return RETCODE_FAILURE;
263    }
264    if (val.objectsNum > 0) {
265        AIE_NEW(val.objects, StructWithPadding[val.objectsNum]);
266        for (size_t i = 0; i < val.objectsNum; ++i) {
267            if (RecursiveDecode(val.objects[i]) != RETCODE_SUCCESS) {
268                AIE_DELETE_ARRAY(val.objects);
269                return RETCODE_FAILURE;
270            }
271        }
272    }
273    return RETCODE_SUCCESS;
274}
275} // namespace AI
276} // namespace OHOS
277
278class EncdecTest : public testing::Test {
279public:
280    // SetUpTestCase:The preset action of the test suite is executed before the first TestCase
281    static void SetUpTestCase() {};
282
283    // TearDownTestCase:The test suite cleanup action is executed after the last TestCase
284    static void TearDownTestCase() {};
285
286    // SetUp:Execute before each test case
287    void SetUp() override {};
288
289    // TearDown:Execute after each test case
290    void TearDown() override {};
291};
292
293/**
294 * @tc.name: EncdecNormalCheck001
295 * @tc.desc: Test encode decode function for non-pointer type in normal mode.
296 * @tc.type: FUNC
297 * @tc.require: AR000F77MR
298 */
299HWTEST_F(EncdecTest, EncdecNormalCheck001, TestSize.Level0)
300{
301    HILOGD ("**********[Test]Normal test start, all the result should return 0************");
302    BasicTypesCheck();
303    HILOGD ("**********[Test]Normal test end************");
304}
305
306/**
307 * @tc.name: EncdecNormalCheck002
308 * @tc.desc: Test encode decode function for struct without pointer.
309 * @tc.type: FUNC
310 * @tc.require: AR000F77MR
311 */
312HWTEST_F(EncdecTest, EncdecNormalCheck002, TestSize.Level0)
313{
314    HILOGD ("**********[Test]Normal test start, all the result should return 0************");
315    StructCheck();
316    HILOGD ("**********[Test]Normal test end************");
317}
318
319/**
320 * @tc.name: EncdecNormalCheck003
321 * @tc.desc: Test encode decode function for types which include pointers in normal mode.
322 * @tc.type: FUNC
323 * @tc.require: AR000F77MR
324 */
325HWTEST_F(EncdecTest, EncdecNormalCheck003, TestSize.Level0)
326{
327    HILOGD ("**********[Test]Normal test start, all the result should return 0************");
328    StructWithPointerCheck();
329    HILOGD ("**********[Test]Normal test end************");
330}
331
332/**
333 * @tc.name: EncdecAbnormalCheck001
334 * @tc.desc: Test encode decode function for non-pointer type in abnormal mode.
335 * @tc.type: FUNC
336 * @tc.require: AR000F77MR
337 */
338HWTEST_F(EncdecTest, EncdecAbnormalCheck001, TestSize.Level1)
339{
340    HILOGD ("**********[Test]abnormal test start************");
341    BasicTypesCheck(false);
342    HILOGD ("**********[Test]abnormal test end************");
343}
344
345/**
346 * @tc.name: EncdecAbnormalCheck002
347 * @tc.desc: Test encode decode function for types which include pointers in abnormal mode.
348 * @tc.type: FUNC
349 * @tc.require: AR000F77MR
350 */
351HWTEST_F(EncdecTest, EncdecAbnormalCheck002, TestSize.Level1)
352{
353    HILOGD ("**********[Test]abnormal test start************");
354    StructCheck(false);
355    HILOGD ("**********[Test]abnormal test end************");
356}
357
358/**
359 * @tc.name: EncdecAbnormalCheck003
360 * @tc.desc: Test encode decode function for types which include pointers in normal mode.
361 * @tc.type: FUNC
362 * @tc.require: AR000F77MR
363 */
364HWTEST_F(EncdecTest, EncdecAbnormalCheck003, TestSize.Level1)
365{
366    HILOGD ("**********[Test]Normal test start, all the result should return 0************");
367    StructWithPointerCheck(false);
368    HILOGD ("**********[Test]Normal test end************");
369}
370