• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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