1 /**
2 * Copyright (c) 2021-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 "ets_coroutine.h"
17 #include "include/mem/panda_string.h"
18 #include "libpandabase/utils/utf.h"
19 #include "types/ets_array.h"
20 #include "types/ets_string.h"
21 #include <gtest/gtest.h>
22 #include <cstdint>
23
24 // NOLINTBEGIN(readability-magic-numbers)
25
26 namespace ark::ets::test {
27 class EtsStringTest : public testing::Test {
28 public:
EtsStringTest()29 EtsStringTest()
30 {
31 options_.SetShouldLoadBootPandaFiles(true);
32 options_.SetShouldInitializeIntrinsics(false);
33 options_.SetCompilerEnableJit(false);
34 options_.SetGcType("epsilon");
35 options_.SetLoadRuntimes({"ets"});
36
37 auto stdlib = std::getenv("PANDA_STD_LIB");
38 if (stdlib == nullptr) {
39 std::cerr << "PANDA_STD_LIB env variable should be set and point to mock_stdlib.abc" << std::endl;
40 std::abort();
41 }
42 options_.SetBootPandaFiles({stdlib});
43
44 Runtime::Create(options_);
45 }
46
~EtsStringTest()47 ~EtsStringTest() override
48 {
49 Runtime::Destroy();
50 }
51
52 NO_COPY_SEMANTIC(EtsStringTest);
53 NO_MOVE_SEMANTIC(EtsStringTest);
54
SetUp()55 void SetUp() override
56 {
57 coroutine_ = EtsCoroutine::GetCurrent();
58 coroutine_->ManagedCodeBegin();
59 }
60
TearDown()61 void TearDown() override
62 {
63 coroutine_->ManagedCodeEnd();
64 }
65
66 private:
67 RuntimeOptions options_;
68 EtsCoroutine *coroutine_ = nullptr;
69 };
70
TEST_F(EtsStringTest,CreateFromUtf16)71 TEST_F(EtsStringTest, CreateFromUtf16)
72 {
73 std::vector<ets_char> data {0xffc3, 0x33, 0x00};
74
75 EtsString *firstEtsString = EtsString::CreateFromUtf16(data.data(), data.size());
76
77 auto *firstString = reinterpret_cast<coretypes::String *>(firstEtsString);
78 auto *secondString = reinterpret_cast<const uint16_t *>(data.data());
79
80 ASSERT_TRUE(coretypes::String::StringsAreEqualUtf16(firstString, secondString, data.size()));
81 }
82
TEST_F(EtsStringTest,CreateFromMUtf8)83 TEST_F(EtsStringTest, CreateFromMUtf8)
84 {
85 std::vector<uint8_t> data {0x01, 0x41, 0x24, 0x00};
86 auto *mutf8Data = reinterpret_cast<const char *>(data.data());
87
88 EtsString *firstEtsString = EtsString::CreateFromMUtf8(mutf8Data);
89
90 auto *firstString = reinterpret_cast<coretypes::String *>(firstEtsString);
91 auto *secondString = reinterpret_cast<const uint8_t *>(data.data());
92
93 ASSERT_TRUE(coretypes::String::StringsAreEqualMUtf8(
94 firstString, secondString, data.size() - 1)); // need to subtract 1 'cause of 0 in the end of Mutf8 string
95 }
96
TEST_F(EtsStringTest,CreateFromMUtf8WithLenArg)97 TEST_F(EtsStringTest, CreateFromMUtf8WithLenArg)
98 {
99 std::vector<uint8_t> data {0x01, 0x41, 0x24, 0x00};
100 auto *mutf8Data = reinterpret_cast<const char *>(data.data());
101
102 EtsString *firstEtsString = EtsString::CreateFromMUtf8(
103 mutf8Data, data.size() - 1); // need to subtract 1 'cause of 0 in the end of Mutf8 string
104
105 auto *firstString = reinterpret_cast<coretypes::String *>(firstEtsString);
106 auto *secondString = reinterpret_cast<const uint8_t *>(data.data());
107
108 ASSERT_TRUE(coretypes::String::StringsAreEqualMUtf8(
109 firstString, secondString, data.size() - 1)); // need to subtract 1 'cause of 0 in the end of Mutf8 string
110 }
111
TEST_F(EtsStringTest,ToCharArray)112 TEST_F(EtsStringTest, ToCharArray)
113 {
114 std::vector<uint8_t> data {'a', 'b', 'c', 'd', 'e', 0};
115 auto *mutf8Data = reinterpret_cast<const char *>(data.data());
116 EtsString *utf8String = EtsString::CreateFromMUtf8(mutf8Data, data.size() - 1);
117 EtsArray *newArray = utf8String->ToCharArray();
118
119 for (uint32_t i = 0; i < newArray->GetLength(); ++i) {
120 ASSERT_EQ(data[i], newArray->GetCoreType()->Get<uint16_t>(i));
121 }
122
123 std::vector<ets_char> data1 {'f', 'g', 'h', 'a', 'b', 0x8ab, 0xdc, 'z', 0};
124 EtsString *utf16String = EtsString::CreateFromUtf16(data1.data(), data1.size());
125 EtsArray *newArray1 = utf16String->ToCharArray();
126
127 for (uint32_t i = 0; i < newArray1->GetLength(); ++i) {
128 ASSERT_EQ(data1[i], newArray1->GetCoreType()->Get<uint16_t>(i));
129 }
130 }
131
TEST_F(EtsStringTest,CreateFromUtf8)132 TEST_F(EtsStringTest, CreateFromUtf8)
133 {
134 std::vector<uint8_t> data {0x01, 0x41, 0x24, 0x32, 0x16, 0x08};
135 size_t firstStringLength = data.size();
136 auto *utf8Data = reinterpret_cast<const char *>(data.data());
137
138 EtsString *firstEtsString = EtsString::CreateFromUtf8(utf8Data, firstStringLength);
139 auto *firstString = reinterpret_cast<const uint8_t *>(data.data());
140
141 // Test full string
142 ASSERT_TRUE(utf::IsEqual({firstEtsString->GetDataMUtf8(), firstStringLength}, {firstString, firstStringLength}));
143 ASSERT_TRUE(
144 utf::IsEqual({firstEtsString->GetDataMUtf8(), firstStringLength - 2}, {firstString, firstStringLength - 2}));
145
146 size_t thirdStringLength = firstStringLength / 2;
147 EtsString *thirdEtsString = EtsString::CreateFromUtf8(utf8Data, thirdStringLength);
148 auto *thirdString = reinterpret_cast<coretypes::String *>(thirdEtsString);
149
150 // Utf8 format, no need to have \0 at the end, so check half string
151 ASSERT_TRUE(utf::IsEqual({firstEtsString->GetDataMUtf8(), thirdStringLength},
152 {thirdString->GetDataMUtf8(), thirdStringLength}));
153 ASSERT_TRUE(utf::IsEqual({firstEtsString->GetDataMUtf8(), thirdStringLength - 1},
154 {thirdString->GetDataMUtf8(), thirdStringLength - 1}));
155 }
156
TEST_F(EtsStringTest,CreateNewStringFromChars)157 TEST_F(EtsStringTest, CreateNewStringFromChars)
158 {
159 std::vector<ets_char> data {0x8ab, 0xdc, 'h', 'e', 'l', 'l', 'o', 0};
160
161 EtsString *utf16String = EtsString::CreateFromUtf16(data.data(), data.size());
162 EtsArray *charArray = utf16String->ToCharArray();
163
164 uint32_t beginOffset = 2;
165 uint32_t length = data.size() - beginOffset;
166
167 // make char array from subdata
168 std::vector<ets_char> subdata {'h', 'e', 'l', 'l', 'o', 0};
169
170 EtsString *expectedString = EtsString::CreateFromUtf16(subdata.data(), subdata.size());
171
172 EtsString *stringFromCharArray = EtsString::CreateNewStringFromChars(beginOffset, length, charArray);
173
174 ASSERT_TRUE(coretypes::String::StringsAreEqual(reinterpret_cast<coretypes::String *>(expectedString),
175 reinterpret_cast<coretypes::String *>(stringFromCharArray)));
176 }
177
TEST_F(EtsStringTest,CreateNewStringFromString)178 TEST_F(EtsStringTest, CreateNewStringFromString)
179 {
180 std::vector<ets_char> data {0xffc3, 0x33, 0x00};
181
182 EtsString *string1 = EtsString::CreateFromUtf16(data.data(), data.size());
183 EtsString *string2 = EtsString::CreateFromUtf16(data.data(), data.size() - 1);
184 EtsString *createdString = EtsString::CreateNewStringFromString(string1);
185
186 ASSERT_TRUE(coretypes::String::StringsAreEqual(reinterpret_cast<coretypes::String *>(string1),
187 reinterpret_cast<coretypes::String *>(createdString)));
188
189 ASSERT_FALSE(coretypes::String::StringsAreEqual(reinterpret_cast<coretypes::String *>(string2),
190 reinterpret_cast<coretypes::String *>(createdString)));
191 }
192
TEST_F(EtsStringTest,CreateNewEmptyString)193 TEST_F(EtsStringTest, CreateNewEmptyString)
194 {
195 ets_char data = 0;
196 EtsString *str1 = EtsString::CreateFromUtf16(&data, 0);
197 EtsString *str2 = EtsString::CreateFromUtf16(&data, 1);
198 EtsString *str3 = EtsString::CreateNewEmptyString();
199
200 ASSERT_TRUE(coretypes::String::StringsAreEqual(reinterpret_cast<coretypes::String *>(str1),
201 reinterpret_cast<coretypes::String *>(str3)));
202 ASSERT_FALSE(coretypes::String::StringsAreEqual(reinterpret_cast<coretypes::String *>(str2),
203 reinterpret_cast<coretypes::String *>(str3)));
204 }
205
TEST_F(EtsStringTest,Compare)206 TEST_F(EtsStringTest, Compare)
207 {
208 // utf8 vs utf8
209 std::vector<uint8_t> data1 {'a', 'b', 'c', 'd', 'z', 0};
210 std::vector<uint8_t> data2 {'a', 'b', 'c', 'd', 'z', 'x', 0};
211 std::vector<uint16_t> data3 {'a', 'b', 'c', 'd', 'z', 0};
212 std::vector<uint16_t> data4 {'a', 'b', 'd', 'c', 'z', 0};
213
214 auto *mutf8Data1 = reinterpret_cast<const char *>(data1.data());
215 auto *mutf8Data2 = reinterpret_cast<const char *>(data2.data());
216
217 EtsString *string1 = EtsString::CreateFromMUtf8(mutf8Data1);
218 EtsString *string2 = EtsString::CreateFromMUtf8(mutf8Data2);
219 EtsString *string3 = EtsString::CreateFromUtf16(data3.data(), data3.size() - 1);
220 EtsString *string4 = EtsString::CreateFromUtf16(data4.data(), data4.size() - 1);
221
222 ASSERT_EQ(false, string1->IsUtf16());
223 ASSERT_EQ(false, string2->IsUtf16());
224 ASSERT_EQ(false, string3->IsUtf16());
225 ASSERT_EQ(false, string4->IsUtf16());
226 ASSERT_LT(string1->Compare(string2), 0);
227 ASSERT_GT(string2->Compare(string1), 0);
228 ASSERT_EQ(string1->Compare(string3), 0);
229 ASSERT_EQ(string3->Compare(string1), 0);
230 ASSERT_LT(string2->Compare(string4), 0);
231 ASSERT_GT(string4->Compare(string2), 0);
232
233 // utf8 vs utf16
234 std::vector<uint16_t> data5 {'a', 'b', 0xab, 0xdc, 'z', 0};
235 EtsString *string5 = EtsString::CreateFromUtf16(data5.data(), data5.size() - 1);
236
237 ASSERT_EQ(true, string5->IsUtf16());
238 ASSERT_LT(string2->Compare(string5), 0);
239 ASSERT_GT(string5->Compare(string2), 0);
240 ASSERT_LT(string4->Compare(string5), 0);
241 ASSERT_GT(string5->Compare(string4), 0);
242
243 // utf16 vs utf16
244 std::vector<uint16_t> data6 {'a', 0xab, 0xab, 0};
245 EtsString *string6 = EtsString::CreateFromUtf16(data6.data(), data6.size() - 1);
246 EtsString *string7 = EtsString::CreateFromUtf16(data6.data(), data6.size() - 1);
247
248 ASSERT_EQ(true, string6->IsUtf16());
249 ASSERT_EQ(true, string7->IsUtf16());
250 ASSERT_LT(string5->Compare(string6), 0);
251 ASSERT_GT(string6->Compare(string5), 0);
252 ASSERT_EQ(string6->Compare(string7), 0);
253 ASSERT_EQ(string7->Compare(string6), 0);
254
255 // compare with self
256 ASSERT_EQ(string1->Compare(string1), 0);
257 ASSERT_EQ(string2->Compare(string2), 0);
258 ASSERT_EQ(string3->Compare(string3), 0);
259 ASSERT_EQ(string4->Compare(string4), 0);
260 ASSERT_EQ(string5->Compare(string5), 0);
261 ASSERT_EQ(string6->Compare(string6), 0);
262 ASSERT_EQ(string7->Compare(string7), 0);
263 }
264
TEST_F(EtsStringTest,Concat)265 TEST_F(EtsStringTest, Concat)
266 {
267 // utf8 + utf8
268 std::vector<uint8_t> data1 {'H', 'e', 'l', 'l', 'o', 0};
269 std::vector<uint8_t> data2 {'w', 'o', 'r', 'l', 'd', '!', 0};
270 std::vector<uint8_t> data3;
271
272 data3.insert(data3.end(), data1.begin(), data1.end() - 1);
273 data3.insert(data3.end(), data2.begin(), data2.end());
274
275 auto *mutf8Data1 = reinterpret_cast<const char *>(data1.data());
276 auto *mutf8Data2 = reinterpret_cast<const char *>(data2.data());
277 auto *mutf8Data3 = reinterpret_cast<const char *>(data3.data());
278
279 EtsString *str1 = EtsString::CreateFromMUtf8(mutf8Data1);
280 EtsString *str2 = EtsString::CreateFromMUtf8(mutf8Data2);
281 EtsString *str3 = EtsString::Concat(str1, str2);
282 EtsString *expectedStr1 = EtsString::CreateFromMUtf8(mutf8Data3);
283
284 ASSERT_EQ(str3->Compare(expectedStr1), 0);
285 ASSERT_EQ(expectedStr1->Compare(str3), 0);
286
287 // utf16 + utf16
288 std::vector<uint16_t> data4 {'a', 'b', 'c', 'd', 0};
289 std::vector<uint16_t> data5 {'e', 'f', 'g', 0};
290 std::vector<uint16_t> data6;
291
292 data6.insert(data6.end(), data4.begin(), data4.end() - 1);
293 data6.insert(data6.end(), data5.begin(), data5.end());
294
295 EtsString *str4 = EtsString::CreateFromUtf16(data4.data(), data4.size() - 1);
296 EtsString *str5 = EtsString::CreateFromUtf16(data5.data(), data5.size());
297 EtsString *str6 = EtsString::Concat(str4, str5);
298 EtsString *expectedStr2 = EtsString::CreateFromUtf16(data6.data(), data6.size());
299
300 ASSERT_EQ(str6->Compare(expectedStr2), 0);
301 ASSERT_EQ(expectedStr2->Compare(str6), 0);
302
303 // utf8 + utf16
304 std::vector<uint16_t> data7;
305 data7.insert(data7.end(), data1.begin(), data1.end() - 1);
306 data7.insert(data7.end(), data4.begin(), data4.end() - 1);
307
308 EtsString *str7 = EtsString::Concat(str1, str4);
309 EtsString *expectedStr3 = EtsString::CreateFromUtf16(data7.data(), data7.size());
310
311 ASSERT_EQ(str7->Compare(expectedStr3), 0);
312 ASSERT_EQ(expectedStr3->Compare(str7), 0);
313 }
314
TEST_F(EtsStringTest,At)315 TEST_F(EtsStringTest, At)
316 {
317 // utf8
318 std::vector<uint8_t> data1 {'a', 'b', 'c', 'd', 'z', 0};
319 auto *mutf8Data1 = reinterpret_cast<const char *>(data1.data());
320 EtsString *string = EtsString::CreateFromMUtf8(mutf8Data1, data1.size() - 1);
321 ASSERT_EQ(false, string->IsUtf16());
322 for (uint32_t i = 0; i < data1.size() - 1; i++) {
323 ASSERT_EQ(data1[i], string->At(i));
324 }
325
326 // utf16
327 std::vector<uint16_t> data2 {'a', 'b', 0xab, 0xdc, 'z', 0};
328 string = EtsString::CreateFromUtf16(data2.data(), data2.size() - 1);
329 ASSERT_EQ(true, string->IsUtf16());
330 for (uint32_t i = 0; i < data2.size() - 1; i++) {
331 ASSERT_EQ(data2[i], string->At(i));
332 }
333
334 // utf16 -> utf8
335 std::vector<uint16_t> data3 {'a', 'b', 121, 122, 'z', 0};
336 string = EtsString::CreateFromUtf16(data3.data(), data3.size() - 1);
337 ASSERT_EQ(false, string->IsUtf16());
338 for (uint32_t i = 0; i < data3.size() - 1; i++) {
339 ASSERT_EQ(data3[i], string->At(i));
340 }
341 }
342
TEST_F(EtsStringTest,DoReplace)343 TEST_F(EtsStringTest, DoReplace)
344 {
345 uint32_t len = 10;
346 std::vector<char> data1(len + 1);
347 std::vector<char> data2(len + 1);
348
349 for (uint32_t i = 0; i < len; i++) {
350 data1[i] = 'A' + i;
351 data2[i] = 'A' + i;
352 }
353
354 data1.front() = 'Z';
355 data1.back() = '\0';
356 data2.back() = '\0';
357
358 EtsString *str1 = EtsString::CreateFromMUtf8(data1.data());
359 EtsString *str2 = EtsString::CreateFromMUtf8(data2.data());
360 EtsString *str3 = EtsString::DoReplace(str1, 'Z', 'A');
361
362 ASSERT_NE(str1->Compare(str2), 0);
363 ASSERT_EQ(str2->Compare(str3), 0);
364 }
365
TEST_F(EtsStringTest,FastSubString)366 TEST_F(EtsStringTest, FastSubString)
367 {
368 uint32_t strLen = 10;
369 uint32_t subStrLen = 5;
370 uint32_t subStrStart = 1;
371
372 std::vector<char> data1(strLen + 1);
373 std::vector<char> data2(subStrLen + 1);
374
375 for (uint32_t i = 0; i < strLen; i++) {
376 data1[i] = 'A' + i;
377 }
378 data1.back() = '\0';
379
380 for (uint32_t i = 0; i < subStrLen; i++) {
381 data2[i] = data1[subStrStart + i];
382 }
383 data2.back() = '\0';
384
385 EtsString *str1 = EtsString::CreateFromMUtf8(data1.data());
386 EtsString *str2 = EtsString::CreateFromMUtf8(data2.data());
387 EtsString *str3 = EtsString::FastSubString(str1, subStrStart, subStrLen);
388
389 ASSERT_EQ(str3->Compare(str2), 0);
390 }
391
TEST_F(EtsStringTest,GetLength)392 TEST_F(EtsStringTest, GetLength)
393 {
394 // utf16
395 std::vector<uint16_t> data1 {0xffc3, 0x33, 0x00};
396 EtsString *str = EtsString::CreateFromUtf16(data1.data(), data1.size());
397 ASSERT_EQ(str->GetLength(), data1.size());
398
399 // utf8
400 std::vector<char> data2 {'H', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '!', 0};
401 str = EtsString::CreateFromMUtf8(data2.data());
402
403 ASSERT_EQ(false, str->IsUtf16());
404 ASSERT_EQ(str->GetLength(), data2.size() - 1);
405 }
406
TEST_F(EtsStringTest,GetMUtf8Length)407 TEST_F(EtsStringTest, GetMUtf8Length)
408 {
409 std::vector<char> data2 {'H', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '!', 0};
410 EtsString *str = EtsString::CreateFromMUtf8(data2.data());
411 ASSERT_EQ(false, str->IsUtf16());
412 ASSERT_EQ(str->GetMUtf8Length(), data2.size());
413 ASSERT_EQ(str->GetMUtf8Length(), str->GetLength() + 1);
414 }
415
TEST_F(EtsStringTest,GetUtf16Length)416 TEST_F(EtsStringTest, GetUtf16Length)
417 {
418 std::vector<uint16_t> data1 {0xffc3, 0x33, 'a', 'b', 'c', 0x00};
419 EtsString *str = EtsString::CreateFromUtf16(data1.data(), data1.size());
420 ASSERT_EQ(true, str->IsUtf16());
421 ASSERT_EQ(str->GetUtf16Length(), data1.size());
422 ASSERT_EQ(str->GetLength(), str->GetUtf16Length());
423 }
424
TEST_F(EtsStringTest,CopyDataMUtf8)425 TEST_F(EtsStringTest, CopyDataMUtf8)
426 {
427 std::vector<char> data {'a', 'b', 'c', 'd', 'z', 0};
428 std::vector<char> copiedDataMutf8(data.size());
429 EtsString *str = EtsString::CreateFromMUtf8(data.data());
430
431 ASSERT_EQ(str->CopyDataMUtf8(copiedDataMutf8.data(), copiedDataMutf8.size(), true), data.size());
432 ASSERT_EQ(copiedDataMutf8, data);
433 }
434
TEST_F(EtsStringTest,CopyDataUtf16)435 TEST_F(EtsStringTest, CopyDataUtf16)
436 {
437 std::vector<char> data {'a', 'b', 'c', 'd', 'z', 0};
438 EtsString *str = EtsString::CreateFromMUtf8(data.data());
439 std::vector<uint16_t> resUtf16 {'a', 'b', 'c', 'd', 'z'};
440 std::vector<uint16_t> copiedDataUtf16(resUtf16.size());
441
442 ASSERT_EQ(str->CopyDataUtf16(copiedDataUtf16.data(), copiedDataUtf16.size()), resUtf16.size());
443 ASSERT_EQ(copiedDataUtf16, resUtf16);
444 }
445
TEST_F(EtsStringTest,CopyDataRegionMUtf8)446 TEST_F(EtsStringTest, CopyDataRegionMUtf8)
447 {
448 std::vector<char> data {'a', 'b', 'h', 'e', 'l', 'l', 'o', 'c', 'd', 'z', 0};
449 std::vector<char> res {'h', 'e', 'l', 'l', 'o', 0};
450 std::vector<char> copiedDataMutf8(res.size());
451 size_t start = 2;
452 size_t len = 5;
453 EtsString *str = EtsString::CreateFromMUtf8(data.data());
454
455 ASSERT_EQ(str->CopyDataRegionMUtf8(copiedDataMutf8.data(), start, len, copiedDataMutf8.size()), res.size() - 1);
456 ASSERT_EQ(copiedDataMutf8, res);
457
458 std::vector<uint16_t> res16 {'h', 'e', 'l', 'l', 'o'};
459 std::vector<uint16_t> copiedDataUtf16(res16.size());
460
461 ASSERT_EQ(str->CopyDataRegionUtf16(copiedDataUtf16.data(), start, len, copiedDataUtf16.size()), res16.size());
462 ASSERT_EQ(copiedDataUtf16, res16);
463 }
464
TEST_F(EtsStringTest,CopyDataRegionUtf16)465 TEST_F(EtsStringTest, CopyDataRegionUtf16)
466 {
467 std::vector<uint16_t> data {0xb7, 0xc7, 0xa4, 'h', 'e', 'l', 'l', 'o', 0xa7, 0};
468 std::vector<uint8_t> res {'h', 'e', 'l', 'l', 'o', 0};
469 std::vector<uint8_t> copiedDataMutf8(res.size());
470 size_t start = 3;
471 size_t len = 5;
472 EtsString *str = EtsString::CreateFromUtf16(data.data(), data.size());
473
474 ASSERT_EQ(str->CopyDataRegionMUtf8(copiedDataMutf8.data(), start, len, copiedDataMutf8.size()), res.size() - 1);
475 ASSERT_EQ(copiedDataMutf8, res);
476
477 std::vector<uint16_t> res16 {'h', 'e', 'l', 'l', 'o'};
478 std::vector<uint16_t> copiedDataUtf16(res16.size());
479
480 ASSERT_EQ(str->CopyDataRegionUtf16(copiedDataUtf16.data(), start, len, copiedDataUtf16.size()), res16.size());
481 ASSERT_EQ(copiedDataUtf16, res16);
482 }
483
TEST_F(EtsStringTest,IsEqual)484 TEST_F(EtsStringTest, IsEqual)
485 {
486 std::vector<char> data1 {'a', 'b', 'c', 'd', 'e', 0};
487 std::vector<char> data2 {'a', 'b', 'c', 'd', 'f', 0};
488 char data3 = 0;
489
490 EtsString *str1 = EtsString::CreateFromMUtf8(data1.data());
491 EtsString *str2 = EtsString::CreateFromMUtf8(data2.data());
492 EtsString *str3 = EtsString::CreateNewEmptyString();
493
494 ASSERT_TRUE(str1->IsEqual(data1.data()));
495 ASSERT_TRUE(str2->IsEqual(data2.data()));
496 ASSERT_TRUE(str3->IsEqual(&data3));
497 ASSERT_FALSE(str1->IsEqual(data2.data()));
498 ASSERT_FALSE(str2->IsEqual(data1.data()));
499 ASSERT_FALSE(str1->IsEqual(&data3));
500 ASSERT_FALSE(str2->IsEqual(&data3));
501 ASSERT_FALSE(str3->IsEqual(data1.data()));
502 ASSERT_FALSE(str3->IsEqual(data2.data()));
503 }
504
TEST_F(EtsStringTest,IsEmpty)505 TEST_F(EtsStringTest, IsEmpty)
506 {
507 std::vector<char> data {'a', 'f', 'a', 0};
508 EtsString *str1 = EtsString::CreateFromMUtf8(data.data());
509 EtsString *str2 = EtsString::CreateNewEmptyString();
510
511 ASSERT_FALSE(str1->IsEmpty());
512 ASSERT_TRUE(str2->IsEmpty());
513 }
514
TEST_F(EtsStringTest,StringsAreEqual)515 TEST_F(EtsStringTest, StringsAreEqual)
516 {
517 std::vector<char> data1 {'a', 'b', 's', 'r', 'd', 'r', 0};
518 std::vector<char> data2 {'a', 'b', 's', 0};
519
520 EtsString *str1 = EtsString::CreateFromMUtf8(data1.data(), data1.size() - 1);
521 data1[data1.size() - 4U] = 0;
522 EtsString *str2 = EtsString::CreateFromMUtf8(data1.data(), data1.size() - 4U);
523 EtsString *str3 = EtsString::CreateFromMUtf8(data2.data());
524
525 ASSERT_TRUE(str1->StringsAreEqual(reinterpret_cast<EtsObject *>(str1)));
526 ASSERT_TRUE(str2->StringsAreEqual(reinterpret_cast<EtsObject *>(str2)));
527 ASSERT_TRUE(str3->StringsAreEqual(reinterpret_cast<EtsObject *>(str3)));
528 ASSERT_TRUE(str2->StringsAreEqual(reinterpret_cast<EtsObject *>(str3)));
529 ASSERT_TRUE(str3->StringsAreEqual(reinterpret_cast<EtsObject *>(str2)));
530
531 ASSERT_FALSE(str1->StringsAreEqual(reinterpret_cast<EtsObject *>(str2)));
532 ASSERT_FALSE(str2->StringsAreEqual(reinterpret_cast<EtsObject *>(str1)));
533 }
534
TEST_F(EtsStringTest,GetCoreType)535 TEST_F(EtsStringTest, GetCoreType)
536 {
537 std::vector<char> data {'a', 'b', 'c', 'd', 0};
538 EtsString *str = EtsString::CreateFromMUtf8(data.data());
539 EtsString *emptyStr = EtsString::CreateNewEmptyString();
540
541 ASSERT_EQ(reinterpret_cast<coretypes::String *>(str), str->GetCoreType());
542 ASSERT_EQ(reinterpret_cast<coretypes::String *>(emptyStr), emptyStr->GetCoreType());
543 }
544
TEST_F(EtsStringTest,FromEtsObject)545 TEST_F(EtsStringTest, FromEtsObject)
546 {
547 std::vector<char> data {'a', 'b', 'c', 'd', 'e', 0};
548
549 EtsString *str1 = EtsString::CreateFromMUtf8(data.data());
550 EtsString *str3 = EtsString::CreateNewEmptyString();
551
552 ASSERT_EQ(str1->Compare(EtsString::FromEtsObject(reinterpret_cast<EtsObject *>(str1))), 0);
553 ASSERT_EQ(str3->Compare(EtsString::FromEtsObject(reinterpret_cast<EtsObject *>(str3))), 0);
554 }
555
TEST_F(EtsStringTest,CreateNewStringFromBytes)556 TEST_F(EtsStringTest, CreateNewStringFromBytes)
557 {
558 std::vector<uint8_t> data {'f', 'g', 'h', 'a', 'b', 0xab, 0xdc, 'z', 0};
559 uint32_t byteArrayLength = 5;
560 uint32_t byteArrayOffset = 1;
561 uint32_t highByte = 1;
562
563 std::vector<uint16_t> data1(byteArrayLength);
564 for (uint32_t i = 0; i < byteArrayLength; ++i) {
565 data1[i] = (highByte << 8U) + (data[i + byteArrayOffset]);
566 }
567
568 EtsString *string1 = EtsString::CreateFromUtf16(data1.data(), byteArrayLength);
569 EtsByteArray *byteArray = EtsByteArray::Create(data.size() - 1);
570
571 Span<uint8_t> sp(data.data(), data.size() - 1);
572 for (uint32_t i = 0; i < data.size() - 1; i++) {
573 byteArray->Set(i, sp[i]);
574 }
575
576 EtsString *result = EtsString::CreateNewStringFromBytes(byteArray, highByte, byteArrayOffset, byteArrayLength);
577
578 ASSERT_TRUE(result->StringsAreEqual(reinterpret_cast<EtsObject *>(string1)));
579 }
580
TEST_F(EtsStringTest,GetDataUtf16)581 TEST_F(EtsStringTest, GetDataUtf16)
582 {
583 std::vector<uint16_t> data = {'a', 'b', 'c', 'd', 'e', 0xac, 0};
584
585 EtsString *string1 = EtsString::CreateFromUtf16(data.data(), data.size());
586 ASSERT_TRUE(string1->IsUtf16());
587 EtsString *string2 = EtsString::CreateFromUtf16(string1->GetDataUtf16(), data.size());
588 ASSERT_TRUE(string2->IsUtf16());
589
590 ASSERT_TRUE(string1->StringsAreEqual(reinterpret_cast<EtsObject *>(string2)));
591 }
592
TEST_F(EtsStringTest,GetDataMUtf8)593 TEST_F(EtsStringTest, GetDataMUtf8)
594 {
595 std::vector<char> data = {'a', 'b', 'c', 'd', 'e', 0};
596
597 EtsString *string1 = EtsString::CreateFromMUtf8(data.data());
598 ASSERT_FALSE(string1->IsUtf16());
599
600 std::vector<uint8_t> data2(string1->GetDataMUtf8(), string1->GetDataMUtf8() + data.size() - 1); // NOLINT
601 data2.push_back(0); // GetDataMUtf8 return array without 0
602
603 EtsString *string2 = EtsString::CreateFromMUtf8(reinterpret_cast<const char *>(data2.data()));
604 ASSERT_FALSE(string2->IsUtf16());
605
606 ASSERT_TRUE(string1->StringsAreEqual(reinterpret_cast<EtsObject *>(string2)));
607 }
608
TEST_F(EtsStringTest,GetMutf8)609 TEST_F(EtsStringTest, GetMutf8)
610 {
611 std::vector<char> data = {'h', 'e', 'l', 'l', 'o', 0};
612
613 EtsString *string = EtsString::CreateFromMUtf8(data.data());
614 PandaString pandaString = string->GetMutf8();
615
616 ASSERT_EQ(strcmp(pandaString.data(), "hello"), 0);
617 }
618
TEST_F(EtsStringTest,ConvertToStringView)619 TEST_F(EtsStringTest, ConvertToStringView)
620 {
621 PandaVector<uint8_t> buf;
622 auto emptyString = EtsString::CreateNewEmptyString();
623 auto emptyStringView = emptyString->ConvertToStringView(&buf);
624 ASSERT_EQ(emptyStringView, "");
625
626 std::vector<uint8_t> data1 {0, 'H', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '!'};
627 std::vector<uint8_t> data2 {'H', 'e', 'l', 'l', 'o', 0, 'w', 'o', 'r', 'l', 'd', '!'};
628 std::vector<uint8_t> data3 {'H', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '!', 0};
629 auto testString1 = EtsString::CreateFromMUtf8(reinterpret_cast<const char *>(data1.data()));
630 auto testString2 = EtsString::CreateFromMUtf8(reinterpret_cast<const char *>(data2.data()));
631 auto testString3 = EtsString::CreateFromMUtf8(reinterpret_cast<const char *>(data3.data()));
632
633 auto testString1View = testString1->ConvertToStringView(&buf);
634 ASSERT_EQ(testString1View, "");
635 auto testString2View = testString2->ConvertToStringView(&buf);
636 ASSERT_EQ(testString2View, "Hello");
637 auto testString3View = testString3->ConvertToStringView(&buf);
638 ASSERT_EQ(testString3View, "Helloworld!");
639 }
640
TEST_F(EtsStringTest,Resolve)641 TEST_F(EtsStringTest, Resolve)
642 {
643 std::vector<uint8_t> data {'H', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '!', 0};
644
645 EtsString *string1 = EtsString::Resolve(data.data(), data.size() - 1);
646 EtsString *string2 = EtsString::Resolve(data.data(), data.size() - 1);
647 EtsString *string3 = EtsString::CreateFromMUtf8(reinterpret_cast<const char *>(data.data()));
648
649 ASSERT_EQ(string1, string2);
650 ASSERT_TRUE(string1->StringsAreEqual(reinterpret_cast<EtsObject *>(string3)));
651 ASSERT_TRUE(string2->StringsAreEqual(reinterpret_cast<EtsObject *>(string3)));
652 }
653
CheckConvertString(EtsString * str)654 void CheckConvertString(EtsString *str)
655 {
656 const std::vector<uint16_t> referenceUtf16 {'a', '\0', 'b', 0x20AC, 'z', '\n'};
657 const std::vector<uint8_t> referenceUtf8 {'a', '\0', 'b', 0xe2, 0x82, 0xac, 'z', '\n'};
658 const std::vector<uint8_t> referenceMUtf8 {'a', 0xc0, 0x80, 'b', 0xe2, 0x82, 0xac, 'z', '\n'};
659
660 PandaString utf8 = str->GetUtf8();
661 PandaString mutf8 = str->GetMutf8();
662 ASSERT_EQ(utf8.size(), referenceUtf8.size());
663 ASSERT_EQ(mutf8.size(), referenceMUtf8.size());
664
665 for (size_t i = 0; i < referenceUtf8.size(); ++i) {
666 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
667 ASSERT_EQ(static_cast<uint8_t>(utf8[i]), referenceUtf8[i]);
668 }
669 for (size_t i = 0; i < referenceMUtf8.size(); ++i) {
670 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
671 ASSERT_EQ(static_cast<uint8_t>(mutf8[i]), referenceMUtf8[i]);
672 }
673
674 auto utf16Data = str->GetDataUtf16();
675 auto utf16Len = str->GetUtf16Length();
676 ASSERT_EQ(utf16Len, referenceUtf16.size());
677
678 for (size_t i = 0; i < utf16Len; ++i) {
679 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
680 ASSERT_EQ(utf16Data[i], referenceUtf16[i]);
681 }
682 }
683
TEST_F(EtsStringTest,ConvertFromUtf16)684 TEST_F(EtsStringTest, ConvertFromUtf16)
685 {
686 std::vector<uint16_t> data {'a', '\0', 'b', 0x20AC, 'z', '\n'};
687 EtsString *str = EtsString::CreateFromUtf16(data.data(), data.size());
688 CheckConvertString(str);
689 }
690
TEST_F(EtsStringTest,ConvertFromUtf8)691 TEST_F(EtsStringTest, ConvertFromUtf8)
692 {
693 std::vector<uint8_t> data {'a', '\0', 'b', 0xe2, 0x82, 0xac, 'z', '\n'};
694 auto *utf8Data = reinterpret_cast<const char *>(data.data());
695 EtsString *str = EtsString::CreateFromUtf8(utf8Data, data.size());
696 CheckConvertString(str);
697 }
698
TEST_F(EtsStringTest,ConvertFromMUtf8)699 TEST_F(EtsStringTest, ConvertFromMUtf8)
700 {
701 std::vector<uint8_t> data {'a', 0xc0, 0x80, 'b', 0xe2, 0x82, 0xac, 'z', '\n'};
702 size_t strLen = 6U;
703 auto *utf8Data = reinterpret_cast<const char *>(data.data());
704 EtsString *str = EtsString::CreateFromMUtf8(utf8Data, strLen);
705 CheckConvertString(str);
706 }
707
708 } // namespace ark::ets::test
709
710 // NOLINTEND(readability-magic-numbers)
711