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