1/*
2 * Copyright (c) 2021 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_SINGLE_STEP_TEST_H
17#define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_SINGLE_STEP_TEST_H
18
19#include "test/utils/test_util.h"
20
21namespace panda::ecmascript::tooling::test {
22class JsSingleStepTest : public TestEvents {
23public:
24    JsSingleStepTest()
25    {
26        vmDeath = [this]() {
27            ASSERT_NE(stepCounter_, 0);  // 0: step counter
28            ASSERT_EQ(breakpointCounter_, 2);  // 2: break point counter
29            return true;
30        };
31
32        loadModule = [this](std::string_view moduleName) {
33            runtime_->Enable();
34            // 19: line number
35            locationStart_ = TestUtil::GetLocation(sourceFile_.c_str(), 19, 0, pandaFile_.c_str());
36            // 22: line number
37            locationEnd_ = TestUtil::GetLocation(sourceFile_.c_str(), 22, 0, pandaFile_.c_str());
38            TestUtil::SuspendUntilContinue(DebugEvent::LOAD_MODULE);
39            ASSERT_EQ(moduleName, pandaFile_);
40            auto condFuncRef = FunctionRef::Undefined(vm_);
41            auto ret = debugInterface_->SetBreakpoint(locationEnd_, condFuncRef);
42            ASSERT_TRUE(ret);
43            return true;
44        };
45
46        breakpoint = [this](const JSPtLocation &location) {
47            ASSERT_TRUE(location.GetMethodId().IsValid());
48            ASSERT_LOCATION_EQ(location, locationEnd_);
49            // Check what step signalled before breakpoint
50            ASSERT_LOCATION_EQ(location, locationStep_);
51            ASSERT_TRUE(collectSteps_);
52            breakpointCounter_++;
53            // Disable collect steps
54            collectSteps_ = false;
55            return true;
56        };
57
58        singleStep = [this](const JSPtLocation &location) {
59            ASSERT_TRUE(location.GetMethodId().IsValid());
60            if (!collectSteps_) {
61                if (locationStart_ == location) {
62                    collectSteps_ = true;
63                }
64                return false;
65            }
66
67            ASSERT_NE(bytecodeOffset_, location.GetBytecodeOffset());
68            locationStep_ = location;
69            stepCounter_++;
70            bytecodeOffset_ = location.GetBytecodeOffset();
71            return false;
72        };
73
74        scenario = []() {
75            TestUtil::WaitForLoadModule();
76            TestUtil::Continue();
77            return true;
78        };
79    }
80
81    std::pair<std::string, std::string> GetEntryPoint() override
82    {
83        return {pandaFile_, entryPoint_};
84    }
85
86private:
87    std::string pandaFile_ = DEBUGGER_ABC_DIR "sample.abc";
88    std::string sourceFile_ = DEBUGGER_JS_DIR "sample.js";
89    std::string entryPoint_ = "_GLOBAL::func_main_0";
90    JSPtLocation locationStart_ {nullptr, JSPtLocation::EntityId(0), 0};
91    JSPtLocation locationEnd_ {nullptr, JSPtLocation::EntityId(0), 0};
92    JSPtLocation locationStep_ {nullptr, JSPtLocation::EntityId(0), 0};
93    int32_t stepCounter_ = 0;
94    int32_t breakpointCounter_ = 0;
95    bool collectSteps_ = false;
96    uint32_t bytecodeOffset_ = std::numeric_limits<uint32_t>::max();
97};
98
99std::unique_ptr<TestEvents> GetJsSingleStepTest()
100{
101    return std::make_unique<JsSingleStepTest>();
102}
103}  // namespace panda::ecmascript::tooling::test
104
105#endif  // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_SINGLE_STEP_TEST_H
106