1/*
2 * Copyright (c) 2021-2024 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 "ecmascript/base/builtins_base.h"
17#include "ecmascript/ecma_runtime_call_info.h"
18#include "ecmascript/ecma_string.h"
19#include "ecmascript/ecma_vm.h"
20#include "ecmascript/global_env.h"
21#include "ecmascript/interpreter/interpreter.h"
22#include "ecmascript/js_function.h"
23#include "ecmascript/js_handle.h"
24#include "ecmascript/js_hclass.h"
25#include "ecmascript/js_object-inl.h"
26#include "ecmascript/js_proxy.h"
27#include "ecmascript/js_tagged_value-inl.h"
28#include "ecmascript/object_factory.h"
29#include "ecmascript/tests/test_helper.h"
30
31using namespace panda::ecmascript;
32using namespace panda::ecmascript::base;
33
34namespace panda::test {
35class JSProxyTest : public BaseTestWithScope<false> {
36};
37
38static JSFunction *JSObjectTestCreate(JSThread *thread)
39{
40    EcmaVM *ecmaVM = thread->GetEcmaVM();
41    JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
42    return globalEnv->GetObjectFunction().GetObject<JSFunction>();
43}
44
45HWTEST_F_L0(JSProxyTest, ProxyCreate)
46{
47    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
48    JSHandle<JSTaggedValue> targetHandle(
49        thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(hclass), hclass));
50
51    JSHandle<JSTaggedValue> key(thread->GetEcmaVM()->GetFactory()->NewFromASCII("x"));
52    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(1));
53    JSObject::SetProperty(thread, targetHandle, key, value);
54    EXPECT_EQ(JSObject::GetProperty(thread, targetHandle, key).GetValue()->GetInt(), 1);
55
56    JSHandle<JSTaggedValue> handlerHandle(
57        thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(hclass), hclass));
58    EXPECT_TRUE(handlerHandle->IsECMAObject());
59
60    JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
61    EXPECT_TRUE(*proxyHandle != nullptr);
62
63    EXPECT_EQ(JSProxy::GetProperty(thread, proxyHandle, key).GetValue()->GetInt(), 1);
64    PropertyDescriptor desc(thread);
65    JSProxy::GetOwnProperty(thread, proxyHandle, key, desc);
66    EXPECT_EQ(desc.GetValue()->GetInt(), 1);
67}
68
69JSHandle<JSProxy> SetPropertyCommon(JSThread *thread, JSHandle<JSTaggedValue>& targetHandle,
70    JSHandle<JSTaggedValue>& handlerHandle, JSHandle<JSTaggedValue>& key, JSHandle<JSTaggedValue>& value)
71{
72    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
73    // 1. handler has no "get"
74    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
75    targetHandle = JSHandle<JSTaggedValue>(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
76    EXPECT_TRUE(targetHandle->IsECMAObject());
77    JSObject::SetProperty(thread, targetHandle, key, value);
78    EXPECT_EQ(JSObject::GetProperty(thread, targetHandle, key).GetValue()->GetInt(), 1);
79
80    handlerHandle = JSHandle<JSTaggedValue>(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
81    EXPECT_TRUE(handlerHandle->IsECMAObject());
82
83    JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
84    return proxyHandle;
85}
86
87// ES6 9.5.8 [[Get]] (P, Receiver)
88// Called by the following function
89JSTaggedValue HandlerGetProperty([[maybe_unused]] EcmaRuntimeCallInfo *argv)
90{
91    return JSTaggedValue(10); // 10 : test case
92}
93
94HWTEST_F_L0(JSProxyTest, GetProperty)
95{
96    JSHandle<JSTaggedValue> targetHandle;
97    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
98    JSHandle<JSTaggedValue> key(factory->NewFromASCII("x"));
99    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(1));
100    JSHandle<JSTaggedValue> handlerHandle;
101    JSHandle<JSProxy> proxyHandle = SetPropertyCommon(thread, targetHandle, handlerHandle, key, value);
102    EXPECT_TRUE(*proxyHandle != nullptr);
103
104    EXPECT_EQ(JSProxy::GetProperty(thread, proxyHandle, key).GetValue()->GetInt(), 1);
105
106    // 2. handler has "get"
107    EcmaVM *vm = thread->GetEcmaVM();
108    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
109    JSHandle<JSTaggedValue> getKey = thread->GlobalConstants()->GetHandledGetString();
110    JSHandle<JSTaggedValue> getHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerGetProperty)));
111    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), getKey, getHandle);
112
113    JSHandle<JSProxy> proxyHandle2(JSProxy::ProxyCreate(thread, targetHandle, handlerHandle));
114    EXPECT_TRUE(*proxyHandle2 != nullptr);
115    JSHandle<JSTaggedValue> key2(factory->NewFromASCII("y"));
116    EXPECT_EQ(JSProxy::GetProperty(thread, proxyHandle2, key2).GetValue()->GetInt(), 10);
117}
118
119// ES6 9.5.5 [[GetOwnProperty]] (P)
120// Called by the following function
121JSTaggedValue HandlerGetOwnProperty([[maybe_unused]] EcmaRuntimeCallInfo *argv)
122{
123    return JSTaggedValue(JSTaggedValue::Undefined());
124}
125
126HWTEST_F_L0(JSProxyTest, GetOwnProperty)
127{
128    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
129    JSHandle<JSTaggedValue> targetHandle;
130    JSHandle<JSTaggedValue> handlerHandle;
131    JSHandle<JSTaggedValue> key(factory->NewFromASCII("x"));
132    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(1));
133    JSHandle<JSProxy> proxyHandle = SetPropertyCommon(thread, targetHandle, handlerHandle, key, value);
134    EXPECT_TRUE(*proxyHandle != nullptr);
135
136    PropertyDescriptor desc(thread);
137    JSProxy::GetOwnProperty(thread, proxyHandle, key, desc);
138    EXPECT_EQ(desc.GetValue()->GetInt(), 1);
139
140    // 2. handler has "get"
141    EcmaVM *vm = thread->GetEcmaVM();
142    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
143    JSHandle<JSTaggedValue> defineKey = thread->GlobalConstants()->GetHandledGetOwnPropertyDescriptorString();
144    JSHandle<JSTaggedValue> defineHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerGetOwnProperty)));
145    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), defineKey, defineHandle);
146
147    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
148    EXPECT_TRUE(*proxyHandle2 != nullptr);
149    JSHandle<JSTaggedValue> key2(factory->NewFromASCII("y"));
150    PropertyDescriptor desc2(thread);
151    EXPECT_FALSE(JSProxy::GetOwnProperty(thread, proxyHandle2, key2, desc2));
152}
153
154// ES6 9.5.9 [[Set]] ( P, V, Receiver)
155JSTaggedValue HandlerSetProperty([[maybe_unused]] EcmaRuntimeCallInfo *argv)
156{
157    return JSTaggedValue(JSTaggedValue::False());
158}
159
160JSHandle<JSProxy> PropertyCommon(JSThread *thread, JSHandle<JSTaggedValue>& targetHandle,
161    JSHandle<JSTaggedValue>& handlerHandle, JSHandle<JSTaggedValue>& key, uint32_t value = 0)
162{
163    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
164    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
165    targetHandle = JSHandle<JSTaggedValue>(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
166    EXPECT_TRUE(targetHandle->IsECMAObject());
167
168    if (value) {
169        PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(value)));
170        JSObject::DefineOwnProperty(thread, JSHandle<JSObject>::Cast(targetHandle), key, desc);
171    }
172    handlerHandle = JSHandle<JSTaggedValue>(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
173    EXPECT_TRUE(handlerHandle->IsECMAObject());
174
175    JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
176    return proxyHandle;
177}
178
179HWTEST_F_L0(JSProxyTest, SetProperty)
180{
181    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
182    JSHandle<JSTaggedValue> key(factory->NewFromASCII("x"));
183    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(1));
184    JSHandle<JSTaggedValue> targetHandle;
185    JSHandle<JSTaggedValue> handlerHandle;
186    JSHandle<JSProxy> proxyHandle = PropertyCommon(thread, targetHandle, handlerHandle, key);
187    EXPECT_TRUE(*proxyHandle != nullptr);
188
189    EXPECT_TRUE(JSProxy::SetProperty(thread, proxyHandle, key, value));
190    EXPECT_EQ(JSProxy::GetProperty(thread, proxyHandle, key).GetValue()->GetInt(), 1);
191    EXPECT_EQ(JSObject::GetProperty(thread, targetHandle, key).GetValue()->GetInt(), 1);
192
193    // 2. handler has "set"
194    EcmaVM *vm = thread->GetEcmaVM();
195    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
196    JSHandle<JSTaggedValue> setKey = thread->GlobalConstants()->GetHandledSetString();
197    JSHandle<JSTaggedValue> setHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerSetProperty)));
198    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), setKey, setHandle);
199
200    JSHandle<JSProxy> proxyHandle2(JSProxy::ProxyCreate(thread, targetHandle, handlerHandle));
201    EXPECT_TRUE(*proxyHandle2 != nullptr);
202    JSHandle<JSTaggedValue> value2(thread, JSTaggedValue(10));
203    EXPECT_FALSE(JSProxy::SetProperty(thread, proxyHandle2, key, value2));
204    EXPECT_EQ(JSProxy::GetProperty(thread, proxyHandle2, key).GetValue()->GetInt(), 1);
205}
206
207// ES6 9.5.6 [[DefineOwnProperty]] (P, Desc)
208JSTaggedValue HandlerDefineOwnProperty([[maybe_unused]] EcmaRuntimeCallInfo *argv)
209{
210    return JSTaggedValue(JSTaggedValue::False());
211}
212
213HWTEST_F_L0(JSProxyTest, DefineOwnProperty)
214{
215    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
216    JSHandle<JSTaggedValue> key(factory->NewFromASCII("x"));
217    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(1));
218    JSHandle<JSTaggedValue> targetHandle;
219    JSHandle<JSTaggedValue> handlerHandle;
220    JSHandle<JSProxy> proxyHandle = PropertyCommon(thread, targetHandle, handlerHandle, key);
221    EXPECT_TRUE(*proxyHandle != nullptr);
222
223    PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)));
224    EXPECT_TRUE(JSProxy::DefineOwnProperty(thread, proxyHandle, key, desc));
225    EXPECT_EQ(JSProxy::GetProperty(thread, proxyHandle, key).GetValue()->GetInt(), 1);
226    EXPECT_EQ(JSObject::GetProperty(thread, targetHandle, key).GetValue()->GetInt(), 1);
227
228    // 2. handler has "defineProperty"
229    EcmaVM *vm = thread->GetEcmaVM();
230    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
231    JSHandle<JSTaggedValue> setKey = thread->GlobalConstants()->GetHandledDefinePropertyString();
232    JSHandle<JSTaggedValue> setHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerDefineOwnProperty)));
233    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), setKey, setHandle);
234
235    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
236    EXPECT_TRUE(*proxyHandle2 != nullptr);
237    PropertyDescriptor desc2(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(10)));
238    EXPECT_FALSE(JSProxy::DefineOwnProperty(thread, proxyHandle, key, desc2));
239    EXPECT_EQ(JSProxy::GetProperty(thread, proxyHandle2, key).GetValue()->GetInt(), 1);
240}
241
242JSTaggedValue HandlerDeleteProperty([[maybe_unused]] EcmaRuntimeCallInfo *argv)
243{
244    return JSTaggedValue(JSTaggedValue::False());
245}
246
247// ES6 9.5.10 [[Delete]] (P)
248HWTEST_F_L0(JSProxyTest, DeleteProperty)
249{
250    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
251    JSHandle<JSTaggedValue> key(factory->NewFromASCII("x"));
252    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(1));
253    JSHandle<JSTaggedValue> targetHandle;
254    JSHandle<JSTaggedValue> handlerHandle;
255    JSHandle<JSProxy> proxyHandle = PropertyCommon(thread, targetHandle, handlerHandle, key);
256    EXPECT_TRUE(*proxyHandle != nullptr);
257
258    PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)), true, true, true);
259    EXPECT_TRUE(JSProxy::DefineOwnProperty(thread, proxyHandle, key, desc));
260    EXPECT_EQ(JSProxy::GetProperty(thread, proxyHandle, key).GetValue()->GetInt(), 1);
261    EXPECT_EQ(JSObject::GetProperty(thread, targetHandle, key).GetValue()->GetInt(), 1);
262    EXPECT_TRUE(JSProxy::DeleteProperty(thread, proxyHandle, key));
263    PropertyDescriptor resDesc(thread);
264    JSProxy::GetOwnProperty(thread, proxyHandle, key, resDesc);
265    EXPECT_TRUE(JSTaggedValue::SameValue(resDesc.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()));
266
267    // 2. handler has "deleteProperty"
268    EcmaVM *vm = thread->GetEcmaVM();
269    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
270    JSHandle<JSTaggedValue> funcKey = thread->GlobalConstants()->GetHandledDeletePropertyString();
271    JSHandle<JSTaggedValue> funcHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerDeleteProperty)));
272    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), funcKey, funcHandle);
273
274    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
275    EXPECT_TRUE(*proxyHandle2 != nullptr);
276    PropertyDescriptor desc2(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)), true, true, true);
277    EXPECT_TRUE(JSProxy::DefineOwnProperty(thread, proxyHandle2, key, desc2));
278    EXPECT_EQ(JSProxy::GetProperty(thread, proxyHandle2, key).GetValue()->GetInt(), 1);
279    EXPECT_FALSE(JSProxy::DeleteProperty(thread, proxyHandle2, key));
280}
281
282JSTaggedValue HandlerGetPrototype([[maybe_unused]] EcmaRuntimeCallInfo *argv)
283{
284    return JSTaggedValue(JSTaggedValue::Null());
285}
286
287// ES6 9.5.1 [[GetPrototypeOf]] ( )
288HWTEST_F_L0(JSProxyTest, GetPrototypeOf)
289{
290    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
291    // 1. handler has no "GetPrototypeOf"
292    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
293    JSHandle<JSTaggedValue> proto(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
294    JSHandle<JSTaggedValue> targetHandle(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
295    EXPECT_TRUE(targetHandle->IsECMAObject());
296    JSObject::SetPrototype(thread, JSHandle<JSObject>(targetHandle), proto);
297    EXPECT_TRUE(
298        JSTaggedValue::SameValue(JSTaggedValue::GetPrototype(thread, targetHandle), proto.GetTaggedValue()));
299
300    JSHandle<JSTaggedValue> handlerHandle(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
301    EXPECT_TRUE(handlerHandle->IsECMAObject());
302
303    JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
304    EXPECT_TRUE(*proxyHandle != nullptr);
305
306    EXPECT_TRUE(JSTaggedValue::SameValue(JSProxy::GetPrototype(thread, proxyHandle), proto.GetTaggedValue()));
307
308    // 2. handler has "GetPrototypeOf"
309    EcmaVM *vm = thread->GetEcmaVM();
310    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
311    JSHandle<JSTaggedValue> funcKey = thread->GlobalConstants()->GetHandledGetPrototypeOfString();
312    JSHandle<JSTaggedValue> funcHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerGetPrototype)));
313    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), funcKey, funcHandle);
314
315    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
316    EXPECT_TRUE(*proxyHandle2 != nullptr);
317    EXPECT_TRUE(JSTaggedValue::SameValue(JSProxy::GetPrototype(thread, proxyHandle2), JSTaggedValue::Null()));
318}
319
320JSTaggedValue HandlerSetPrototype([[maybe_unused]] EcmaRuntimeCallInfo *argv)
321{
322    return JSTaggedValue(JSTaggedValue::False());
323}
324
325// ES6 9.5.2 [[SetPrototypeOf]] (V)
326HWTEST_F_L0(JSProxyTest, SetPrototypeOf)
327{
328    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
329    // 1. handler has no "SetPrototypeOf"
330    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
331    JSHandle<JSTaggedValue> proto(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
332    JSHandle<JSTaggedValue> targetHandle(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
333    EXPECT_TRUE(targetHandle->IsECMAObject());
334
335    JSHandle<JSTaggedValue> handlerHandle(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
336    EXPECT_TRUE(handlerHandle->IsECMAObject());
337
338    JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
339    EXPECT_TRUE(*proxyHandle != nullptr);
340
341    JSProxy::SetPrototype(thread, proxyHandle, proto);
342    EXPECT_TRUE(
343        JSTaggedValue::SameValue(JSTaggedValue::GetPrototype(thread, targetHandle), proto.GetTaggedValue()));
344
345    // 2. handler has "SetPrototypeOf"
346    EcmaVM *vm = thread->GetEcmaVM();
347    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
348    JSHandle<JSTaggedValue> funcKey = thread->GlobalConstants()->GetHandledSetPrototypeOfString();
349    JSHandle<JSTaggedValue> funcHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerSetPrototype)));
350    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), funcKey, funcHandle);
351
352    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
353    EXPECT_TRUE(*proxyHandle2 != nullptr);
354    EXPECT_FALSE(JSProxy::SetPrototype(thread, proxyHandle2, proto));
355}
356
357JSTaggedValue HandlerIsExtensible([[maybe_unused]] EcmaRuntimeCallInfo *argv)
358{
359    return JSTaggedValue(JSTaggedValue::False());
360}
361
362// ES6 9.5.3 [[IsExtensible]] ( )
363HWTEST_F_L0(JSProxyTest, IsExtensible)
364{
365    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
366    // 1. handler has no "IsExtensible"
367    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
368    JSHandle<JSTaggedValue> targetHandle(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
369    EXPECT_TRUE(targetHandle->IsECMAObject());
370
371    JSHandle<JSTaggedValue> handlerHandle(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
372    EXPECT_TRUE(handlerHandle->IsECMAObject());
373
374    JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
375    EXPECT_TRUE(*proxyHandle != nullptr);
376
377    bool status1 = JSProxy::IsExtensible(thread, proxyHandle);
378    bool status2 = JSHandle<JSObject>::Cast(targetHandle)->IsExtensible();
379    EXPECT_TRUE(status1 == status2);
380
381    // 2. handler has "IsExtensible"
382    EcmaVM *vm = thread->GetEcmaVM();
383    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
384    JSHandle<JSTaggedValue> funcKey = thread->GlobalConstants()->GetHandledIsExtensibleString();
385    JSHandle<JSTaggedValue> funcHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerIsExtensible)));
386    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), funcKey, funcHandle);
387
388    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
389    EXPECT_TRUE(*proxyHandle2 != nullptr);
390    EXPECT_FALSE(JSProxy::IsExtensible(thread, proxyHandle2));
391}
392
393JSTaggedValue HandlerPreventExtensions([[maybe_unused]] EcmaRuntimeCallInfo *argv)
394{
395    return JSTaggedValue(JSTaggedValue::False());
396}
397
398// ES6 9.5.4 [[PreventExtensions]] ( )
399HWTEST_F_L0(JSProxyTest, PreventExtensions)
400{
401    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
402    // 1. handler has no "PreventExtensions"
403    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
404    JSHandle<JSTaggedValue> targetHandle(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
405    EXPECT_TRUE(targetHandle->IsECMAObject());
406
407    JSHandle<JSTaggedValue> handlerHandle(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
408    EXPECT_TRUE(handlerHandle->IsECMAObject());
409
410    JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
411    EXPECT_TRUE(*proxyHandle != nullptr);
412
413    bool status1 = JSProxy::PreventExtensions(thread, proxyHandle);
414    EXPECT_TRUE(status1);
415    bool status2 = JSHandle<JSObject>::Cast(targetHandle)->IsExtensible();
416    EXPECT_FALSE(status2);
417
418    // 2. handler has "PreventExtensions"
419    EcmaVM *vm = thread->GetEcmaVM();
420    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
421    JSHandle<JSTaggedValue> funcKey = thread->GlobalConstants()->GetHandledPreventExtensionsString();
422    JSHandle<JSTaggedValue> funcHandle(
423        factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerPreventExtensions)));
424    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), funcKey, funcHandle);
425
426    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
427    EXPECT_TRUE(*proxyHandle2 != nullptr);
428    EXPECT_FALSE(JSProxy::PreventExtensions(thread, proxyHandle2));
429}
430
431JSTaggedValue HandlerHasProperty([[maybe_unused]] EcmaRuntimeCallInfo *argv)
432{
433    return JSTaggedValue(JSTaggedValue::False());
434}
435
436// ES6 9.5.7 [[HasProperty]] (P)
437HWTEST_F_L0(JSProxyTest, HasProperty)
438{
439    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
440    JSHandle<JSTaggedValue> key(factory->NewFromASCII("x"));
441    JSHandle<JSTaggedValue> targetHandle;
442    JSHandle<JSTaggedValue> handlerHandle;
443    JSHandle<JSProxy> proxyHandle = PropertyCommon(thread, targetHandle, handlerHandle, key, 1); // 1: value
444    EXPECT_TRUE(*proxyHandle != nullptr);
445
446    EXPECT_TRUE(JSProxy::HasProperty(thread, proxyHandle, key));
447
448    // 2. handler has "HasProperty"
449    EcmaVM *vm = thread->GetEcmaVM();
450    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
451    JSHandle<JSTaggedValue> funcKey = thread->GlobalConstants()->GetHandledHasString();
452    JSHandle<JSTaggedValue> funcHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerHasProperty)));
453    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), funcKey, funcHandle);
454
455    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
456    EXPECT_TRUE(*proxyHandle2 != nullptr);
457    EXPECT_FALSE(JSProxy::HasProperty(thread, proxyHandle2, key));
458}
459
460JSTaggedValue HandlerOwnPropertyKeys([[maybe_unused]] EcmaRuntimeCallInfo *argv)
461{
462    auto thread = argv->GetThread();
463    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
464    JSHandle<JSArray> arr = factory->NewJSArray();
465    return JSTaggedValue(arr.GetTaggedValue());
466}
467
468// ES6 9.5.12 [[OwnPropertyKeys]] ()
469HWTEST_F_L0(JSProxyTest, OwnPropertyKeys)
470{
471    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
472    JSHandle<JSTaggedValue> key(factory->NewFromASCII("x"));
473    JSHandle<JSTaggedValue> targetHandle;
474    JSHandle<JSTaggedValue> handlerHandle;
475    JSHandle<JSProxy> proxyHandle = PropertyCommon(thread, targetHandle, handlerHandle, key, 1); // 1: value
476    EXPECT_TRUE(*proxyHandle != nullptr);
477    JSHandle<TaggedArray> res = JSProxy::OwnPropertyKeys(thread, proxyHandle);
478
479    EXPECT_TRUE(JSTaggedValue::SameValue(res->Get(0), key.GetTaggedValue()));
480
481    // 2. handler has "OwnPropertyKeys"
482    EcmaVM *vm = thread->GetEcmaVM();
483    JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
484    JSHandle<JSTaggedValue> funcKey = thread->GlobalConstants()->GetHandledOwnKeysString();
485    JSHandle<JSTaggedValue> funcHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerOwnPropertyKeys)));
486    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), funcKey, funcHandle);
487
488    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
489    EXPECT_TRUE(*proxyHandle2 != nullptr);
490    JSHandle<TaggedArray> res2 = JSProxy::OwnPropertyKeys(thread, proxyHandle2);
491    EXPECT_TRUE(res2->GetLength() == 0U || !JSTaggedValue::SameValue(res2->Get(0), key.GetTaggedValue()));
492}
493
494JSTaggedValue HandlerCall([[maybe_unused]] EcmaRuntimeCallInfo *argv)
495{
496    return JSTaggedValue(JSTaggedValue::False());
497}
498JSTaggedValue HandlerFunction([[maybe_unused]] EcmaRuntimeCallInfo *argv)
499{
500    return JSTaggedValue(JSTaggedValue::True());
501}
502
503// ES6 9.5.13 [[Call]] (thisArgument, argumentsList)
504HWTEST_F_L0(JSProxyTest, Call)
505{
506    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
507    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
508    // 1. handler has no "Call"
509    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
510    JSHandle<JSTaggedValue> targetHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerFunction)));
511    EXPECT_TRUE(targetHandle->IsECMAObject());
512
513    JSHandle<JSTaggedValue> handlerHandle(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
514    EXPECT_TRUE(handlerHandle->IsECMAObject());
515
516    JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
517    EXPECT_TRUE(*proxyHandle != nullptr);
518
519    JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
520    EcmaRuntimeCallInfo *info =
521        EcmaInterpreter::NewRuntimeCallInfo(thread, JSHandle<JSTaggedValue>(proxyHandle),
522        JSHandle<JSTaggedValue>(proxyHandle), undefined, 0);
523    JSTaggedValue res = JSProxy::CallInternal(info);
524    EXPECT_TRUE(JSTaggedValue::SameValue(res, JSTaggedValue::True()));
525
526    // 2. handler has "Call"
527    JSHandle<JSTaggedValue> funcKey = thread->GlobalConstants()->GetHandledApplyString();
528    JSHandle<JSTaggedValue> funcHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerCall)));
529    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), funcKey, funcHandle);
530
531    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
532    EXPECT_TRUE(*proxyHandle2 != nullptr);
533
534    EcmaRuntimeCallInfo *runtimeInfo =
535        EcmaInterpreter::NewRuntimeCallInfo(thread, JSHandle<JSTaggedValue>(proxyHandle2),
536        JSHandle<JSTaggedValue>(proxyHandle2), undefined, 0);
537    JSTaggedValue res2 = JSProxy::CallInternal(runtimeInfo);
538    EXPECT_TRUE(JSTaggedValue::SameValue(res2, JSTaggedValue::False()));
539}
540
541JSTaggedValue HandlerConstruct([[maybe_unused]] EcmaRuntimeCallInfo *argv)
542{
543    auto thread = argv->GetThread();
544    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
545    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
546    JSHandle<JSTaggedValue> obj(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
547
548    JSHandle<JSTaggedValue> key(factory->NewFromASCII("x"));
549    PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(2))); // 2 : test case
550    JSObject::DefineOwnProperty(argv->GetThread(), JSHandle<JSObject>::Cast(obj), key, desc);
551    return JSTaggedValue(obj.GetTaggedValue());
552}
553JSTaggedValue HandlerConFunc([[maybe_unused]] EcmaRuntimeCallInfo *argv)
554{
555    auto thread = argv->GetThread();
556    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
557    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
558    JSHandle<JSTaggedValue> obj(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
559
560    JSHandle<JSTaggedValue> key(factory->NewFromASCII("x"));
561    PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)));
562    JSObject::DefineOwnProperty(argv->GetThread(), JSHandle<JSObject>::Cast(obj), key, desc);
563    return JSTaggedValue(obj.GetTaggedValue());
564}
565
566// ES6 9.5.14 [[Construct]] ( argumentsList, newTarget)
567HWTEST_F_L0(JSProxyTest, Construct)
568{
569    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
570    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
571    // 1. handler has no "Construct"
572    JSHandle<JSTaggedValue> hclass(thread, JSObjectTestCreate(thread));
573    JSHandle<JSTaggedValue> targetHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerConFunc)));
574    JSHandle<JSFunction>::Cast(targetHandle)->GetJSHClass()->SetConstructor(true);
575    EXPECT_TRUE(targetHandle->IsECMAObject());
576
577    JSHandle<JSTaggedValue> handlerHandle(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(hclass), hclass));
578    EXPECT_TRUE(handlerHandle->IsECMAObject());
579
580    JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
581    EXPECT_TRUE(*proxyHandle != nullptr);
582    JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
583    EcmaRuntimeCallInfo *info =
584        EcmaInterpreter::NewRuntimeCallInfo(thread, JSHandle<JSTaggedValue>(proxyHandle), handlerHandle, undefined, 0);
585    JSTaggedValue res = JSProxy::ConstructInternal(info);
586    JSHandle<JSTaggedValue> taggedRes(thread, res);
587    JSHandle<JSTaggedValue> key(factory->NewFromASCII("x"));
588    EXPECT_EQ(JSObject::GetProperty(thread, taggedRes, key).GetValue()->GetInt(), 1);
589
590    // 2. handler has "Construct"
591    JSHandle<JSTaggedValue> funcKey = thread->GlobalConstants()->GetHandledProxyConstructString();
592    JSHandle<JSTaggedValue> funcHandle(factory->NewJSFunction(env, reinterpret_cast<void *>(HandlerConstruct)));
593    JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handlerHandle), funcKey, funcHandle);
594
595    JSHandle<JSProxy> proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle);
596    EXPECT_TRUE(*proxyHandle2 != nullptr);
597    EcmaRuntimeCallInfo *runtimeInfo =
598        EcmaInterpreter::NewRuntimeCallInfo(thread, JSHandle<JSTaggedValue>(proxyHandle2), targetHandle, undefined, 0);
599    JSTaggedValue res2 = JSProxy::ConstructInternal(runtimeInfo);
600    JSHandle<JSTaggedValue> taggedRes2(thread, res2);
601    EXPECT_EQ(JSObject::GetProperty(thread, taggedRes2, key).GetValue()->GetInt(), 2);
602}
603}  // namespace panda::test
604