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 "../lsp_api_test.h"
17
18 #include <gtest/gtest.h>
19
20 #include "ir/astNode.h"
21 #include "lsp/include/register_code_fix/ui_plugin_suggest.h"
22 #include "lsp/include/internal_api.h"
23 #include "public/es2panda_lib.h"
24 #include "public/public.h"
25
26 namespace {
27
28 class LspUISuggestionTests : public LSPAPITests {};
29
30 using ark::es2panda::lsp::Initializer;
31
AssertDiagnosticContainsCodeAndMessage(const DiagnosticReferences & suggest,const int code,const char * dmessage)32 void AssertDiagnosticContainsCodeAndMessage(const DiagnosticReferences &suggest, const int code, const char *dmessage)
33 {
34 bool found = false;
35 for (auto diag : suggest.diagnostic) {
36 if (std::get<int>(diag.code_) == code) {
37 if (diag.message_ == dmessage) {
38 found = true;
39 }
40 }
41 }
42 ASSERT_TRUE(found) << "Expected code: " << code << " not found";
43 }
44
TEST_F(LspUISuggestionTests,UIPluginsErrorTest1)45 TEST_F(LspUISuggestionTests, UIPluginsErrorTest1)
46 {
47 using ark::es2panda::ir::AstNode;
48 using ark::es2panda::public_lib::Context;
49 Initializer initializer = Initializer();
50 std::vector<std::string> files = {"ui_error1.ets"};
51 std::vector<std::string> texts = {R"delimiter(function main() {})delimiter"};
52 auto filePaths = CreateTempFile(files, texts);
53 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
54 LSPAPI const *lspApi = GetImpl();
55 int const offset = 11;
56 // NOLINTNEXTLINE
57 const char *params[] = {
58 "a",
59 };
60 const char *dmessage1 = "origin {}";
61 const size_t argc1 = 1;
62 const char *substitutionCode = "replace b";
63 const char *dmessage2 = "error";
64 const size_t argc0 = 0;
65 const size_t index1 = 1;
66 const size_t line1 = 0;
67 const size_t index2 = 15;
68 const size_t line2 = 0;
69 const int code = 4000;
70 auto suggestionkind = initializer.CreateDiagnosticKind(ctx, dmessage1, ES2PANDA_PLUGIN_SUGGESTION);
71 auto suggestionInfo = initializer.CreateSuggestionInfo(ctx, suggestionkind, params, argc1, substitutionCode);
72 auto diagnostikind = initializer.CreateDiagnosticKind(ctx, dmessage2, ES2PANDA_PLUGIN_ERROR);
73 auto diagnosticInfo = initializer.CreateDiagnosticInfo(ctx, diagnostikind, nullptr, argc0);
74 es2panda_SourcePosition *left = initializer.CreateSourcePosition(ctx, index1, line1);
75 es2panda_SourcePosition *right = initializer.CreateSourcePosition(ctx, index2, line2);
76 es2panda_SourceRange *range = initializer.CreateSourceRange(ctx, left, right);
77 initializer.LogDiagnosticWithSuggestion(ctx, diagnosticInfo, suggestionInfo, range);
78 auto suggest = lspApi->getSyntacticDiagnostics(ctx);
79 AssertDiagnosticContainsCodeAndMessage(suggest, code, dmessage2);
80 auto result = ark::es2panda::lsp::UIPluginSuggest::GetUIPluginCodeFixes(ctx, offset, false);
81 ASSERT_EQ(result.at(0).textChanges.at(0).newText, substitutionCode);
82 std::vector<int> codes;
83 codes.emplace_back(code);
84 CodeFixOptions emptyOptions;
85 auto fix = ark::es2panda::lsp::GetCodeFixesAtPositionImpl(ctx, index1, index2, codes, emptyOptions);
86 ASSERT_EQ(fix.at(0).changes_.at(0).textChanges.at(0).newText, substitutionCode);
87 ASSERT_EQ(fix.at(0).changes_.at(0).textChanges.at(0).span.length, index2 - index1);
88
89 initializer.DestroyContext(ctx);
90 }
91
TEST_F(LspUISuggestionTests,UIPluginsErrorTest2)92 TEST_F(LspUISuggestionTests, UIPluginsErrorTest2)
93 {
94 using ark::es2panda::ir::AstNode;
95 using ark::es2panda::public_lib::Context;
96 Initializer initializer = Initializer();
97 std::vector<std::string> files = {"ui_error2.ets"};
98 std::vector<std::string> texts = {R"delimiter(function main() {})delimiter"};
99 auto filePaths = CreateTempFile(files, texts);
100 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
101 LSPAPI const *lspApi = GetImpl();
102 // NOLINTNEXTLINE
103 const char *params[] = {
104 "a",
105 };
106 const size_t argc1 = 1;
107 const char *dmessage2 = "origin {}";
108 const char *dmessage1 = "origin a";
109 const size_t index1 = 0;
110 const size_t line1 = 0;
111 const int code = 4000;
112 auto diagnostikind = initializer.CreateDiagnosticKind(ctx, dmessage2, ES2PANDA_PLUGIN_ERROR);
113 es2panda_SourcePosition *left = initializer.CreateSourcePosition(ctx, index1, line1);
114
115 initializer.LogDiagnostic(ctx, diagnostikind, params, argc1, left);
116 auto suggest = lspApi->getSyntacticDiagnostics(ctx);
117 AssertDiagnosticContainsCodeAndMessage(suggest, code, dmessage1);
118 std::vector<int> codes;
119 codes.emplace_back(code);
120 CodeFixOptions emptyOptions;
121 auto fix = ark::es2panda::lsp::GetCodeFixesAtPositionImpl(ctx, index1, index1, codes, emptyOptions);
122 ASSERT_TRUE(fix.at(0).changes_.at(0).textChanges.empty());
123
124 initializer.DestroyContext(ctx);
125 }
126
TEST_F(LspUISuggestionTests,UIPluginsErrorTest3)127 TEST_F(LspUISuggestionTests, UIPluginsErrorTest3)
128 {
129 using ark::es2panda::ir::AstNode;
130 using ark::es2panda::public_lib::Context;
131 Initializer initializer = Initializer();
132 std::vector<std::string> files = {"ui_error3.ets"};
133 std::vector<std::string> texts = {R"delimiter(function main() {})delimiter"};
134 auto filePaths = CreateTempFile(files, texts);
135 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
136 LSPAPI const *lspApi = GetImpl();
137 const char *dmessage1 = "origin a";
138 const char *substitutionCode = "replace b";
139 const char *dmessage2 = "error";
140 const size_t argc0 = 0;
141 const size_t index1 = 0;
142 const size_t line1 = 0;
143 const size_t index2 = 15;
144 const size_t line2 = 0;
145 const int code = 4000;
146 auto suggestionkind = initializer.CreateDiagnosticKind(ctx, dmessage1, ES2PANDA_PLUGIN_SUGGESTION);
147 auto suggestionInfo = initializer.CreateSuggestionInfo(ctx, suggestionkind, nullptr, argc0, substitutionCode);
148 auto diagnostikind = initializer.CreateDiagnosticKind(ctx, dmessage2, ES2PANDA_PLUGIN_ERROR);
149 auto diagnosticInfo = initializer.CreateDiagnosticInfo(ctx, diagnostikind, nullptr, argc0);
150 es2panda_SourcePosition *left = initializer.CreateSourcePosition(ctx, index1, line1);
151 es2panda_SourcePosition *right = initializer.CreateSourcePosition(ctx, index2, line2);
152 es2panda_SourceRange *range = initializer.CreateSourceRange(ctx, left, right);
153 initializer.LogDiagnosticWithSuggestion(ctx, diagnosticInfo, suggestionInfo, range);
154
155 const char *substitutionCode2 = "replace c";
156 auto suggestionkind2 = initializer.CreateDiagnosticKind(ctx, dmessage1, ES2PANDA_PLUGIN_SUGGESTION);
157 auto suggestionInfo2 = initializer.CreateSuggestionInfo(ctx, suggestionkind2, nullptr, argc0, substitutionCode2);
158 auto diagnostikind2 = initializer.CreateDiagnosticKind(ctx, dmessage2, ES2PANDA_PLUGIN_ERROR);
159 auto diagnosticInfo2 = initializer.CreateDiagnosticInfo(ctx, diagnostikind2, nullptr, argc0);
160 es2panda_SourcePosition *left2 = initializer.CreateSourcePosition(ctx, index1, line1);
161 es2panda_SourcePosition *right2 = initializer.CreateSourcePosition(ctx, index2, line2);
162 es2panda_SourceRange *range2 = initializer.CreateSourceRange(ctx, left2, right2);
163 initializer.LogDiagnosticWithSuggestion(ctx, diagnosticInfo2, suggestionInfo2, range2);
164
165 auto suggest = lspApi->getSyntacticDiagnostics(ctx);
166 AssertDiagnosticContainsCodeAndMessage(suggest, code, dmessage2);
167 AssertDiagnosticContainsCodeAndMessage(suggest, code, dmessage2);
168 std::vector<int> codes;
169 codes.emplace_back(code);
170 CodeFixOptions emptyOptions;
171 const std::string fixId = "UIPluginSuggest";
172 auto fix = ark::es2panda::lsp::GetCodeFixesAtPositionImpl(ctx, index1, index1, codes, emptyOptions);
173 ASSERT_FALSE(fix.at(0).changes_.at(0).textChanges.empty());
174 auto fixAll = ark::es2panda::lsp::GetCombinedCodeFixImpl(ctx, fixId, emptyOptions);
175 const size_t expectedCount = 2;
176 ASSERT_EQ(fixAll.changes_.size(), expectedCount);
177
178 initializer.DestroyContext(ctx);
179 }
180
181 } // namespace
182