1/*
2 * Copyright (c) 2022 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/containers/containers_queue.h"
17#include "ecmascript/containers/containers_private.h"
18#include "ecmascript/ecma_runtime_call_info.h"
19#include "ecmascript/global_env.h"
20#include "ecmascript/js_api/js_api_queue.h"
21#include "ecmascript/js_api/js_api_queue_iterator.h"
22#include "ecmascript/js_handle.h"
23#include "ecmascript/js_tagged_value-inl.h"
24#include "ecmascript/js_thread.h"
25#include "ecmascript/object_factory.h"
26#include "ecmascript/tests/test_helper.h"
27#include "ecmascript/containers/tests/containers_test_helper.h"
28
29using namespace panda::ecmascript;
30using namespace panda::ecmascript::containers;
31
32namespace panda::test {
33class ContainersQueueTest : public testing::Test {
34public:
35    static void SetUpTestCase()
36    {
37        GTEST_LOG_(INFO) << "SetUpTestCase";
38    }
39
40    static void TearDownTestCase()
41    {
42        GTEST_LOG_(INFO) << "TearDownCase";
43    }
44
45    void SetUp() override
46    {
47        TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
48    }
49
50    void TearDown() override
51    {
52        TestHelper::DestroyEcmaVMWithScope(instance, scope);
53    }
54
55    EcmaVM *instance {nullptr};
56    EcmaHandleScope *scope {nullptr};
57    JSThread *thread {nullptr};
58protected:
59    JSTaggedValue InitializeQueueConstructor()
60    {
61        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
62        JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
63
64        JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
65        JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
66        JSHandle<JSTaggedValue> value =
67            JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
68
69        auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
70        objCallInfo->SetFunction(JSTaggedValue::Undefined());
71        objCallInfo->SetThis(value.GetTaggedValue());
72        objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(ContainerTag::Queue)));
73        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
74        JSTaggedValue result = ContainersPrivate::Load(objCallInfo);
75        TestHelper::TearDownFrame(thread, prev);
76
77        return result;
78    }
79
80    JSHandle<JSAPIQueue> CreateJSAPIQueue(JSTaggedValue compare = JSTaggedValue::Undefined())
81    {
82        JSHandle<JSTaggedValue> compareHandle(thread, compare);
83        JSHandle<JSFunction> newTarget(thread, InitializeQueueConstructor());
84        auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
85        objCallInfo->SetFunction(newTarget.GetTaggedValue());
86        objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
87        objCallInfo->SetThis(JSTaggedValue::Undefined());
88        objCallInfo->SetCallArg(0, compareHandle.GetTaggedValue());
89
90        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
91        JSTaggedValue result = ContainersQueue::QueueConstructor(objCallInfo);
92        TestHelper::TearDownFrame(thread, prev);
93        JSHandle<JSAPIQueue> queue(thread, result);
94        return queue;
95    }
96};
97
98HWTEST_F_L0(ContainersQueueTest, QueueConstructor)
99{
100    InitializeQueueConstructor();
101    JSHandle<JSFunction> newTarget(thread, InitializeQueueConstructor());
102
103    auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
104    objCallInfo->SetFunction(newTarget.GetTaggedValue());
105    objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
106    objCallInfo->SetThis(JSTaggedValue::Undefined());
107
108    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
109    JSTaggedValue result = ContainersQueue::QueueConstructor(objCallInfo);
110    TestHelper::TearDownFrame(thread, prev);
111
112    ASSERT_TRUE(result.IsJSAPIQueue());
113    JSHandle<JSAPIQueue> queue(thread, result);
114    JSTaggedValue resultProto = JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(queue));
115    JSTaggedValue funcProto = newTarget->GetFunctionPrototype();
116    ASSERT_EQ(resultProto, funcProto);
117
118    // test QueueConstructor exception
119    objCallInfo->SetNewTarget(JSTaggedValue::Undefined());
120    CONTAINERS_API_EXCEPTION_TEST(ContainersQueue, QueueConstructor, objCallInfo);
121}
122
123HWTEST_F_L0(ContainersQueueTest, ProxyOfGetSize)
124{
125    constexpr uint32_t NODE_NUMBERS = 8;
126    JSHandle<JSAPIQueue> queue = CreateJSAPIQueue();
127    auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
128    callInfo->SetFunction(JSTaggedValue::Undefined());
129    JSHandle<JSProxy> proxy = CreateJSProxyHandle(thread);
130    proxy->SetTarget(thread, queue.GetTaggedValue());
131    callInfo->SetThis(proxy.GetTaggedValue());
132
133    for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
134        callInfo->SetCallArg(0, JSTaggedValue(i));
135        callInfo->SetCallArg(1, JSTaggedValue(i + 1));
136        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
137        ContainersQueue::Add(callInfo);
138        TestHelper::TearDownFrame(thread, prev);
139
140        [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo);
141        JSTaggedValue retult = ContainersQueue::GetSize(callInfo);
142        TestHelper::TearDownFrame(thread, prev1);
143        EXPECT_EQ(retult, JSTaggedValue(i + 1));
144    }
145}
146
147HWTEST_F_L0(ContainersQueueTest, ExceptionReturn)
148{
149    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersQueue, Add);
150    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersQueue, GetFirst);
151    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersQueue, Pop);
152    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersQueue, ForEach);
153    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersQueue, GetIteratorObj);
154    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersQueue, GetSize);
155}
156}  // namespace panda::test
157