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#ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_STEP_OUT_TEST_H
17#define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_STEP_OUT_TEST_H
18
19#include "test/utils/test_util.h"
20
21namespace panda::ecmascript::tooling::test {
22class JsStepOutTest : public TestEvents {
23public:
24    JsStepOutTest()
25    {
26        vmDeath = [this]() {
27            ASSERT_EQ(breakpointCounter_, pointerLocations_.size());  // size: break point counter
28            ASSERT_EQ(stepCompleteCounter_, stepLocations_.size());  // size: step complete counter
29            return true;
30        };
31
32        loadModule = [this](std::string_view moduleName) {
33            runtime_->Enable();
34            // 74、36: line number for breakpoint array
35            size_t breakpoint[5][2] = {{74, 0}, {36, 0}, {50, 0}, {61, 0}, {96, 0}};
36            // 28: line number for stepinto array
37            size_t stepOut[4][2] = {{28, 0}, {43, 0}, {57, 0}, {88, 5}};
38            SetJSPtLocation(breakpoint[0], POINTER_SIZE, pointerLocations_);
39            SetJSPtLocation(stepOut[0], STEP_SIZE, stepLocations_);
40            TestUtil::SuspendUntilContinue(DebugEvent::LOAD_MODULE);
41            ASSERT_EQ(moduleName, pandaFile_);
42            debugger_->NotifyScriptParsed(0, moduleName.data());
43            auto condFuncRef = FunctionRef::Undefined(vm_);
44            for (auto &iter : pointerLocations_) {
45                auto ret = debugInterface_->SetBreakpoint(iter, condFuncRef);
46                ASSERT_TRUE(ret);
47            }
48            return true;
49        };
50
51        breakpoint = [this](const JSPtLocation &location) {
52            ASSERT_TRUE(location.GetMethodId().IsValid());
53            ASSERT_LOCATION_EQ(location, pointerLocations_.at(breakpointCounter_));
54            ++breakpointCounter_;
55            TestUtil::SuspendUntilContinue(DebugEvent::BREAKPOINT, location);
56            debugger_->SetDebuggerState(DebuggerState::PAUSED);
57            debugger_->StepOut();
58            return true;
59        };
60
61        singleStep = [this](const JSPtLocation &location) {
62            if (debugger_->NotifySingleStep(location)) {
63                ASSERT_TRUE(location.GetMethodId().IsValid());
64                ASSERT_LOCATION_EQ(location, stepLocations_.at(stepCompleteCounter_));
65                stepCompleteCounter_++;
66                TestUtil::SuspendUntilContinue(DebugEvent::STEP_COMPLETE, location);
67                return true;
68            }
69            return false;
70        };
71
72        scenario = [this]() {
73            TestUtil::WaitForLoadModule();
74            TestUtil::Continue();
75            size_t index = 0;
76            while (index < pointerLocations_.size()) {
77                TestUtil::WaitForBreakpoint(pointerLocations_.at(index));
78                TestUtil::Continue();
79                if (index < STEP_SIZE) {
80                    TestUtil::WaitForStepComplete(stepLocations_.at(index));
81                    TestUtil::Continue();
82                }
83                ++index;
84            }
85            ASSERT_EXITED();
86            return true;
87        };
88    }
89
90    std::pair<std::string, std::string> GetEntryPoint() override
91    {
92        return {pandaFile_, entryPoint_};
93    }
94
95private:
96    static constexpr size_t LINE_COLUMN = 2;
97    static constexpr size_t POINTER_SIZE = 5;
98    static constexpr size_t STEP_SIZE = 4;
99
100    std::string pandaFile_ = DEBUGGER_ABC_DIR "step.abc";
101    std::string sourceFile_ = DEBUGGER_JS_DIR "step.js";
102    std::string entryPoint_ = "_GLOBAL::func_main_0";
103    JSPtLocation location1_ {nullptr, JSPtLocation::EntityId(0), 0};
104    JSPtLocation location2_ {nullptr, JSPtLocation::EntityId(0), 0};
105    size_t breakpointCounter_ = 0;
106    size_t stepCompleteCounter_ = 0;
107    std::vector<JSPtLocation> pointerLocations_;
108    std::vector<JSPtLocation> stepLocations_;
109
110    void SetJSPtLocation(size_t *arr, size_t number, std::vector<JSPtLocation> &locations)
111    {
112        for (size_t i = 0; i < number; i++) {
113            JSPtLocation location_ = TestUtil::GetLocation(sourceFile_.c_str(), arr[i * LINE_COLUMN],
114                                                           arr[i * LINE_COLUMN + 1], pandaFile_.c_str());
115            locations.push_back(location_);
116        }
117    };
118};
119
120std::unique_ptr<TestEvents> GetJsStepOutTest()
121{
122    return std::make_unique<JsStepOutTest>();
123}
124}  // namespace panda::ecmascript::tooling::test
125
126#endif  // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_STEP_OUT_TEST_H
127