* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/ecma_string.h"
#include "ecmascript/ecma_string-inl.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tests/ecma_test_common.h"
using namespace panda::ecmascript;
namespace panda::test {
class EcmaExternalStringTest : public BaseTestWithScope<false> {
public:
static constexpr uint32_t TYPE_INFO_SIZE = 4;
static constexpr uint32_t UTF8_CACHED_DATA_SIZE = 4;
static constexpr uint32_t UTF16_CACHED_DATA_SIZE = 8;
static constexpr uint32_t UTF16_STRING_LENGTH = UTF16_CACHED_DATA_SIZE / sizeof(uint16_t);
static inline void CallBackFn([[maybe_unused]] void *data, void *hint)
{
free(hint);
}
};
* @tc.name: CachedExternalEcmaStringCastTest
* @tc.desc: Test base functions in class CachedExternalEcmaString
* @tc.type: FUNC
*/
HWTEST_F_L0(EcmaExternalStringTest, CachedExternalEcmaStringBaseTestUtf8)
{
uint8_t *hint = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF8_CACHED_DATA_SIZE);
uint8_t *cachedData = hint + TYPE_INFO_SIZE;
memset_s(cachedData, UTF8_CACHED_DATA_SIZE, 'a', UTF8_CACHED_DATA_SIZE);
EcmaString *ecmaString = EcmaStringAccessor::CreateFromExternalResource(
instance, cachedData, UTF8_CACHED_DATA_SIZE, true, EcmaExternalStringTest::CallBackFn, hint);
JSHandle<EcmaString> ecmaStrHandle(thread, ecmaString);
CachedExternalEcmaString *cachedEcmaString = CachedExternalEcmaString::Cast(ecmaString);
EXPECT_NE(cachedEcmaString, nullptr);
EXPECT_NE(CachedExternalEcmaString::Cast(*ecmaStrHandle), nullptr);
EXPECT_NE(CachedExternalEcmaString::ConstCast(*ecmaStrHandle), nullptr);
EXPECT_NE(CachedExternalEcmaString::Cast(ecmaStrHandle.GetTaggedValue()), nullptr);
EXPECT_NE(cachedEcmaString, nullptr);
EXPECT_NE(CachedExternalEcmaString::Cast(const_cast<EcmaString *>(ecmaString)), nullptr);
CachedExternalString *cachedExternalString = cachedEcmaString->ToCachedExternalString();
EXPECT_NE(cachedExternalString, nullptr);
const CachedExternalString *constCachedExternalString = cachedEcmaString->ToCachedExternalString();
EXPECT_NE(constCachedExternalString, nullptr);
EXPECT_NE(CachedExternalEcmaString::FromBaseString(cachedExternalString), nullptr);
}
* @tc.name: CachedExternalEcmaStringBaseTestUtf16
* @tc.desc: Test the basic interfaces in class CachedExternalString while input utf16 data
* @tc.type: FUNC
*/
HWTEST_F_L0(EcmaExternalStringTest, CachedExternalEcmaStringBaseTestUtf16)
{
uint8_t *hint = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF16_CACHED_DATA_SIZE);
uint8_t *cachedData = hint + TYPE_INFO_SIZE;
memset_s(cachedData, UTF16_CACHED_DATA_SIZE, 0xff, UTF16_CACHED_DATA_SIZE);
EcmaString *ecmaString = EcmaStringAccessor::CreateFromExternalResource(
instance, cachedData, UTF16_STRING_LENGTH, false, EcmaExternalStringTest::CallBackFn, hint);
CachedExternalString *cachedExternalString = CachedExternalEcmaString::Cast(ecmaString)->ToCachedExternalString();
EXPECT_EQ(cachedExternalString->Get(0), 0xffff);
}
* @tc.name: CreateFromExternalResourceTest
* @tc.desc: Test a function that create ECMA string from external resource
* @tc.type: FUNC
*/
HWTEST_F_L0(EcmaExternalStringTest, CreateFromExternalResourceTest)
{
uint8_t *hint = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF8_CACHED_DATA_SIZE);
uint8_t *cachedData = hint + TYPE_INFO_SIZE;
memset_s(cachedData, UTF8_CACHED_DATA_SIZE, 'a', UTF8_CACHED_DATA_SIZE);
EcmaString *ecmaString = EcmaStringAccessor::CreateFromExternalResource(
instance, cachedData, UTF8_CACHED_DATA_SIZE, true, EcmaExternalStringTest::CallBackFn, hint);
EcmaStringAccessor strAcc(ecmaString);
EXPECT_TRUE(strAcc.IsCachedExternalString());
EXPECT_TRUE(strAcc.IsLineOrCachedExternalString());
EXPECT_EQ(strAcc.GetLength(), UTF8_CACHED_DATA_SIZE);
EXPECT_STREQ(EcmaStringAccessor(ecmaString).ToCString(thread).c_str(), "aaaa");
}
* @tc.name: GetNonTreeUtf8DataTest
* @tc.desc: Test function EcmaStringAccessor::GetNonTreeUtf8Data
* @tc.type: FUNC
*/
HWTEST_F_L0(EcmaExternalStringTest, GetNonTreeUtf8DataTest)
{
uint8_t *hint = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF8_CACHED_DATA_SIZE);
uint8_t *cachedData = hint + TYPE_INFO_SIZE;
memset_s(cachedData, UTF8_CACHED_DATA_SIZE, 'a', UTF8_CACHED_DATA_SIZE);
EcmaString *ecmaStr = EcmaStringAccessor::CreateFromUtf8(instance, cachedData, UTF8_CACHED_DATA_SIZE, true);
const uint8_t *lineStrData = EcmaStringAccessor::GetNonTreeUtf8Data(thread, ecmaStr);
EXPECT_EQ(lineStrData[0], 'a');
ecmaStr = EcmaStringAccessor::CreateFromExternalResource(instance, cachedData, UTF8_CACHED_DATA_SIZE, true,
EcmaExternalStringTest::CallBackFn, hint);
const uint8_t *externalStrData = EcmaStringAccessor::GetNonTreeUtf8Data(thread, ecmaStr);
EXPECT_EQ(externalStrData[0], 'a');
EXPECT_EQ(externalStrData, cachedData);
}
* @tc.name: GetNonTreeUtf16DataTest
* @tc.desc: Test function EcmaStringAccessor::GetNonTreeUtf16DataTest
* @tc.type: FUNC
*/
HWTEST_F_L0(EcmaExternalStringTest, GetNonTreeUtf16DataTest)
{
uint8_t *hint = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF16_CACHED_DATA_SIZE);
uint16_t *cachedData = reinterpret_cast<uint16_t *>(hint + TYPE_INFO_SIZE);
memset_s(cachedData, UTF16_CACHED_DATA_SIZE, 0xff, UTF16_CACHED_DATA_SIZE);
EcmaString *ecmaStr = EcmaStringAccessor::CreateFromUtf16(instance, cachedData, UTF16_STRING_LENGTH, false);
const uint16_t *lineStrData = EcmaStringAccessor::GetNonTreeUtf16Data(thread, ecmaStr);
EXPECT_EQ(lineStrData[0], 0xffff);
ecmaStr = EcmaStringAccessor::CreateFromExternalResource(instance, cachedData, UTF16_STRING_LENGTH, false,
EcmaExternalStringTest::CallBackFn, hint);
const uint16_t *externalStrData = EcmaStringAccessor::GetNonTreeUtf16Data(thread, ecmaStr);
EXPECT_EQ(externalStrData, cachedData);
EXPECT_EQ(externalStrData[0], 0xffff);
}
* @tc.name: GetUtf16DataFlatTest
* @tc.desc: Test function EcmaStringAccessor::GetUtf16DataFlat
* @tc.type: FUNC
*/
HWTEST_F_L0(EcmaExternalStringTest, GetUtf16DataFlatTest)
{
uint8_t *hint = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF16_CACHED_DATA_SIZE);
uint16_t *cachedData = reinterpret_cast<uint16_t *>(hint + TYPE_INFO_SIZE);
memset_s(cachedData, UTF16_CACHED_DATA_SIZE, 0xff, UTF16_CACHED_DATA_SIZE);
EcmaString *ecmaStr = EcmaStringAccessor::CreateFromUtf16(instance, cachedData, UTF16_STRING_LENGTH, false);
CVector<uint16_t> utf16Buf1;
const uint16_t *lineStrData = EcmaStringAccessor::GetUtf16DataFlat(thread, ecmaStr, utf16Buf1);
EXPECT_EQ(lineStrData[0], 0xffff);
ecmaStr = EcmaStringAccessor::CreateFromExternalResource(instance, cachedData, UTF16_STRING_LENGTH, false,
EcmaExternalStringTest::CallBackFn, hint);
CVector<uint16_t> utf16Buf2;
const uint16_t *externalStrData = EcmaStringAccessor::GetUtf16DataFlat(thread, ecmaStr, utf16Buf2);
EXPECT_EQ(externalStrData, cachedData);
EXPECT_EQ(externalStrData[0], 0xffff);
}
* @tc.name: GetUtf8DataFlatTest
* @tc.desc: Test function EcmaStringAccessor::GetUtf8DataFlat
* @tc.type: FUNC
*/
HWTEST_F_L0(EcmaExternalStringTest, GetUtf8DataFlatTest)
{
uint8_t *hint = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF8_CACHED_DATA_SIZE);
uint8_t *cachedData = hint + TYPE_INFO_SIZE;
memset_s(cachedData, UTF8_CACHED_DATA_SIZE, 'a', UTF8_CACHED_DATA_SIZE);
EcmaString *ecmaStr = EcmaStringAccessor::CreateFromUtf8(instance, cachedData, UTF8_CACHED_DATA_SIZE, true);
CVector<uint8_t> utf8Buf1;
const uint8_t *lineStrData = EcmaStringAccessor::GetUtf8DataFlat(thread, ecmaStr, utf8Buf1);
EXPECT_EQ(lineStrData[0], 'a');
ecmaStr = EcmaStringAccessor::CreateFromExternalResource(instance, cachedData, UTF8_CACHED_DATA_SIZE, true,
EcmaExternalStringTest::CallBackFn, hint);
CVector<uint8_t> utf8Buf2;
const uint8_t *externalStrData = EcmaStringAccessor::GetUtf8DataFlat(thread, ecmaStr, utf8Buf2);
EXPECT_EQ(externalStrData[0], 'a');
EXPECT_EQ(externalStrData, cachedData);
}
* @tc.name: AtTest
* @tc.desc: Test function EcmaString::At
* @tc.type: FUNC
*/
HWTEST_F_L0(EcmaExternalStringTest, AtTest)
{
uint8_t *hint = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF8_CACHED_DATA_SIZE);
uint8_t *cachedData = hint + TYPE_INFO_SIZE;
memset_s(cachedData, UTF8_CACHED_DATA_SIZE, 'a', UTF8_CACHED_DATA_SIZE);
EcmaString *ecmaString = EcmaStringAccessor::CreateFromExternalResource(
instance, cachedData, UTF8_CACHED_DATA_SIZE, true, EcmaExternalStringTest::CallBackFn, hint);
EcmaStringAccessor strAcc(ecmaString);
EXPECT_EQ(strAcc.Get(thread, 0), 'a');
}
* @tc.name: WriteToFlatTest
* @tc.desc: Test function EcmaString::WriteToFlat
* @tc.type: FUNC
*/
HWTEST_F_L0(EcmaExternalStringTest, WriteToFlatTest)
{
uint8_t *hint = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF8_CACHED_DATA_SIZE);
uint8_t *cachedData = hint + TYPE_INFO_SIZE;
memset_s(cachedData, UTF8_CACHED_DATA_SIZE, 'a', UTF8_CACHED_DATA_SIZE);
EcmaString *ecmaString = EcmaStringAccessor::CreateFromExternalResource(
instance, cachedData, UTF8_CACHED_DATA_SIZE, true, EcmaExternalStringTest::CallBackFn, hint);
char *buf = (char *)malloc(UTF8_CACHED_DATA_SIZE);
EcmaStringAccessor::WriteToFlat(thread, ecmaString, buf, UTF8_CACHED_DATA_SIZE);
EXPECT_EQ(buf[0], 'a');
free(buf);
uint8_t *hintForUtf16 = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF16_CACHED_DATA_SIZE);
uint8_t *cachedDataForUtf16 = hintForUtf16 + TYPE_INFO_SIZE;
memset_s(cachedDataForUtf16, UTF16_CACHED_DATA_SIZE, 'a', UTF16_CACHED_DATA_SIZE);
EcmaString *ecmaStrUft16 = EcmaStringAccessor::CreateFromExternalResource(
instance, cachedDataForUtf16, UTF16_STRING_LENGTH, true, EcmaExternalStringTest::CallBackFn, hintForUtf16);
char *bufForUtf16 = (char *)malloc(UTF16_CACHED_DATA_SIZE);
EcmaStringAccessor::WriteToFlat(thread, ecmaStrUft16, bufForUtf16, UTF16_STRING_LENGTH);
EXPECT_EQ(bufForUtf16[0], 'a');
free(bufForUtf16);
}
* @tc.name: WriteToFlatWithPosTest
* @tc.desc: Test function EcmaString::WriteToFlatWithPos
* @tc.type: FUNC
*/
HWTEST_F_L0(EcmaExternalStringTest, WriteToFlatWithPosTest)
{
uint8_t *hint = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF8_CACHED_DATA_SIZE);
uint8_t *cachedData = hint + TYPE_INFO_SIZE;
memset_s(cachedData, UTF8_CACHED_DATA_SIZE, 'a', UTF8_CACHED_DATA_SIZE);
EcmaString *ecmaString = EcmaStringAccessor::CreateFromExternalResource(
instance, cachedData, UTF8_CACHED_DATA_SIZE, true, EcmaExternalStringTest::CallBackFn, hint);
char *buf = (char *)malloc(UTF8_CACHED_DATA_SIZE);
EcmaStringAccessor::WriteToFlatWithPos(thread, ecmaString, buf, UTF8_CACHED_DATA_SIZE, 0);
EXPECT_EQ(buf[0], 'a');
free(buf);
uint8_t *hintForUtf16 = (uint8_t *)std::malloc(TYPE_INFO_SIZE + UTF16_CACHED_DATA_SIZE);
uint8_t *cachedDataForUtf16 = hintForUtf16 + TYPE_INFO_SIZE;
memset_s(cachedDataForUtf16, UTF16_CACHED_DATA_SIZE, 'a', UTF16_CACHED_DATA_SIZE);
EcmaString *ecmaStrUft16 = EcmaStringAccessor::CreateFromExternalResource(
instance, cachedDataForUtf16, UTF16_STRING_LENGTH, true, EcmaExternalStringTest::CallBackFn, hintForUtf16);
char *bufForUtf16 = (char *)malloc(UTF16_CACHED_DATA_SIZE);
EcmaStringAccessor::WriteToFlatWithPos(thread, ecmaStrUft16, bufForUtf16, UTF16_STRING_LENGTH, 0);
EXPECT_EQ(bufForUtf16[0], 'a');
free(bufForUtf16);
}
}