1 /*
2  * Copyright (c) 2022 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 "ops/top_k_builder.h"
17 
18 #include <gtest/gtest.h>
19 #include "nn_tensor.h"
20 #include "ops_test.h"
21 
22 using namespace testing;
23 using namespace testing::ext;
24 using namespace OHOS::NeuralNetworkRuntime::Ops;
25 
26 namespace OHOS {
27 namespace NeuralNetworkRuntime {
28 namespace UnitTest {
29 class TopKBuilderTest : public OpsTest {
30 protected:
31     void InitTensor(const std::vector<uint32_t>& inputsIndex,
32         const std::vector<uint32_t>& outputsIndex) override;
33     void SaveSortedTensor(OH_NN_DataType dataType, const std::vector<int32_t> &dim,
34         const OH_NN_QuantParam* quantParam, OH_NN_TensorType type);
35     void SaveAxisTensor(OH_NN_DataType dataType, const std::vector<int32_t> &dim,
36         const OH_NN_QuantParam* quantParam, OH_NN_TensorType type);
37 
38 protected:
39     TopKBuilder m_builder;
40     bool m_topkValue {false};
41 };
42 
InitTensor(const std::vector<uint32_t> & inputsIndex,const std::vector<uint32_t> & outputsIndex)43 void TopKBuilderTest::InitTensor(const std::vector<uint32_t>& inputsIndex, const std::vector<uint32_t>& outputsIndex)
44 {
45     std::vector<int32_t> inputDim = {9};
46     std::vector<int32_t> OutputDim = {3};
47 
48     SaveInputTensor(inputsIndex, OH_NN_FLOAT32, inputDim, nullptr);
49     SaveOutputTensor(outputsIndex, OH_NN_FLOAT32, OutputDim, nullptr);
50 }
51 
SaveAxisTensor(OH_NN_DataType dataType,const std::vector<int32_t> & dim,const OH_NN_QuantParam * quantParam,OH_NN_TensorType type)52 void TopKBuilderTest::SaveAxisTensor(OH_NN_DataType dataType, const std::vector<int32_t> &dim,
53     const OH_NN_QuantParam* quantParam, OH_NN_TensorType type)
54 {
55     std::shared_ptr<NNTensor> axisTensor = TransToNNTensor(dataType, dim, quantParam, type);
56     int64_t* axisValue = new (std::nothrow) int64_t[1] {0};
57     EXPECT_NE(nullptr, axisValue);
58     axisTensor->SetBuffer(axisValue, sizeof(int64_t));
59     m_allTensors.emplace_back(axisTensor);
60 }
61 
SaveSortedTensor(OH_NN_DataType dataType,const std::vector<int32_t> & dim,const OH_NN_QuantParam * quantParam,OH_NN_TensorType type)62 void TopKBuilderTest::SaveSortedTensor(OH_NN_DataType dataType, const std::vector<int32_t> &dim,
63     const OH_NN_QuantParam* quantParam, OH_NN_TensorType type)
64 {
65     std::shared_ptr<NNTensor> topkTensor = TransToNNTensor(dataType, dim, quantParam, type);
66     bool* topkValue = new (std::nothrow) bool[1] {true};
67     EXPECT_NE(nullptr, topkValue);
68     topkTensor->SetBuffer(topkValue, sizeof(bool));
69     m_allTensors.emplace_back(topkTensor);
70     m_topkValue = *topkValue;
71 }
72 
73 /**
74  * @tc.name: topk_build_001
75  * @tc.desc: Provide normal input, output, and parameters to verify the normal behavior of the Build function
76  * @tc.type: FUNC
77  */
78 HWTEST_F(TopKBuilderTest, topk_build_001, TestSize.Level0)
79 {
80     std::vector<uint32_t> inputsIndex = { 0, 1 };
81     std::vector<uint32_t> outputsIndex = { 2, 3 };
82     std::vector<uint32_t> paramsIndex = { 4, 5 };
83     std::vector<int32_t> paramDim = {};
84 
85     InitTensor(inputsIndex, outputsIndex);
86     SaveSortedTensor(OH_NN_BOOL, paramDim, nullptr, OH_NN_TOP_K_SORTED);
87     SaveAxisTensor(OH_NN_INT64, paramDim, nullptr, OH_NN_TOP_K_AXIS);
88 
89     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors);
90     EXPECT_EQ(OH_NN_SUCCESS, ret);
91 }
92 
93 /**
94  * @tc.name: topk_build_002
95  * @tc.desc: Call Build func twice to verify the abnormal behavior of the Build function
96  * @tc.type: FUNC
97  */
98 HWTEST_F(TopKBuilderTest, topk_build_002, TestSize.Level0)
99 {
100     std::vector<uint32_t> inputsIndex = { 0, 1 };
101     std::vector<uint32_t> outputsIndex = { 2, 3 };
102     std::vector<uint32_t> paramsIndex = { 4, 5 };
103     std::vector<int32_t> paramDim = {};
104 
105     InitTensor(inputsIndex, outputsIndex);
106     SaveSortedTensor(OH_NN_BOOL, paramDim, nullptr, OH_NN_TOP_K_SORTED);
107     SaveAxisTensor(OH_NN_INT64, paramDim, nullptr, OH_NN_TOP_K_AXIS);
108 
109     EXPECT_EQ(OH_NN_SUCCESS, m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors));
110     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors);
111     EXPECT_EQ(OH_NN_OPERATION_FORBIDDEN, ret);
112 }
113 
114 /**
115  * @tc.name: topk_build_003
116  * @tc.desc: Provide one more than normal input to verify the abnormal behavior of the Build function
117  * @tc.type: FUNC
118  */
119 HWTEST_F(TopKBuilderTest, topk_build_003, TestSize.Level0)
120 {
121     std::vector<uint32_t> inputsIndex = { 0, 1, 2, 3 };
122     std::vector<uint32_t> outputsIndex = { 4, 5 };
123     std::vector<uint32_t> paramsIndex = { 6, 7 };
124     std::vector<int32_t> paramDim = {};
125 
126     InitTensor(inputsIndex, outputsIndex);
127     SaveSortedTensor(OH_NN_BOOL, paramDim, nullptr, OH_NN_TOP_K_SORTED);
128     SaveAxisTensor(OH_NN_INT64, paramDim, nullptr, OH_NN_TOP_K_AXIS);
129 
130     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors);
131     EXPECT_EQ(OH_NN_INVALID_PARAMETER, ret);
132 }
133 
134 /**
135  * @tc.name: topk_builder_004
136  * @tc.desc: Provide one more than normal output to verify the abnormal behavior of the Build function
137  * @tc.type: FUNC
138  */
139 HWTEST_F(TopKBuilderTest, topk_builder_004, TestSize.Level0)
140 {
141     std::vector<uint32_t> inputsIndex = { 0, 1 };
142     std::vector<uint32_t> outputsIndex = { 2, 3, 4 };
143     std::vector<uint32_t> paramsIndex = { 5, 6 };
144     std::vector<int32_t> paramDim = {};
145 
146     InitTensor(inputsIndex, outputsIndex);
147     SaveSortedTensor(OH_NN_BOOL, paramDim, nullptr, OH_NN_TOP_K_SORTED);
148     SaveAxisTensor(OH_NN_INT64, paramDim, nullptr, OH_NN_TOP_K_AXIS);
149 
150     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors);
151     EXPECT_EQ(OH_NN_INVALID_PARAMETER, ret);
152 }
153 
154 /**
155  * @tc.name: topk_build_005
156  * @tc.desc: Provide empty input, output, and parameters to verify the abnormal behavior of the Build function
157  * @tc.type: FUNC
158  */
159 HWTEST_F(TopKBuilderTest, topk_build_005, TestSize.Level0)
160 {
161     std::vector<uint32_t> inputsIndex = { 0, 1, 2 };
162     std::vector<uint32_t> outputsIndex = { 3, 4 };
163     std::vector<uint32_t> paramsIndex = { 5, 6, 7 };
164 
165     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, inputsIndex, outputsIndex, m_allTensors);
166     EXPECT_EQ(OH_NN_INVALID_PARAMETER, ret);
167 }
168 
169 /**
170  * @tc.name: topk_build_006
171  * @tc.desc: Provide param type error to verify the abnormal behavior of the Build function
172  * @tc.type: FUNC
173  */
174 HWTEST_F(TopKBuilderTest, topk_build_006, TestSize.Level0)
175 {
176     std::vector<uint32_t> inputsIndex = { 0, 1 };
177     std::vector<uint32_t> outputsIndex = { 2, 3 };
178     std::vector<uint32_t> paramsIndex = { 4, 5 };
179     std::vector<int32_t> paramDim = {};
180 
181     InitTensor(inputsIndex, outputsIndex);
182     SaveSortedTensor(OH_NN_INT8, paramDim, nullptr, OH_NN_TOP_K_SORTED);
183     SaveAxisTensor(OH_NN_INT64, paramDim, nullptr, OH_NN_TOP_K_AXIS);
184 
185     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors);
186     EXPECT_EQ(OH_NN_INVALID_PARAMETER, ret);
187 }
188 
189 /**
190  * @tc.name: topk_build_007
191  * @tc.desc: Provide param type error to verify the abnormal behavior of the Build function
192  * @tc.type: FUNC
193  */
194 HWTEST_F(TopKBuilderTest, topk_build_007, TestSize.Level0)
195 {
196     std::vector<uint32_t> inputsIndex = { 0, 1 };
197     std::vector<uint32_t> outputsIndex = { 2, 3 };
198     std::vector<uint32_t> paramsIndex = { 4, 5 };
199     std::vector<int32_t> paramDim = {};
200 
201     InitTensor(inputsIndex, outputsIndex);
202     SaveSortedTensor(OH_NN_BOOL, paramDim, nullptr, OH_NN_TOP_K_SORTED);
203     SaveAxisTensor(OH_NN_INT32, paramDim, nullptr, OH_NN_TOP_K_AXIS);
204 
205     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors);
206     EXPECT_EQ(OH_NN_INVALID_PARAMETER, ret);
207 }
208 
209 /**
210  * @tc.name: topk_build_008
211  * @tc.desc: Provide sorted parameter buffer is nullptr to verify the abnormal behavior of the Build function
212  * @tc.type: FUNC
213  */
214 HWTEST_F(TopKBuilderTest, topk_build_008, TestSize.Level0)
215 {
216     std::vector<uint32_t> inputsIndex = { 0, 1 };
217     std::vector<uint32_t> outputsIndex = { 2, 3 };
218     std::vector<uint32_t> paramsIndex = { 4, 5 };
219     std::vector<int32_t> paramDim = {};
220 
221     InitTensor(inputsIndex, outputsIndex);
222 
223     std::shared_ptr<NNTensor> topkTensor = TransToNNTensor(OH_NN_BOOL, paramDim, nullptr, OH_NN_TOP_K_SORTED);
224     topkTensor->SetBuffer(nullptr, 0);
225     m_allTensors.emplace_back(topkTensor);
226     SaveAxisTensor(OH_NN_INT64, paramDim, nullptr, OH_NN_TOP_K_AXIS);
227 
228     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors);
229     EXPECT_EQ(OH_NN_INVALID_PARAMETER, ret);
230 }
231 
232 /**
233  * @tc.name: topk_build_009
234  * @tc.desc: Provide axis parameter buffer is nullptr to verify the abnormal behavior of the Build function
235  * @tc.type: FUNC
236  */
237 HWTEST_F(TopKBuilderTest, topk_build_009, TestSize.Level0)
238 {
239     std::vector<uint32_t> inputsIndex = { 0, 1 };
240     std::vector<uint32_t> outputsIndex = { 2, 3 };
241     std::vector<uint32_t> paramsIndex = { 4, 5 };
242     std::vector<int32_t> paramDim = {};
243 
244     InitTensor(inputsIndex, outputsIndex);
245 
246     SaveSortedTensor(OH_NN_BOOL, paramDim, nullptr, OH_NN_TOP_K_SORTED);
247     std::shared_ptr<NNTensor> axisTensor = TransToNNTensor(OH_NN_INT64, paramDim, nullptr, OH_NN_TOP_K_AXIS);
248     axisTensor->SetBuffer(nullptr, 0);
249     m_allTensors.emplace_back(axisTensor);
250 
251     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors);
252     EXPECT_EQ(OH_NN_INVALID_PARAMETER, ret);
253 }
254 
255 /**
256  * @tc.name: topk_build_010
257  * @tc.desc: Provide invalid parameter type to verify the abnormal behavior of the Build function
258  * @tc.type: FUNC
259  */
260 HWTEST_F(TopKBuilderTest, topk_build_010, TestSize.Level0)
261 {
262     std::vector<uint32_t> inputsIndex = { 0, 1 };
263     std::vector<uint32_t> outputsIndex = { 2, 3 };
264     std::vector<uint32_t> paramsIndex = { 4, 5 };
265     std::vector<int32_t> paramDim = {};
266 
267     InitTensor(inputsIndex, outputsIndex);
268     SaveSortedTensor(OH_NN_BOOL, paramDim, nullptr, OH_NN_SCALE_AXIS);
269     SaveAxisTensor(OH_NN_INT64, paramDim, nullptr, OH_NN_TOP_K_AXIS);
270 
271     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors);
272     EXPECT_EQ(OH_NN_INVALID_PARAMETER, ret);
273 }
274 
275 /**
276  * @tc.name: topk_build_011
277  * @tc.desc: Provide invalid parameter type to verify the abnormal behavior of the Build function
278  * @tc.type: FUNC
279  */
280 HWTEST_F(TopKBuilderTest, topk_build_011, TestSize.Level0)
281 {
282     std::vector<uint32_t> inputsIndex = { 0, 1 };
283     std::vector<uint32_t> outputsIndex = { 2, 3 };
284     std::vector<uint32_t> paramsIndex = { 4, 5 };
285     std::vector<int32_t> paramDim = {};
286 
287     InitTensor(inputsIndex, outputsIndex);
288     SaveSortedTensor(OH_NN_BOOL, paramDim, nullptr, OH_NN_TOP_K_SORTED);
289     SaveAxisTensor(OH_NN_INT64, paramDim, nullptr, OH_NN_SCALE_AXIS);
290 
291     OH_NN_ReturnCode ret = m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors);
292     EXPECT_EQ(OH_NN_INVALID_PARAMETER, ret);
293 }
294 
295 /**
296  * @tc.name: topk_get_primitive_001
297  * @tc.desc: Verify the GetPrimitive function return nullptr
298  * @tc.type: FUNC
299  */
300 HWTEST_F(TopKBuilderTest, topk_get_primitive_001, TestSize.Level0)
301 {
302     LiteGraphTensorPtr primitive = m_builder.GetPrimitive();
303     LiteGraphTensorPtr expectPrimitive = { nullptr, DestroyLiteGraphPrimitive };
304     EXPECT_EQ(primitive, expectPrimitive);
305 }
306 
307 /**
308  * @tc.name: topk_get_primitive_002
309  * @tc.desc: Verify the normal params return behavior of the getprimitive function
310  * @tc.type: FUNC
311  */
312 HWTEST_F(TopKBuilderTest, topk_get_primitive_002, TestSize.Level0)
313 {
314     std::vector<uint32_t> inputsIndex = { 0, 1 };
315     std::vector<uint32_t> outputsIndex = { 2, 3 };
316     std::vector<uint32_t> paramsIndex = { 4, 5 };
317     std::vector<int32_t> paramDim = {};
318 
319     InitTensor(inputsIndex, outputsIndex);
320     SaveSortedTensor(OH_NN_BOOL, paramDim, nullptr, OH_NN_TOP_K_SORTED);
321     SaveAxisTensor(OH_NN_INT64, paramDim, nullptr, OH_NN_TOP_K_AXIS);
322 
323     int64_t axisValue = 0;
324     EXPECT_EQ(OH_NN_SUCCESS, m_builder.Build(paramsIndex, m_inputsIndex, m_outputsIndex, m_allTensors));
325     LiteGraphTensorPtr primitive = m_builder.GetPrimitive();
326     LiteGraphTensorPtr expectPrimitive = { nullptr, DestroyLiteGraphPrimitive };
327     EXPECT_NE(primitive, expectPrimitive);
328 
329     auto sortedReturn = mindspore::lite::MindIR_TopKFusion_GetSorted(primitive.get());
330     EXPECT_EQ(sortedReturn, m_topkValue);
331     auto axisReturn = mindspore::lite::MindIR_TopKFusion_GetAxis(primitive.get());
332     EXPECT_EQ(axisReturn, axisValue);
333 }
334 } // namespace UnitTest
335 } // namespace NeuralNetworkRuntime
336 } // namespace OHOS
337