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_CONTAINER_TEST_H
17#define ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_CONTAINER_TEST_H
18
19#include "tooling/test/client_utils/test_util.h"
20
21namespace panda::ecmascript::tooling::test {
22class JsContainerTest : public TestActions {
23public:
24    JsContainerTest()
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            // set breakpoint
38            {SocketAction::SEND, "b " DEBUGGER_JS_DIR "container.js 368"},
39            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
40            // hit breakpoint after resume first time
41            {SocketAction::SEND, "resume"},
42            {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
43            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
44            {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE, [this] (auto recv, auto, auto) -> bool {
45                std::unique_ptr<PtJson> json = PtJson::Parse(recv);
46                Result ret;
47                std::string method;
48                ret = json->GetString("method", &method);
49                if (ret != Result::SUCCESS || method != "Debugger.paused") {
50                    return false;
51                }
52
53                std::unique_ptr<PtJson> params = nullptr;
54                ret = json->GetObject("params", &params);
55                if (ret != Result::SUCCESS) {
56                    return false;
57                }
58
59                std::unique_ptr<PtJson> hitBreakpoints = nullptr;
60                ret = params->GetArray("hitBreakpoints", &hitBreakpoints);
61                if (ret != Result::SUCCESS) {
62                    return false;
63                }
64
65                std::string breakpoint;
66                breakpoint = hitBreakpoints->Get(0)->GetString();
67                if (ret != Result::SUCCESS || breakpoint.find(sourceFile_) == std::string::npos ||
68                    breakpoint.find("367") == std::string::npos) {
69                    return false;
70                }
71
72                DebuggerClient debuggerClient(0);
73                debuggerClient.PausedReply(std::move(json));
74                return true;
75            }},
76
77            {SocketAction::SEND, "print"},
78            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, [this] (auto recv, auto, auto) -> bool {
79                std::unique_ptr<PtJson> json = PtJson::Parse(recv);
80                Result ret;
81                int32_t id = 0;
82                ret = json->GetInt("id", &id);
83                if (ret != Result::SUCCESS) {
84                    return false;
85                }
86
87                std::unique_ptr<PtJson> result = nullptr;
88                ret = json->GetObject("result", &result);
89                if (ret != Result::SUCCESS) {
90                    return false;
91                }
92
93                std::unique_ptr<PtJson> innerResult;
94                ret = result->GetArray("result", &innerResult);
95                if (ret != Result::SUCCESS) {
96                    return false;
97                }
98
99                std::string name;
100                std::unique_ptr<PtJson> value;
101                std::string type;
102                std::string className;
103                std::string unserializableValue;
104                std::string description;
105                for (int32_t i = 0; i < innerResult->GetSize(); i++) {
106                    std::vector<std::string> infos;
107                    ret = innerResult->Get(i)->GetString("name", &name);
108                    if (ret != Result::SUCCESS) {
109                        return false;
110                    }
111
112                    ret = innerResult->Get(i)->GetObject("value", &value);
113                    if (ret != Result::SUCCESS) {
114                        return false;
115                    }
116
117                    ret = value->GetString("type", &type);
118                    if (ret == Result::SUCCESS) {
119                        infos.push_back(type);
120                    }
121
122                    ret = value->GetString("className", &className);
123                    if (ret == Result::SUCCESS) {
124                        infos.push_back(className);
125                    }
126
127                    ret = value->GetString("unserializableValue", &unserializableValue);
128                    if (ret == Result::SUCCESS) {
129                        infos.push_back(unserializableValue);
130                    }
131
132                    ret = value->GetString("description", &description);
133                    if (ret == Result::SUCCESS) {
134                        infos.push_back(description);
135                    }
136
137                    for (uint32_t j = 0; j < infos.size(); j++) {
138                        if (infos[j] != this->variableMap_.at(name)[j]) {
139                            return false;
140                        }
141                    }
142                }
143                return true;
144            }},
145
146            // reply success and run
147            {SocketAction::SEND, "success"},
148            {SocketAction::SEND, "resume"},
149            {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
150            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
151        };
152    }
153
154    std::pair<std::string, std::string> GetEntryPoint() override
155    {
156        return {pandaFile_, entryPoint_};
157    }
158    ~JsContainerTest() = default;
159
160private:
161    std::string pandaFile_ = DEBUGGER_ABC_DIR "container.abc";
162    std::string sourceFile_ = DEBUGGER_JS_DIR "container.js";
163    std::string entryPoint_ = "_GLOBAL::func_main_0";
164
165    const std::map<std::string, std::vector<std::string>> variableMap_ = {
166        { "nop", { "undefined" } },
167        { "foo", { "function", "Function", "function foo( { [js code] }",
168            "function foo( { [js code] }" } },
169        { "ArrayList", { "function", "Function", "function ArrayList( { [native code] }",
170            "function ArrayList( { [native code] }" } },
171        { "Deque", { "function", "Function", "function Deque( { [native code] }",
172            "function Deque( { [native code] }" } },
173        { "HashMap", { "function", "Function", "function HashMap( { [native code] }",
174            "function HashMap( { [native code] }" } },
175        { "HashSet", { "function", "Function", "function HashSet( { [native code] }",
176            "function HashSet( { [native code] }" } },
177        { "LightWeightMap", { "function", "Function", "function LightWeightMap( { [native code] }",
178            "function LightWeightMap( { [native code] }" } },
179        { "LightWeightSet", { "function", "Function", "function LightWeightSet( { [native code] }",
180            "function LightWeightSet( { [native code] }" } },
181        { "LinkedList", { "function", "Function", "function LinkedList( { [native code] }",
182            "function LinkedList( { [native code] }" } },
183        { "List", { "function", "Function", "function List( { [native code] }",
184            "function List( { [native code] }" } },
185        { "PlainArray", { "function", "Function", "function PlainArray( { [native code] }",
186            "function PlainArray( { [native code] }" } },
187        { "Queue", { "function", "Function", "function Queue( { [native code] }",
188            "function Queue( { [native code] }" } },
189        { "Stack", { "function", "Function", "function Stack( { [native code] }",
190            "function Stack( { [native code] }" } },
191        { "TreeMap", { "function", "Function", "function TreeMap( { [native code] }",
192            "function TreeMap( { [native code] }" } },
193        { "TreeSet", { "function", "Function", "function TreeSet( { [native code] }",
194            "function TreeSet( { [native code] }" } },
195        { "Vector", { "function", "Function", "function Vector( { [native code] }",
196            "function Vector( { [native code] }" } },
197        { "arrayList", { "object", "Object", "ArrayList", "ArrayList" } },
198        { "deque", { "object", "Object", "Deque", "Deque" } },
199        { "hashMap", { "object", "Object", "HashMap", "HashMap" } },
200        { "hashSet", { "object", "Object", "HashSet", "HashSet" } },
201        { "lightWeightMap", { "object", "Object", "LightWeightMap", "LightWeightMap" } },
202        { "lightWeightSet", { "object", "Object", "LightWeightSet", "LightWeightSet" } },
203        { "linkedList", { "object", "Object", "LinkedList", "LinkedList" } },
204        { "list", { "object", "Object", "List", "List" } },
205        { "plainArray", { "object", "Object", "PlainArray", "PlainArray" } },
206        { "queue", { "object", "Object", "Queue", "Queue" } },
207        { "stack", { "object", "Object", "Stack", "Stack" } },
208        { "treeMap", { "object", "Object", "TreeMap", "TreeMap" } },
209        { "treeSet", { "object", "Object", "TreeSet", "TreeSet" } },
210        { "vector", { "object", "Object", "Vector", "Vector" } },
211        { "boolean0", { "boolean", "false", "false" } },
212        { "boolean1", { "boolean", "true", "true" } },
213        { "boolean2", { "boolean", "false", "false" } },
214        { "boolean3", { "boolean", "true", "true" } },
215        { "number0", { "number", "1888", "1888" } },
216        { "number1", { "number", "177", "177" } },
217        { "number2", { "number", "-1", "-1" } },
218        { "number3", { "number", "-1", "-1" } },
219        { "number4", { "number", "222", "222" } },
220        { "number5", { "number", "-2", "-2" } },
221        { "number6", { "number", "566", "566" } },
222        { "number7", { "number", "588", "588" } },
223        { "number8", { "number", "588", "588" } },
224        { "number9", { "number", "0", "0" } },
225        { "number10", { "number", "-1", "-1" } },
226        { "number11", { "number", "88", "88" } },
227        { "number12", { "number", "18", "18" } },
228        { "number13", { "number", "322", "322" } },
229        { "number14", { "number", "8", "8" } },
230        { "number15", { "number", "4", "4" } },
231        { "number16", { "number", "8", "8" } },
232        { "number17", { "number", "5", "5" } },
233        { "number18", { "number", "188", "188" } },
234        { "number19", { "number", "8", "8" } },
235        { "number20", { "number", "388", "388" } },
236        { "number21", { "number", "0", "0" } },
237        { "number22", { "number", "5", "5" } },
238        { "number23", { "number", "18", "18" } },
239        { "number24", { "number", "1388", "1388" } },
240        { "number25", { "number", "6", "6" } },
241        { "number26", { "number", "0", "0" } },
242        { "number27", { "number", "857", "857" } },
243        { "string0", { "string", "two", "two" } },
244        { "string1", { "string", "change", "change" } },
245        { "string2", { "string", "three", "three" } },
246        { "string3", { "string", "array", "array" } },
247        { "string4", { "string", "male", "male" } },
248        { "string5", { "string", "one", "one" } },
249        { "sendableArray", { "object", "Object", "SendableArray [Sendable]", "SendableArray [Sendable]" } },
250        { "sendableArray0", { "number", "1", "1" } },
251        { "sendableArray1", { "number", "2", "2" } },
252        { "sendableArraySize", { "number", "2", "2" } },
253        { "sendableMap", { "object", "Object", "SendableMap [Sendable]", "SendableMap [Sendable]" } },
254        { "sendableMap0", { "number", "1", "1" } },
255        { "sendableMap1", { "number", "2", "2" } },
256        { "sendableMapSize", { "number", "2", "2" } },
257        { "sendableSet", { "object", "Object", "SendableSet [Sendable]", "SendableSet [Sendable]" } },
258        { "sendableSet0", { "boolean", "true", "true" } },
259        { "sendableSet1", { "boolean", "true", "true" } },
260        { "sendableSetSize", { "number", "2", "2" } },
261        };
262};
263
264std::unique_ptr<TestActions> GetJsContainerTest()
265{
266    return std::make_unique<JsContainerTest>();
267}
268}  // namespace panda::ecmascript::tooling::test
269
270#endif  // ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_CONTAINER_TEST_H
271