1/*
2 * Copyright (c) 2023 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_TESTCASES_JS_HEAPDUMP_TEST_H
17#define ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_HEAPDUMP_TEST_H
18
19#include "tooling/test/client_utils/test_util.h"
20
21namespace panda::ecmascript::tooling::test {
22class JsHeapdumpTest : public TestActions {
23public:
24    JsHeapdumpTest()
25    {
26        testAction = {
27            {SocketAction::SEND, "enable"},
28            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
29            {SocketAction::SEND, "runtime-enable"},
30            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
31            {SocketAction::SEND, "run"},
32            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
33            // load sample.js
34            {SocketAction::RECV, "Debugger.scriptParsed", ActionRule::STRING_CONTAIN},
35            // break on start
36            {SocketAction::RECV, "Debugger.paused", ActionRule::STRING_CONTAIN},
37            {SocketAction::SEND, "heapprofiler-enable"},
38            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
39            {SocketAction::SEND, "heapdump"},
40            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, [this] (auto recv, auto, auto) -> bool {
41                return RecvReportProgress(recv);
42            }},
43            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, [this] (auto recv, auto, bool& needMoreMsg) -> bool {
44                return RecvReportProgressFinished(recv, needMoreMsg);
45            }},
46            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, [this] (auto recv, auto, bool& needMoreMsg) -> bool {
47                return RecvReportProgressChunk(recv, needMoreMsg);
48            }},
49            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
50            {SocketAction::SEND, "heapprofiler-disable"},
51            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
52            // reply success and run
53            {SocketAction::SEND, "success"},
54            {SocketAction::SEND, "resume"},
55            {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
56            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
57        };
58    }
59
60    bool RecvReportProgress(std::string recv)
61    {
62        std::unique_ptr<PtJson> json = PtJson::Parse(recv);
63        Result ret;
64        std::string method;
65        ret = json->GetString("method", &method);
66        if (ret != Result::SUCCESS) {
67            return false;
68        }
69
70        if (method != "HeapProfiler.reportHeapSnapshotProgress") {
71            return false;
72        }
73
74        std::unique_ptr<PtJson> params = nullptr;
75        ret = json->GetObject("params", &params);
76        if (ret != Result::SUCCESS) {
77            return false;
78        }
79
80        int done;
81        ret = params->GetInt("done", &done);
82        if (ret != Result::SUCCESS) {
83            return false;
84        }
85
86        if (done != 0) {
87            return false;
88        }
89        return true;
90    }
91
92    bool RecvReportProgressFinished(std::string recv, bool &needMoreMsg)
93    {
94        needMoreMsg = false;
95        std::unique_ptr<PtJson> json = PtJson::Parse(recv);
96        Result ret;
97        std::string method;
98        ret = json->GetString("method", &method);
99        if (ret != Result::SUCCESS) {
100            return false;
101        }
102
103        if (method != "HeapProfiler.reportHeapSnapshotProgress") {
104            return false;
105        }
106
107        std::unique_ptr<PtJson> params = nullptr;
108        ret = json->GetObject("params", &params);
109        if (ret != Result::SUCCESS) {
110            return false;
111        }
112
113        int done;
114        ret = params->GetInt("done", &done);
115        if (ret != Result::SUCCESS) {
116            return false;
117        }
118
119        bool finished;
120        ret = params->GetBool("finished", &finished);
121        if (ret != Result::SUCCESS) {
122            needMoreMsg = true;
123        }
124        return true;
125    }
126
127    bool RecvReportProgressChunk(std::string recv, bool& needMoreMsg)
128    {
129        static std::string content;
130        needMoreMsg = false;
131        std::unique_ptr<PtJson> json = PtJson::Parse(recv);
132        Result ret;
133        std::string method;
134        ret = json->GetString("method", &method);
135        if (ret != Result::SUCCESS) {
136            return false;
137        }
138
139        if (method != "HeapProfiler.addHeapSnapshotChunk") {
140            return false;
141        }
142
143        std::unique_ptr<PtJson> params = nullptr;
144        ret = json->GetObject("params", &params);
145        if (ret != Result::SUCCESS) {
146            return false;
147        }
148
149        std::string chunk;
150        ret = params->GetString("chunk", &chunk);
151        if (ret != Result::SUCCESS) {
152            return false;
153        }
154
155        content += chunk;
156        std::unique_ptr<PtJson> contentJson = PtJson::Parse(content);
157        if (contentJson == nullptr || contentJson->Stringify().empty()) {
158            needMoreMsg = true;
159        }
160        return true;
161    }
162
163    std::pair<std::string, std::string> GetEntryPoint() override
164    {
165        return {pandaFile_, entryPoint_};
166    }
167    ~JsHeapdumpTest() = default;
168
169private:
170    std::string pandaFile_ = DEBUGGER_ABC_DIR "sample.abc";
171    std::string sourceFile_ = DEBUGGER_JS_DIR "sample.js";
172    std::string entryPoint_ = "_GLOBAL::func_main_0";
173};
174
175std::unique_ptr<TestActions> GetJsHeapdumpTest()
176{
177    return std::make_unique<JsHeapdumpTest>();
178}
179}  // namespace panda::ecmascript::tooling::test
180
181#endif  // ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_HEAPDUMP_TEST_H
182