1 /**
2 * Copyright (c) 2021-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 "plugins/ets/tests/mock/mock_test_helper.h"
17
18 #include "runtime/include/runtime.h"
19 #include "runtime/include/runtime_options.h"
20 #include "plugins/ets/runtime/types/ets_method.h"
21
22 // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-magic-numbers)
23
24 namespace panda::ets::test {
25
26 class EtsNativeInterfaceArrayTest : public MockEtsNapiTestBaseClass {};
27
TEST_F(EtsNativeInterfaceArrayTest,NewPrimitiveArrayTestEmpty)28 TEST_F(EtsNativeInterfaceArrayTest, NewPrimitiveArrayTestEmpty)
29 {
30 ets_booleanArray array1 = env_->NewBooleanArray(0);
31 ASSERT_NE(array1, nullptr);
32 ASSERT_FALSE(env_->ErrorOccurred());
33 EXPECT_EQ(env_->GetArrayLength(array1), static_cast<ets_size>(0));
34
35 ets_byteArray array2 = env_->NewByteArray(0);
36 ASSERT_NE(array2, nullptr);
37 ASSERT_FALSE(env_->ErrorOccurred());
38 EXPECT_EQ(env_->GetArrayLength(array2), static_cast<ets_size>(0));
39
40 ets_charArray array3 = env_->NewCharArray(0);
41 ASSERT_NE(array3, nullptr);
42 ASSERT_FALSE(env_->ErrorOccurred());
43 EXPECT_EQ(env_->GetArrayLength(array3), static_cast<ets_size>(0));
44
45 ets_shortArray array4 = env_->NewShortArray(0);
46 ASSERT_NE(array4, nullptr);
47 ASSERT_FALSE(env_->ErrorOccurred());
48 EXPECT_EQ(env_->GetArrayLength(array4), static_cast<ets_size>(0));
49
50 ets_intArray array5 = env_->NewIntArray(0);
51 ASSERT_NE(array5, nullptr);
52 ASSERT_FALSE(env_->ErrorOccurred());
53 EXPECT_EQ(env_->GetArrayLength(array5), static_cast<ets_size>(0));
54
55 ets_longArray array6 = env_->NewLongArray(0);
56 ASSERT_NE(array6, nullptr);
57 ASSERT_FALSE(env_->ErrorOccurred());
58 EXPECT_EQ(env_->GetArrayLength(array6), static_cast<ets_size>(0));
59
60 ets_floatArray array7 = env_->NewFloatArray(0);
61 ASSERT_NE(array7, nullptr);
62 ASSERT_FALSE(env_->ErrorOccurred());
63 EXPECT_EQ(env_->GetArrayLength(array7), static_cast<ets_size>(0));
64
65 ets_doubleArray array8 = env_->NewDoubleArray(0);
66 ASSERT_NE(array8, nullptr);
67 ASSERT_FALSE(env_->ErrorOccurred());
68 EXPECT_EQ(env_->GetArrayLength(array8), static_cast<ets_size>(0));
69 }
70
TEST_F(EtsNativeInterfaceArrayTest,BooleanArray)71 TEST_F(EtsNativeInterfaceArrayTest, BooleanArray)
72 {
73 const std::vector<ets_boolean> src = {ETS_FALSE, ETS_FALSE, ETS_FALSE, ETS_TRUE, ETS_FALSE, ETS_FALSE};
74 ets_booleanArray array = env_->NewBooleanArray(src.size());
75 ASSERT_NE(array, nullptr);
76
77 ets_size length = env_->GetArrayLength(array);
78 ASSERT_EQ(length, src.size());
79
80 env_->SetBooleanArrayRegion(array, 0, src.size(), src.data());
81 {
82 // Use PinBooleanArray
83 ets_boolean *buf = env_->PinBooleanArray(array);
84 ASSERT_NE(buf, nullptr);
85 std::vector<ets_boolean> res1 = {buf, buf + length};
86 ASSERT_EQ(res1, src);
87
88 std::vector<ets_boolean> res2(src.size());
89 env_->GetBooleanArrayRegion(array, 0, src.size(), res2.data());
90 ASSERT_EQ(res2, src);
91
92 env_->UnpinBooleanArray(array);
93 }
94 {
95 // Use GetBooleanArrayRegion
96 std::vector<ets_boolean> vec(length);
97 env_->GetBooleanArrayRegion(array, 0, length, vec.data());
98 ASSERT_EQ(vec, src);
99 }
100 {
101 // Use GetBooleanArrayRegion with shift
102 ets_size half = length / 2;
103 std::vector<ets_boolean> vec(length - half);
104 env_->GetBooleanArrayRegion(array, half, length - half, vec.data());
105 ASSERT_TRUE(std::equal(src.begin() + half, src.end(), vec.begin()));
106 }
107 }
108
TEST_F(EtsNativeInterfaceArrayTest,ByteArray)109 TEST_F(EtsNativeInterfaceArrayTest, ByteArray)
110 {
111 const std::vector<ets_byte> src = {std::numeric_limits<ets_byte>::lowest(), -1, 0, 1,
112 std::numeric_limits<ets_byte>::max()};
113 ets_byteArray array = env_->NewByteArray(src.size());
114 ASSERT_NE(array, nullptr);
115
116 ets_size length = env_->GetArrayLength(array);
117 ASSERT_EQ(length, src.size());
118
119 env_->SetByteArrayRegion(array, 0, src.size(), src.data());
120 {
121 // Use PinByteArray
122 ets_byte *buf = env_->PinByteArray(array);
123 ASSERT_NE(buf, nullptr);
124 std::vector<ets_byte> res1 = {buf, buf + length};
125 ASSERT_EQ(res1, src);
126
127 std::vector<ets_byte> res2(src.size());
128 env_->GetByteArrayRegion(array, 0, src.size(), res2.data());
129 ASSERT_EQ(res2, src);
130
131 env_->UnpinByteArray(array);
132 }
133 {
134 // Use GetByteArrayRegion
135 std::vector<ets_byte> vec(length);
136 env_->GetByteArrayRegion(array, 0, length, vec.data());
137 ASSERT_EQ(vec, src);
138 }
139 {
140 // Use GetByteArrayRegion with shift
141 ets_size half = length / 2;
142 std::vector<ets_byte> vec(length - half);
143 env_->GetByteArrayRegion(array, half, length - half, vec.data());
144 ASSERT_TRUE(std::equal(src.begin() + half, src.end(), vec.begin()));
145 }
146 }
147
TEST_F(EtsNativeInterfaceArrayTest,CharArray)148 TEST_F(EtsNativeInterfaceArrayTest, CharArray)
149 {
150 const std::vector<ets_char> src = {std::numeric_limits<ets_char>::lowest(), 0, 1, 2, 3,
151 std::numeric_limits<ets_char>::max()};
152 ets_charArray array = env_->NewCharArray(src.size());
153 ASSERT_NE(array, nullptr);
154
155 ets_size length = env_->GetArrayLength(array);
156 ASSERT_EQ(length, src.size());
157
158 env_->SetCharArrayRegion(array, 0, src.size(), src.data());
159 {
160 // Use PinCharArray
161 ets_char *buf = env_->PinCharArray(array);
162 ASSERT_NE(buf, nullptr);
163 std::vector<ets_char> res1 = {buf, buf + length};
164 ASSERT_EQ(res1, src);
165
166 std::vector<ets_char> res2(src.size());
167 env_->GetCharArrayRegion(array, 0, src.size(), res2.data());
168 ASSERT_EQ(res2, src);
169
170 env_->UnpinCharArray(array);
171 }
172 {
173 // Use GetCharArrayRegion
174 std::vector<ets_char> vec(length);
175 env_->GetCharArrayRegion(array, 0, length, vec.data());
176 ASSERT_EQ(vec, src);
177 }
178 {
179 // Use GetCharArrayRegion with shift
180 ets_size half = length / 2;
181 std::vector<ets_char> vec(length - half);
182 env_->GetCharArrayRegion(array, half, length - half, vec.data());
183 ASSERT_TRUE(std::equal(src.begin() + half, src.end(), vec.begin()));
184 }
185 }
186
TEST_F(EtsNativeInterfaceArrayTest,ShortArray)187 TEST_F(EtsNativeInterfaceArrayTest, ShortArray)
188 {
189 const std::vector<ets_short> src = {std::numeric_limits<ets_short>::lowest(), -1, 0, 1,
190 std::numeric_limits<ets_short>::max()};
191 ets_shortArray array = env_->NewShortArray(src.size());
192 ASSERT_NE(array, nullptr);
193
194 ets_size length = env_->GetArrayLength(array);
195 ASSERT_EQ(length, src.size());
196
197 env_->SetShortArrayRegion(array, 0, src.size(), src.data());
198 {
199 // Use PinShortArray
200 ets_short *buf = env_->PinShortArray(array);
201 ASSERT_NE(buf, nullptr);
202 std::vector<ets_short> res1 = {buf, buf + length};
203 ASSERT_EQ(res1, src);
204
205 std::vector<ets_short> res2(src.size());
206 env_->GetShortArrayRegion(array, 0, src.size(), res2.data());
207 ASSERT_EQ(res2, src);
208
209 env_->UnpinShortArray(array);
210 }
211 {
212 // Use GetShortArrayRegion
213 std::vector<ets_short> vec(length);
214 env_->GetShortArrayRegion(array, 0, length, vec.data());
215 ASSERT_EQ(vec, src);
216 }
217 {
218 // Use GetShortArrayRegion with shift
219 ets_size half = length / 2;
220 std::vector<ets_short> vec(length - half);
221 env_->GetShortArrayRegion(array, half, length - half, vec.data());
222 ASSERT_TRUE(std::equal(src.begin() + half, src.end(), vec.begin()));
223 }
224 }
225
TEST_F(EtsNativeInterfaceArrayTest,IntArray)226 TEST_F(EtsNativeInterfaceArrayTest, IntArray)
227 {
228 const std::vector<ets_int> src = {std::numeric_limits<ets_int>::lowest(), -2, -1, 0, 1, 2,
229 std::numeric_limits<ets_int>::max()};
230 ets_intArray array = env_->NewIntArray(src.size());
231 ASSERT_NE(array, nullptr);
232
233 ets_size length = env_->GetArrayLength(array);
234 ASSERT_EQ(length, src.size());
235
236 env_->SetIntArrayRegion(array, 0, src.size(), src.data());
237 {
238 // Use PinIntArray
239 ets_int *buf = env_->PinIntArray(array);
240 ASSERT_NE(buf, nullptr);
241 std::vector<ets_int> res1 = {buf, buf + length};
242 ASSERT_EQ(res1, src);
243
244 std::vector<ets_int> res2(src.size());
245 env_->GetIntArrayRegion(array, 0, src.size(), res2.data());
246 ASSERT_EQ(res2, src);
247
248 env_->UnpinIntArray(array);
249 }
250 {
251 // Use GetIntArrayRegion
252 std::vector<ets_int> vec(length);
253 env_->GetIntArrayRegion(array, 0, length, vec.data());
254 ASSERT_EQ(vec, src);
255 }
256 {
257 // Use GetIntArrayRegion with shift
258 ets_size half = length / 2;
259 std::vector<ets_int> vec(length - half);
260 env_->GetIntArrayRegion(array, half, length - half, vec.data());
261 ASSERT_TRUE(std::equal(src.begin() + half, src.end(), vec.begin()));
262 }
263 }
264
TEST_F(EtsNativeInterfaceArrayTest,LongArray)265 TEST_F(EtsNativeInterfaceArrayTest, LongArray)
266 {
267 const std::vector<ets_long> src = {std::numeric_limits<ets_long>::lowest(), -1, 0, 1,
268 std::numeric_limits<ets_long>::max()};
269 ets_longArray array = env_->NewLongArray(src.size());
270 ASSERT_NE(array, nullptr);
271
272 ets_size length = env_->GetArrayLength(array);
273 ASSERT_EQ(length, src.size());
274
275 env_->SetLongArrayRegion(array, 0, src.size(), src.data());
276 {
277 // Use PinLongArray
278 ets_long *buf = env_->PinLongArray(array);
279 ASSERT_NE(buf, nullptr);
280 std::vector<ets_long> res1 = {buf, buf + length};
281 ASSERT_EQ(res1, src);
282
283 std::vector<ets_long> res2(src.size());
284 env_->GetLongArrayRegion(array, 0, src.size(), res2.data());
285 ASSERT_EQ(res2, src);
286
287 env_->UnpinLongArray(array);
288 }
289 {
290 // Use GetLongArrayRegion
291 std::vector<ets_long> vec(length);
292 env_->GetLongArrayRegion(array, 0, length, vec.data());
293 ASSERT_EQ(vec, src);
294 }
295 {
296 // Use GetLongArrayRegion with shift
297 ets_size half = length / 2;
298 std::vector<ets_long> vec(length - half);
299 env_->GetLongArrayRegion(array, half, length - half, vec.data());
300 ASSERT_TRUE(std::equal(src.begin() + half, src.end(), vec.begin()));
301 }
302 }
303
TEST_F(EtsNativeInterfaceArrayTest,FloatArray)304 TEST_F(EtsNativeInterfaceArrayTest, FloatArray)
305 {
306 const std::vector<ets_float> src = {std::numeric_limits<ets_float>::lowest(), -1.0F, 0.0F, 1.0F,
307 std::numeric_limits<ets_float>::max()};
308 ets_floatArray array = env_->NewFloatArray(src.size());
309 ASSERT_NE(array, nullptr);
310
311 ets_size length = env_->GetArrayLength(array);
312 ASSERT_EQ(length, src.size());
313
314 env_->SetFloatArrayRegion(array, 0, src.size(), src.data());
315 {
316 // Use PinFloatArray
317 ets_float *buf = env_->PinFloatArray(array);
318 ASSERT_NE(buf, nullptr);
319 std::vector<ets_float> res1 = {buf, buf + length};
320 ASSERT_EQ(res1, src);
321
322 std::vector<ets_float> res2(src.size());
323 env_->GetFloatArrayRegion(array, 0, src.size(), res2.data());
324 ASSERT_EQ(res2, src);
325
326 env_->UnpinFloatArray(array);
327 }
328 {
329 // Use GetFloatArrayRegion
330 std::vector<ets_float> vec(length);
331 env_->GetFloatArrayRegion(array, 0, length, vec.data());
332 ASSERT_EQ(vec, src);
333 }
334 {
335 // Use GetFloatArrayRegion with shift
336 ets_size half = length / 2;
337 std::vector<ets_float> vec(length - half);
338 env_->GetFloatArrayRegion(array, half, length - half, vec.data());
339 ASSERT_TRUE(std::equal(src.begin() + half, src.end(), vec.begin()));
340 }
341 }
342
TEST_F(EtsNativeInterfaceArrayTest,DoubleArray)343 TEST_F(EtsNativeInterfaceArrayTest, DoubleArray)
344 {
345 const std::vector<ets_double> src = {std::numeric_limits<ets_double>::lowest(), -1.1, 0, 1.1,
346 std::numeric_limits<ets_double>::max()};
347 ets_doubleArray array = env_->NewDoubleArray(src.size());
348 ASSERT_NE(array, nullptr);
349
350 ets_size length = env_->GetArrayLength(array);
351 ASSERT_EQ(length, src.size());
352
353 env_->SetDoubleArrayRegion(array, 0, src.size(), src.data());
354 {
355 // Use PinDoubleArray
356 ets_double *buf = env_->PinDoubleArray(array);
357 ASSERT_NE(buf, nullptr);
358 std::vector<ets_double> res1 = {buf, buf + length};
359 ASSERT_EQ(res1, src);
360
361 std::vector<ets_double> res2(src.size());
362 env_->GetDoubleArrayRegion(array, 0, src.size(), res2.data());
363 ASSERT_EQ(res2, src);
364
365 env_->UnpinDoubleArray(array);
366 }
367 {
368 // Use GetDoubleArrayRegion
369 std::vector<ets_double> vec(length);
370 env_->GetDoubleArrayRegion(array, 0, length, vec.data());
371 ASSERT_EQ(vec, src);
372 }
373 {
374 // Use GetDoubleArrayRegion with shift
375 ets_size half = length / 2;
376 std::vector<ets_double> vec(length - half);
377 env_->GetDoubleArrayRegion(array, half, length - half, vec.data());
378 ASSERT_TRUE(std::equal(src.begin() + half, src.end(), vec.begin()));
379 }
380 }
381
TEST_F(EtsNativeInterfaceArrayTest,NewObjectsArrayZeroAndOneSize)382 TEST_F(EtsNativeInterfaceArrayTest, NewObjectsArrayZeroAndOneSize)
383 {
384 ets_class cls = env_->FindClass("std/core/String");
385 ASSERT_NE(cls, nullptr);
386 const std::string example {"sample7"};
387 ets_string str = env_->NewStringUTF(example.c_str());
388 ASSERT_NE(str, nullptr);
389
390 ets_objectArray arrZero = env_->NewObjectsArray(0, cls, str);
391 EXPECT_EQ(env_->GetArrayLength(arrZero), static_cast<ets_size>(0));
392 ets_objectArray arrOne = env_->NewObjectsArray(1, cls, str);
393 EXPECT_EQ(env_->GetArrayLength(arrOne), static_cast<ets_size>(1));
394 }
395
TEST_F(EtsNativeInterfaceArrayTest,NewObjectArrayTest)396 TEST_F(EtsNativeInterfaceArrayTest, NewObjectArrayTest)
397 {
398 // NOLINTNEXTLINE(bugprone-string-literal-with-embedded-nul)
399 const std::vector<std::string> src = {"\t", "\n", "\0", "abcdefghijklmnopqrstuvwxyz",
400 "", "texttext", "ABCD", "1111111"};
401 std::vector<ets_string> etsSrc;
402 etsSrc.reserve(src.size());
403 for (auto &s : src) {
404 etsSrc.push_back(env_->NewStringUTF(s.c_str()));
405 }
406
407 ets_class cls = env_->FindClass("std/core/String");
408 ASSERT_NE(cls, nullptr);
409 ets_objectArray array = env_->NewObjectsArray(src.size(), cls, etsSrc[0]);
410 ASSERT_NE(array, nullptr);
411 ets_size size = env_->GetArrayLength(array);
412 ASSERT_EQ(size, src.size());
413 for (ets_size i = 1; i < size; ++i) {
414 env_->SetObjectArrayElement(array, i, etsSrc[i]);
415 }
416
417 std::vector<std::string> etsRes;
418 etsRes.reserve(src.size());
419 for (ets_size i = 0; i < size; ++i) {
420 auto str = static_cast<ets_string>(env_->GetObjectArrayElement(array, i));
421 ets_boolean isCopy;
422 const char *res = env_->GetStringUTFChars(str, &isCopy);
423 etsRes.emplace_back(res);
424 env_->ReleaseStringUTFChars(str, res);
425 }
426 ASSERT_EQ(etsRes, src);
427
428 panda::ets::napi::ScopedManagedCodeFix s(PandaEtsNapiEnv::ToPandaEtsEnv(env_));
429 auto *objectArr = s.Convert<EtsObjectArray>(array);
430 auto *desc = objectArr->GetClass()->GetDescriptor();
431
432 const char *expectedDesc = "[Lstd/core/String;";
433 uint32_t len = 18;
434 ASSERT_THAT(std::vector<char>(desc, desc + len), ::testing::ElementsAreArray(expectedDesc, len));
435 }
436
437 } // namespace panda::ets::test
438
439 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-magic-numbers)