1 /**
2 * Copyright (c) 2025 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 #include <gtest/gtest.h>
17 #include <cstddef>
18 #include <string>
19 #include "lsp_api_test.h"
20 #include "lsp/include/applicable_refactors.h"
21
22 const size_t REFACTOR_TEMPLATE_POSITION_OFFSET = 8;
23
24 namespace {
25 using ark::es2panda::lsp::Initializer;
26
27 class LspTemplateRefTests : public LSPAPITests {
28 public:
29 static constexpr std::string_view TO_NAMED_TEMPLATE_KIND = "refactor.rewrite.string";
30 static constexpr std::string_view TO_NAMED_TEMPLATE_NAME = "Convert to template string";
31 };
32
TEST_F(LspTemplateRefTests,ConvertTemplateRefactor1)33 TEST_F(LspTemplateRefTests, ConvertTemplateRefactor1)
34 {
35 std::vector<std::string> files = {"ConvertTemplateRefactor1.ets"};
36 std::vector<std::string> texts = {R"(let a = /*1*/"\\0\\b\\f\\t\\r\\n" +text + "\\n"/*2*/;)"};
37 auto filePaths = CreateTempFile(files, texts);
38 size_t const expectedFileCount = 1;
39 ASSERT_EQ(filePaths.size(), expectedFileCount);
40
41 auto pos = texts[0].find("/*1*/");
42 ASSERT_NE(pos, std::string::npos);
43 Initializer initializer = Initializer();
44
45 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
46 ark::es2panda::lsp::RefactorContext refactorContext;
47 refactorContext.context = ctx;
48 refactorContext.kind = std::string(TO_NAMED_TEMPLATE_KIND);
49 refactorContext.span.pos = pos + REFACTOR_TEMPLATE_POSITION_OFFSET;
50 auto result = GetApplicableRefactorsImpl(&refactorContext);
51 initializer.DestroyContext(ctx);
52
53 ASSERT_EQ(1, result.size());
54 ASSERT_EQ(std::string(TO_NAMED_TEMPLATE_NAME), result[0].action.name);
55 }
56
TEST_F(LspTemplateRefTests,ConvertTemplateRefactor2)57 TEST_F(LspTemplateRefTests, ConvertTemplateRefactor2)
58 {
59 std::vector<std::string> files = {"ConvertTemplateRefactor2.ets"};
60 std::vector<std::string> texts = {R"(let b = /*3*/"" + text + ""/*4*/;)"};
61 auto filePaths = CreateTempFile(files, texts);
62 size_t const expectedFileCount = 1;
63 ASSERT_EQ(filePaths.size(), expectedFileCount);
64
65 auto pos = texts[0].find("/*3*/");
66 ASSERT_NE(pos, std::string::npos);
67 Initializer initializer = Initializer();
68 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
69 ark::es2panda::lsp::RefactorContext refactorContext;
70 refactorContext.context = ctx;
71 refactorContext.kind = std::string(TO_NAMED_TEMPLATE_KIND);
72 refactorContext.span.pos = pos + REFACTOR_TEMPLATE_POSITION_OFFSET;
73 auto result = GetApplicableRefactorsImpl(&refactorContext);
74 initializer.DestroyContext(ctx);
75 ASSERT_EQ(1, result.size());
76 ASSERT_EQ(std::string(TO_NAMED_TEMPLATE_NAME), result[0].action.name);
77 }
78
TEST_F(LspTemplateRefTests,ConvertTemplateRefactor3)79 TEST_F(LspTemplateRefTests, ConvertTemplateRefactor3)
80 {
81 std::vector<std::string> files = {"ConvertTemplateRefactor3.ets"};
82 std::vector<std::string> texts = {R"(let c = /*5*/'\$' + text + "\\\\/*6*/";)"};
83 auto filePaths = CreateTempFile(files, texts);
84 size_t const expectedFileCount = 1;
85 ASSERT_EQ(filePaths.size(), expectedFileCount);
86
87 auto pos = texts[0].find("/*5*/");
88 ASSERT_NE(pos, std::string::npos);
89 Initializer initializer = Initializer();
90 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
91 ark::es2panda::lsp::RefactorContext refactorContext;
92 refactorContext.context = ctx;
93 refactorContext.kind = std::string(TO_NAMED_TEMPLATE_KIND);
94 refactorContext.span.pos = pos + REFACTOR_TEMPLATE_POSITION_OFFSET;
95 auto result = GetApplicableRefactorsImpl(&refactorContext);
96
97 initializer.DestroyContext(ctx);
98 ASSERT_EQ(1, result.size());
99 ASSERT_EQ(std::string(TO_NAMED_TEMPLATE_NAME), result[0].action.name);
100 }
101
TEST_F(LspTemplateRefTests,ConvertTemplateRefactor4)102 TEST_F(LspTemplateRefTests, ConvertTemplateRefactor4)
103 {
104 std::vector<std::string> files = {"ConvertTemplateRefactor4.ets"};
105 std::vector<std::string> texts = {R"(let d = /*7*/\'\$\' + text + \'\\\\\'/*8*/;)"};
106 auto filePaths = CreateTempFile(files, texts);
107 size_t const expectedFileCount = 1;
108 ASSERT_EQ(filePaths.size(), expectedFileCount);
109
110 auto pos = texts[0].find("/*7*/");
111 ASSERT_NE(pos, std::string::npos);
112 Initializer initializer = Initializer();
113 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
114 ark::es2panda::lsp::RefactorContext refactorContext;
115 refactorContext.context = ctx;
116 refactorContext.kind = std::string(TO_NAMED_TEMPLATE_KIND);
117 refactorContext.span.pos = pos + REFACTOR_TEMPLATE_POSITION_OFFSET;
118 auto result = GetApplicableRefactorsImpl(&refactorContext);
119
120 initializer.DestroyContext(ctx);
121 ASSERT_EQ(0, result.size());
122 }
123
TEST_F(LspTemplateRefTests,ConvertTemplateRefactor5)124 TEST_F(LspTemplateRefTests, ConvertTemplateRefactor5)
125 {
126 std::vector<std::string> files = {"ConvertTemplateRefactor5.ets"};
127 std::vector<std::string> texts = {R"(let e = /*9*/'\$\{' + text + "\}"/*10*/;)"};
128 auto filePaths = CreateTempFile(files, texts);
129 size_t const expectedFileCount = 1;
130 ASSERT_EQ(filePaths.size(), expectedFileCount);
131
132 auto pos = texts[0].find("/*9*/");
133 ASSERT_NE(pos, std::string::npos);
134 Initializer initializer = Initializer();
135 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
136 ark::es2panda::lsp::RefactorContext refactorContext;
137 refactorContext.context = ctx;
138 refactorContext.kind = std::string(TO_NAMED_TEMPLATE_KIND);
139 refactorContext.span.pos = pos + REFACTOR_TEMPLATE_POSITION_OFFSET;
140 auto result = GetApplicableRefactorsImpl(&refactorContext);
141
142 initializer.DestroyContext(ctx);
143 ASSERT_EQ(1, result.size());
144 ASSERT_EQ(std::string(TO_NAMED_TEMPLATE_NAME), result[0].action.name);
145 }
146
TEST_F(LspTemplateRefTests,ConvertTemplateRefactor6)147 TEST_F(LspTemplateRefTests, ConvertTemplateRefactor6)
148 {
149 std::vector<std::string> files = {"ConvertTemplateRefactor6.ets"};
150 std::vector<std::string> texts = {R"(let f = /*11*/ \'\\\$\{\' + text + \'\}\'/*12*/;)"};
151 auto filePaths = CreateTempFile(files, texts);
152 size_t const expectedFileCount = 1;
153 ASSERT_EQ(filePaths.size(), expectedFileCount);
154
155 auto pos = texts[0].find("/*11*/");
156 ASSERT_NE(pos, std::string::npos);
157 Initializer initializer = Initializer();
158 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
159 ark::es2panda::lsp::RefactorContext refactorContext;
160 refactorContext.context = ctx;
161 refactorContext.kind = std::string(TO_NAMED_TEMPLATE_KIND);
162 refactorContext.span.pos = pos + REFACTOR_TEMPLATE_POSITION_OFFSET;
163 auto result = GetApplicableRefactorsImpl(&refactorContext);
164 initializer.DestroyContext(ctx);
165 ASSERT_EQ(0, result.size());
166 }
167
TEST_F(LspTemplateRefTests,ConvertTemplateRefactor7)168 TEST_F(LspTemplateRefTests, ConvertTemplateRefactor7)
169 {
170 std::vector<std::string> files = {"ConvertTemplateRefactor7.ets"};
171 std::vector<std::string> texts = {R"(let g = /*13*/'\\\\$ + text + "\\\\"/*14*/;)"};
172 auto filePaths = CreateTempFile(files, texts);
173 size_t const expectedFileCount = 1;
174 ASSERT_EQ(filePaths.size(), expectedFileCount);
175
176 auto pos = texts[0].find("/*13*/");
177 ASSERT_NE(pos, std::string::npos);
178 Initializer initializer = Initializer();
179 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
180 ark::es2panda::lsp::RefactorContext refactorContext;
181 refactorContext.context = ctx;
182 refactorContext.kind = std::string(TO_NAMED_TEMPLATE_KIND);
183 refactorContext.span.pos = pos + REFACTOR_TEMPLATE_POSITION_OFFSET;
184 auto result = GetApplicableRefactorsImpl(&refactorContext);
185
186 initializer.DestroyContext(ctx);
187 ASSERT_EQ(0, result.size());
188 }
189
TEST_F(LspTemplateRefTests,ConvertTemplateRefactor8)190 TEST_F(LspTemplateRefTests, ConvertTemplateRefactor8)
191 {
192 std::vector<std::string> files = {"ConvertTemplateRefactor8.ets"};
193 std::vector<std::string> texts = {R"(let h = /*15*/"\\u0041\\u0061" + text + "\\0\\u0000"/*16*/;)"};
194 auto filePaths = CreateTempFile(files, texts);
195 size_t const expectedFileCount = 1;
196 ASSERT_EQ(filePaths.size(), expectedFileCount);
197
198 auto pos = texts[0].find("/*15*/");
199 ASSERT_NE(pos, std::string::npos);
200 Initializer initializer = Initializer();
201 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
202 ark::es2panda::lsp::RefactorContext refactorContext;
203 refactorContext.context = ctx;
204 refactorContext.kind = std::string(TO_NAMED_TEMPLATE_KIND);
205 refactorContext.span.pos = pos + REFACTOR_TEMPLATE_POSITION_OFFSET;
206 auto result = GetApplicableRefactorsImpl(&refactorContext);
207 initializer.DestroyContext(ctx);
208 ASSERT_EQ(1, result.size());
209 ASSERT_EQ(std::string(TO_NAMED_TEMPLATE_NAME), result[0].action.name);
210 }
211
TEST_F(LspTemplateRefTests,ConvertTemplateRefactor9)212 TEST_F(LspTemplateRefTests, ConvertTemplateRefactor9)
213 {
214 std::vector<std::string> files = {"ConvertTemplateRefactor9.ets"};
215 std::vector<std::string> texts = {R"(let i = /*17*/'\$\`' + text + "\`\\\\"/*18*/;)"};
216 auto filePaths = CreateTempFile(files, texts);
217 size_t const expectedFileCount = 1;
218 ASSERT_EQ(filePaths.size(), expectedFileCount);
219
220 auto pos = texts[0].find("/*17*/");
221 ASSERT_NE(pos, std::string::npos);
222 Initializer initializer = Initializer();
223 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
224 ark::es2panda::lsp::RefactorContext refactorContext;
225 refactorContext.context = ctx;
226 refactorContext.kind = std::string(TO_NAMED_TEMPLATE_KIND);
227 refactorContext.span.pos = pos + REFACTOR_TEMPLATE_POSITION_OFFSET;
228 auto result = GetApplicableRefactorsImpl(&refactorContext);
229 initializer.DestroyContext(ctx);
230 ASSERT_EQ(1, result.size());
231 ASSERT_EQ(std::string(TO_NAMED_TEMPLATE_NAME), result[0].action.name);
232 }
233
234 } // namespace