diff --git a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp index 5f57df150365b44a5392ff6d731a63eefd63c632..a7f8980c2ebe03d686c5273648eb2fb805669547 100644 --- a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp +++ b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp @@ -56,6 +56,8 @@ napi_add_env_cleanup_hook([[maybe_unused]] napi_env env, [[maybe_unused]] void ( INTEROP_LOG(ERROR) << "napi_add_env_cleanup_hook is implemented in OHOS since 4.1.0, please update" << std::endl; return napi_ok; } +extern "C" napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style +napi_get_last_error_info(napi_env env, const napi_extended_error_info **result); #endif #endif // ARK_HYBRID @@ -566,6 +568,14 @@ void InteropCtx::ThrowJSValue(napi_env env, napi_value val) #endif } +void InteropCtx::ThrowJSLastError(napi_env env) +{ + const napi_extended_error_info *info = NULL; + NAPI_CHECK_FATAL(napi_get_last_error_info(env, &info)); + ASSERT(info != NULL); + ThrowJSError(env, info->error_message); +} + void InteropCtx::InitializeDefaultLinkerCtxIfNeeded(EtsRuntimeLinker *linker) { os::memory::LockHolder lock(InteropCtx::SharedEtsVmState::mutex_); @@ -615,6 +625,12 @@ void InteropCtx::ForwardEtsException(EtsCoroutine *coro) ThrowJSValue(env, res); } +void InteropCtx::ForwardJSLastError(EtsCoroutine *coro) +{ + ThrowJSLastError(GetJSEnv()); + ForwardJSException(coro); +} + void InteropCtx::ForwardJSException(EtsCoroutine *coro) { auto env = GetJSEnv(); diff --git a/static_core/plugins/ets/runtime/interop_js/interop_context.h b/static_core/plugins/ets/runtime/interop_js/interop_context.h index de28f57a5cc9eed3faaf8a244cb90db6028262ab..a5606777d929bfe2ede7fc7b93c5e58de31d18da 100644 --- a/static_core/plugins/ets/runtime/interop_js/interop_context.h +++ b/static_core/plugins/ets/runtime/interop_js/interop_context.h @@ -430,12 +430,14 @@ public: PANDA_PUBLIC_API static void ThrowJSError(napi_env env, const std::string &msg); static void ThrowJSTypeError(napi_env env, const std::string &msg); static void ThrowJSValue(napi_env env, napi_value val); + static void ThrowJSLastError(napi_env env); static void InitializeDefaultLinkerCtxIfNeeded(EtsRuntimeLinker *linker); static void SetDefaultLinkerContext(EtsRuntimeLinker *linker); void ForwardEtsException(EtsCoroutine *coro); void ForwardJSException(EtsCoroutine *coro); + void ForwardJSLastError(EtsCoroutine *coro); [[nodiscard]] static bool SanityETSExceptionPending() { @@ -555,21 +557,11 @@ private: // Intentionally leaving these members public to avoid duplicating the InteropCtx's accessors. // Maybe its worth to add some e.g. VmState() method to the InteropCtx and move all its accessors here - Class *jsRuntimeClass {}; - Class *jsValueClass {}; - Class *esErrorClass {}; - Class *objectClass {}; - Class *stringClass {}; - Class *bigintClass {}; - Class *arrayAsListIntClass {}; - Class *nullValueClass {}; - Class *promiseClass {}; - Class *errorClass {}; - Class *exceptionClass {}; - Class *typeClass {}; - Class *arrayClass {}; - Class *boxIntClass {}; - Class *boxLongClass {}; + Class *jsRuntimeClass {}, *jsValueClass {}, *esErrorClass {}, *objectClass {}, *stringClass {}, *bigintClass {}; + Class *arrayAsListIntClass {}, *arrayClass {}, *nullValueClass {}; + Class *promiseClass {}, *errorClass {}, *exceptionClass {}; + Class *typeClass {}, *boxIntClass {}, *boxLongClass {}; + PandaSet functionalInterfaces {}; Method *promiseInteropConnectMethod = nullptr; PandaEtsVM *pandaEtsVm = nullptr; diff --git a/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp b/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp index 4f468e9c5ad67be7b506a1f2d86354353f811f81..fe457ac33cbbdfe28f684fccf6232abf64a6b182 100644 --- a/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp +++ b/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp @@ -24,6 +24,7 @@ #include "plugins/ets/runtime/types/ets_string.h" #include "runtime/include/class_linker-inl.h" #include "runtime/coroutines/stackful_coroutine.h" +#include // NOLINTBEGIN(readability-identifier-naming) // CC-OFFNXT(G.FMT.10-CPP) project code style @@ -510,9 +511,17 @@ uint8_t JSRuntimeHasProperty(JSValue *object, EtsString *name) auto env = ctx->GetJSEnv(); NapiScope jsHandleScope(env); + napi_status jsStatus; bool result = false; - NAPI_CHECK_FATAL(napi_has_property(env, JSConvertJSValue::WrapWithNullCheck(env, object), - JSConvertString::WrapWithNullCheck(env, name), &result)); + jsStatus = napi_has_property(env, JSConvertJSValue::WrapWithNullCheck(env, object), + JSConvertString::WrapWithNullCheck(env, name), &result); + if (jsStatus != napi_ok) { + if (jsStatus == napi_pending_exception) { + NAPI_CHECK_FATAL(jsStatus); + } else { + ctx->ForwardJSLastError(coro); + } + } return static_cast(result); } @@ -663,7 +672,11 @@ EtsObject *InvokeWithObjectReturn(JSValue *thisObj, JSValue *func, SpanForwardJSException(coro); + if (jsStatus == napi_pending_exception) { + ctx->ForwardJSException(coro); + } else { + ctx->ForwardJSLastError(coro); + } return nullptr; } return JSConvertEtsObject::UnwrapWithNullCheck(ctx, env, retVal).value(); @@ -704,9 +717,17 @@ uint8_t JSRuntimeHasOwnProperty(JSValue *object, EtsString *name) auto env = ctx->GetJSEnv(); NapiScope jsHandleScope(env); + napi_status jsStatus; bool result = false; - NAPI_CHECK_FATAL(napi_has_own_property(env, JSConvertJSValue::WrapWithNullCheck(env, object), - JSConvertString::WrapWithNullCheck(env, name), &result)); + jsStatus = napi_has_own_property(env, JSConvertJSValue::WrapWithNullCheck(env, object), + JSConvertString::WrapWithNullCheck(env, name), &result); + if (jsStatus != napi_ok) { + if (jsStatus == napi_pending_exception) { + NAPI_CHECK_FATAL(jsStatus); + } else { + ctx->ForwardJSLastError(coro); + } + } return static_cast(result); } @@ -788,10 +809,17 @@ JSValue *JSRuntimeInvoke(JSValue *recv, JSValue *func, EtsArray *args) } if (jsStatus != napi_ok) { - ctx->ForwardJSException(coro); + if (jsStatus == napi_pending_exception) { + ctx->ForwardJSException(coro); + } else { + ctx->ForwardJSLastError(coro); + } return nullptr; } - return JSConvertJSValue::UnwrapWithNullCheck(ctx, env, retVal).value(); + if (IsUndefined(env, retVal)) { + return JSValue::CreateUndefined(coro, ctx); + } + return JSConvertJSValue::Unwrap(ctx, env, retVal).value(); } JSValue *JSRuntimeInstantiate(JSValue *callable, EtsArray *args) @@ -826,10 +854,17 @@ JSValue *JSRuntimeInstantiate(JSValue *callable, EtsArray *args) } if (jsStatus != napi_ok) { - ctx->ForwardJSException(coro); + if (jsStatus == napi_pending_exception) { + ctx->ForwardJSException(coro); + } else { + ctx->ForwardJSLastError(coro); + } return nullptr; } - return JSConvertJSValue::UnwrapWithNullCheck(ctx, env, retVal).value(); + if (IsUndefined(env, retVal)) { + return JSValue::CreateUndefined(coro, ctx); + } + return JSConvertJSValue::Unwrap(ctx, env, retVal).value(); } EtsObject *CreateObject(JSValue *ctor, Span> args) diff --git a/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.h b/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.h index bf2815bb9df9efdb263d0f2b29e9e8037d5d38ed..98cfdc30f045ec5f17c403040fff8355ae9e8a2a 100644 --- a/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.h +++ b/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.h @@ -150,14 +150,15 @@ typename T::cpptype JSValueIndexedGetter(JSValue *etsJsValue, int64_t index) napi_value result; napi_value jsVal = etsJsValue->GetNapiValue(env); - + napi_status jsStatus; { ScopedNativeCodeThread nativeScope(coro); - auto rc = napi_get_element(env, jsVal, index, &result); - if (UNLIKELY(NapiThrownGeneric(rc))) { - ctx->ForwardJSException(coro); - return {}; - } + jsStatus = napi_get_element(env, jsVal, index, &result); + } + + if (jsStatus != napi_ok) { + ctx->ForwardJSLastError(coro); + return {}; } auto res = T::UnwrapWithNullCheck(ctx, env, result); @@ -177,11 +178,15 @@ void JSValueIndexedSetter(JSValue *etsJsValue, int32_t index, typename T::cpptyp INTEROP_CODE_SCOPE_ETS(coro); auto env = ctx->GetJSEnv(); NapiScope jsHandleScope(env); + napi_status jsStatus; + { + ScopedNativeCodeThread nativeScope(coro); + jsStatus = napi_set_element(env, JSConvertJSValue::WrapWithNullCheck(env, etsJsValue), index, + T::WrapWithNullCheck(env, value)); + } - auto rec = napi_set_element(env, JSConvertJSValue::WrapWithNullCheck(env, etsJsValue), index, - T::WrapWithNullCheck(env, value)); - if (rec != napi_ok) { - ctx->ForwardJSException(coro); + if (jsStatus != napi_ok) { + ctx->ForwardJSLastError(coro); } } diff --git a/static_core/plugins/ets/runtime/interop_js/js_convert.h b/static_core/plugins/ets/runtime/interop_js/js_convert.h index b6bc83398c70f1b0a70fa6ae4095ac0105d701ab..e17cd2538309b45e20b3ba8017795a02d8cdbd24 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_convert.h +++ b/static_core/plugins/ets/runtime/interop_js/js_convert.h @@ -410,10 +410,11 @@ ALWAYS_INLINE inline std::optional JSValueGetByName(Interop auto env = ctx->GetJSEnv(); napi_value jsVal = jsvalue->GetNapiValue(env); { - ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); - // No access to jsvalue after this line + auto coro = EtsCoroutine::GetCurrent(); + ScopedNativeCodeThread nativeScope(coro); napi_status rc = napi_get_named_property(env, jsVal, name, &jsVal); - if (UNLIKELY(rc == napi_pending_exception || NapiThrownGeneric(rc))) { + if (rc != napi_ok) { + InteropCtx::ThrowJSLastError(env); return {}; } } @@ -430,10 +431,14 @@ template if (UNLIKELY(jsPropVal == nullptr)) { return false; } - ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); - // No access to jsvalue after this line + auto coro = EtsCoroutine::GetCurrent(); + ScopedNativeCodeThread nativeScope(coro); napi_status rc = napi_set_named_property(env, jsVal, name, jsPropVal); - return rc != napi_pending_exception && !NapiThrownGeneric(rc); + if (rc != napi_ok) { + InteropCtx::ThrowJSLastError(env); + return false; + } + return true; } } // namespace ark::ets::interop::js diff --git a/static_core/plugins/ets/stdlib/std/interop/ESValue.ets b/static_core/plugins/ets/stdlib/std/interop/ESValue.ets index ebc7d9d45f8334041583236f2d409bfd91e29c78..4aa0d2cdbe1f8ce5fb3665756ca24e5b8dd8c015 100644 --- a/static_core/plugins/ets/stdlib/std/interop/ESValue.ets +++ b/static_core/plugins/ets/stdlib/std/interop/ESValue.ets @@ -163,18 +163,30 @@ export final class ESValue { } public toBoolean(): boolean { + if (!this.isBoolean()) { + throw new TypeError("Boolaen expected"); + } return JSRuntime.getValueBoolean(this.ev); } public toString(): string { + if (!this.isString()) { + throw new TypeError("String expected"); + } return JSRuntime.getValueString(this.ev); } public toNumber(): number { + if (!this.isNumber()) { + throw new TypeError("Number expected"); + } return JSRuntime.getValueDouble(this.ev); } public toBigInt(): bigint { + if (!this.isBigInt()) { + throw new TypeError("bigint expected"); + } return JSRuntime.getValueObject(this.ev, Class.of(new bigint())) as bigint; } @@ -441,6 +453,9 @@ export final class ESValue { } public toPromise(): Promise { + if (!this.isPromise()) { + throw new TypeError("Promise expected"); + } const callerClass = Class.ofCaller(); const linker = callerClass == undefined ? getBootRuntimeLinker() : callerClass.getLinker(); let clsName = 'std.core.Promise'; diff --git a/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/CMakeLists.txt b/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..3fcca1246bfcade7ab07e942cf56859133d8cb1c --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/CMakeLists.txt @@ -0,0 +1,14 @@ +# 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. + +add_subdirectory(ts_to_ets) \ No newline at end of file diff --git a/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/CMakeLists.txt b/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..3a4eb91f76be22e53a8dc92f9c7cbeb1ef90962b --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/CMakeLists.txt @@ -0,0 +1,18 @@ +# 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. + +panda_ets_interop_js_gtest(ets_interop_js__invopesval_ts_to_ets + CPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/invalid_op_esvalue_test.cpp + ETS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/invalid_op_esvalue_test.ets + JS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_invalid_op_esvalue.ts +) \ No newline at end of file diff --git a/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/invalid_op_esvalue_test.cpp b/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/invalid_op_esvalue_test.cpp new file mode 100755 index 0000000000000000000000000000000000000000..76001a8dbec03f4e8ef9aa9c4a04c61f7c2603a1 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/invalid_op_esvalue_test.cpp @@ -0,0 +1,87 @@ +/** + * 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 +#include "ets_interop_js_gtest.h" + +namespace ark::ets::interop::js::testing { + +class InvalidOpESValTsToEtsTest : public EtsInteropTest {}; + +TEST_F(InvalidOpESValTsToEtsTest, checkInvokeTestValue) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkInvokeTestValue")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkIntGetProperty) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkIntGetProperty")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkIntGetIndex) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkIntGetIndex")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkIntInvoke) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkIntInvoke")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkIntSetProperty) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkIntSetProperty")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkIntSetIndex) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkIntSetIndex")); +} +TEST_F(InvalidOpESValTsToEtsTest, checkWrapNullToNumber) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkWrapNullToNumber")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkWrapIntToString) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkWrapIntToString")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkWrapIntToBoolean) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkWrapIntToBoolean")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkWrapIntToBigInt) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkWrapIntToBigInt")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkWrapIntToPromise) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkWrapIntToPromise")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkWrapIntHasProperty) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkWrapIntHasProperty")); +} + +TEST_F(InvalidOpESValTsToEtsTest, checkWrapIntHasOwnProperty) +{ + ASSERT_EQ(true, CallEtsFunction(GetPackageName(), "checkWrapIntHasOwnProperty")); +} + +} // namespace ark::ets::interop::js::testing \ No newline at end of file diff --git a/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/invalid_op_esvalue_test.ets b/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/invalid_op_esvalue_test.ets new file mode 100755 index 0000000000000000000000000000000000000000..9f461f0b525498df50f05fd6a94e8dd3935a7e50 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/invalid_op_esvalue_test.ets @@ -0,0 +1,149 @@ +/** + * 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. + */ + +let module = ESValue.load('../../plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/test_invalid_op_esvalue'); + +function checkInvokeTestValue(): boolean { + let res: boolean = false; + try { + let jsCls = module.getProperty("Base"); + let jsClsIns = jsCls.instantiate(); + let jsCls1 = jsClsIns.getProperty("getBase").invoke(); + jsCls1.getProperty("baseVal").toNumber(); + } catch (e: Error) { + res = e.message === 'Need object'; + } + return res; +} + +function checkIntGetProperty(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).getProperty('123'); + } catch (e: Error) { + res = e.message === 'Need object'; + } + return res; +} + +function checkIntGetIndex(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).getProperty(1); + } catch (e: Error) { + res = e.message === 'Need object'; + } + return res; +} + +function checkIntInvoke(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).invoke(); + } catch (e: Error) { + res = e.message === 'Need function'; + } + return res; +} + +function checkIntSetProperty(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).setProperty('ID', ESValue.wrapInt(456)); + } catch (e: Error) { + res = e.message === 'Need object'; + } + return res; +} + +function checkIntSetIndex(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).setProperty(1, ESValue.wrapInt(456)); + } catch (e: Error) { + res = e.message === 'Need object'; + } + return res; +} + +function checkWrapNullToNumber(): boolean { + let res: boolean = false; + try { + ESValue.wrap(null).toNumber(); + } catch (e: Error) { + res = e.message === 'Number expected'; + } + return res; +} + +function checkWrapIntToString(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).toString(); + } catch (e: Error) { + res = e.message === 'String expected'; + } + return res; +} + +function checkWrapIntToBoolean(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).toBoolean(); + } catch (e: Error) { + res = e.message === 'Boolaen expected'; + } + return res; +} + +function checkWrapIntToBigInt(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).toBigInt(); + } catch (e: Error) { + res = e.message === 'bigint expected'; + } + return res; +} + +function checkWrapIntToPromise(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).toPromise(); + } catch (e: Error) { + res = e.message === 'Promise expected'; + } + return res; +} + +function checkWrapIntHasProperty(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).hasProperty('foo'); + } catch (e: Error) { + res = e.message === 'Need object'; + } + return res; +} + +function checkWrapIntHasOwnProperty(): boolean { + let res: boolean = false; + try { + ESValue.wrapInt(123).hasOwnProperty('foo'); + } catch (e: Error) { + res = e.message === 'Need object'; + } + return res; +} \ No newline at end of file diff --git a/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/test_invalid_op_esvalue.ts b/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/test_invalid_op_esvalue.ts new file mode 100755 index 0000000000000000000000000000000000000000..989ffe66fb7cd9e1fd899b50ce15915b45bb0f21 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/tests/invalid_op_esvalue/ts_to_ets/test_invalid_op_esvalue.ts @@ -0,0 +1,21 @@ +/** + * 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. + */ + +export class Base { + baseVal: number = 1; + getBase(): Base { + return this + } +} \ No newline at end of file