1//===-- CompletionRequestTest.cpp -----------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "gtest/gtest.h"
10
11#include "lldb/Utility/CompletionRequest.h"
12using namespace lldb_private;
13
14TEST(CompletionRequest, Constructor) {
15 std::string command = "a bad c";
16 const unsigned cursor_pos = 3;
17 const size_t arg_index = 1;
18 StringList matches;
19 CompletionResult result;
20
21 CompletionRequest request(command, cursor_pos, result);
22 result.GetMatches(matches);
23
24 EXPECT_EQ(request.GetRawLine(), "a b");
25 EXPECT_EQ(request.GetRawLineWithUnusedSuffix(), command);
26 EXPECT_EQ(request.GetRawCursorPos(), cursor_pos);
27 EXPECT_EQ(request.GetCursorIndex(), arg_index);
28
29 EXPECT_EQ(request.GetParsedLine().GetArgumentCount(), 2u);
30 EXPECT_EQ(request.GetCursorArgumentPrefix().str(), "b");
31}
32
33TEST(CompletionRequest, FakeLastArg) {
34 // We insert an empty fake argument into the argument list when the
35 // cursor is after a space.
36 std::string command = "a bad c ";
37 const unsigned cursor_pos = command.size();
38 CompletionResult result;
39
40 CompletionRequest request(command, cursor_pos, result);
41
42 EXPECT_EQ(request.GetRawLine(), command);
43 EXPECT_EQ(request.GetRawLineWithUnusedSuffix(), command);
44 EXPECT_EQ(request.GetRawCursorPos(), cursor_pos);
45 EXPECT_EQ(request.GetCursorIndex(), 3U);
46
47 EXPECT_EQ(request.GetParsedLine().GetArgumentCount(), 4U);
48 EXPECT_EQ(request.GetCursorArgumentPrefix().str(), "");
49}
50
51TEST(CompletionRequest, TryCompleteCurrentArgGood) {
52 std::string command = "a bad c";
53 StringList matches, descriptions;
54 CompletionResult result;
55
56 CompletionRequest request(command, 3, result);
57 request.TryCompleteCurrentArg(completion: "boo", description: "car");
58 result.GetMatches(matches);
59 result.GetDescriptions(descriptions);
60
61 EXPECT_EQ(1U, result.GetResults().size());
62 EXPECT_STREQ("boo", matches.GetStringAtIndex(0U));
63 EXPECT_EQ(1U, descriptions.GetSize());
64 EXPECT_STREQ("car", descriptions.GetStringAtIndex(0U));
65}
66
67TEST(CompletionRequest, TryCompleteCurrentArgBad) {
68 std::string command = "a bad c";
69 CompletionResult result;
70
71 CompletionRequest request(command, 3, result);
72 request.TryCompleteCurrentArg(completion: "car", description: "card");
73
74 EXPECT_EQ(0U, result.GetResults().size());
75}
76
77TEST(CompletionRequest, TryCompleteCurrentArgMode) {
78 std::string command = "a bad c";
79 CompletionResult result;
80
81 CompletionRequest request(command, 3, result);
82 request.TryCompleteCurrentArg<CompletionMode::Partial>(completion: "bar", description: "bard");
83
84 EXPECT_EQ(1U, result.GetResults().size());
85 EXPECT_EQ(CompletionMode::Partial, result.GetResults()[0].GetMode());
86}
87
88TEST(CompletionRequest, ShiftArguments) {
89 std::string command = "a bad c";
90 const unsigned cursor_pos = 3;
91 const size_t arg_index = 1;
92 StringList matches;
93 CompletionResult result;
94
95 CompletionRequest request(command, cursor_pos, result);
96 result.GetMatches(matches);
97
98 EXPECT_EQ(request.GetRawLine(), "a b");
99 EXPECT_EQ(request.GetRawLineWithUnusedSuffix(), command);
100 EXPECT_EQ(request.GetRawCursorPos(), cursor_pos);
101 EXPECT_EQ(request.GetCursorIndex(), arg_index);
102
103 EXPECT_EQ(request.GetParsedLine().GetArgumentCount(), 2u);
104 EXPECT_STREQ(request.GetParsedLine().GetArgumentAtIndex(1), "b");
105
106 // Shift away the 'a' argument.
107 request.ShiftArguments();
108
109 // The raw line/cursor stays identical.
110 EXPECT_EQ(request.GetRawLine(), "a b");
111 EXPECT_EQ(request.GetRawLineWithUnusedSuffix(), command);
112 EXPECT_EQ(request.GetRawCursorPos(), cursor_pos);
113
114 // Partially parsed line and cursor should be updated.
115 EXPECT_EQ(request.GetCursorIndex(), arg_index - 1U);
116 EXPECT_EQ(request.GetParsedLine().GetArgumentCount(), 1u);
117 EXPECT_EQ(request.GetCursorArgumentPrefix().str(), "b");
118}
119
120TEST(CompletionRequest, DuplicateFiltering) {
121 std::string command = "a bad c";
122 const unsigned cursor_pos = 3;
123 StringList matches;
124
125 CompletionResult result;
126 CompletionRequest request(command, cursor_pos, result);
127 result.GetMatches(matches);
128
129 EXPECT_EQ(0U, result.GetNumberOfResults());
130
131 // Add foo twice
132 request.AddCompletion(completion: "foo");
133 result.GetMatches(matches);
134
135 EXPECT_EQ(1U, result.GetNumberOfResults());
136 EXPECT_EQ(1U, matches.GetSize());
137 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
138
139 request.AddCompletion(completion: "foo");
140 result.GetMatches(matches);
141
142 EXPECT_EQ(1U, result.GetNumberOfResults());
143 EXPECT_EQ(1U, matches.GetSize());
144 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
145
146 // Add bar twice
147 request.AddCompletion(completion: "bar");
148 result.GetMatches(matches);
149
150 EXPECT_EQ(2U, result.GetNumberOfResults());
151 EXPECT_EQ(2U, matches.GetSize());
152 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
153 EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
154
155 request.AddCompletion(completion: "bar");
156 result.GetMatches(matches);
157
158 EXPECT_EQ(2U, result.GetNumberOfResults());
159 EXPECT_EQ(2U, matches.GetSize());
160 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
161 EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
162
163 // Add foo again.
164 request.AddCompletion(completion: "foo");
165 result.GetMatches(matches);
166
167 EXPECT_EQ(2U, result.GetNumberOfResults());
168 EXPECT_EQ(2U, matches.GetSize());
169 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
170 EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
171
172 // Add something with an existing prefix
173 request.AddCompletion(completion: "foobar");
174 result.GetMatches(matches);
175
176 EXPECT_EQ(3U, result.GetNumberOfResults());
177 EXPECT_EQ(3U, matches.GetSize());
178 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
179 EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
180 EXPECT_STREQ("foobar", matches.GetStringAtIndex(2));
181}
182
183TEST(CompletionRequest, DuplicateFilteringWithComments) {
184 std::string command = "a bad c";
185 const unsigned cursor_pos = 3;
186 StringList matches, descriptions;
187
188 CompletionResult result;
189 CompletionRequest request(command, cursor_pos, result);
190 result.GetMatches(matches);
191 result.GetDescriptions(descriptions);
192
193 EXPECT_EQ(0U, result.GetNumberOfResults());
194
195 // Add foo twice with same comment
196 request.AddCompletion(completion: "foo", description: "comment");
197 result.GetMatches(matches);
198 result.GetDescriptions(descriptions);
199
200 EXPECT_EQ(1U, result.GetNumberOfResults());
201 EXPECT_EQ(1U, matches.GetSize());
202 EXPECT_EQ(1U, descriptions.GetSize());
203 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
204 EXPECT_STREQ("comment", descriptions.GetStringAtIndex(0));
205
206 request.AddCompletion(completion: "foo", description: "comment");
207 result.GetMatches(matches);
208 result.GetDescriptions(descriptions);
209
210 EXPECT_EQ(1U, result.GetNumberOfResults());
211 EXPECT_EQ(1U, matches.GetSize());
212 EXPECT_EQ(1U, descriptions.GetSize());
213 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
214 EXPECT_STREQ("comment", descriptions.GetStringAtIndex(0));
215
216 // Add bar twice with different comments
217 request.AddCompletion(completion: "bar", description: "comment");
218 result.GetMatches(matches);
219 result.GetDescriptions(descriptions);
220
221 EXPECT_EQ(2U, result.GetNumberOfResults());
222 EXPECT_EQ(2U, matches.GetSize());
223 EXPECT_EQ(2U, descriptions.GetSize());
224 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
225 EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
226
227 request.AddCompletion(completion: "bar", description: "another comment");
228 result.GetMatches(matches);
229 result.GetDescriptions(descriptions);
230
231 EXPECT_EQ(3U, result.GetNumberOfResults());
232 EXPECT_EQ(3U, matches.GetSize());
233 EXPECT_EQ(3U, descriptions.GetSize());
234 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
235 EXPECT_STREQ("comment", descriptions.GetStringAtIndex(0));
236 EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
237 EXPECT_STREQ("comment", descriptions.GetStringAtIndex(1));
238 EXPECT_STREQ("bar", matches.GetStringAtIndex(2));
239 EXPECT_STREQ("another comment", descriptions.GetStringAtIndex(2));
240
241 // Add foo again with no comment
242 request.AddCompletion(completion: "foo");
243 result.GetMatches(matches);
244 result.GetDescriptions(descriptions);
245
246 EXPECT_EQ(4U, result.GetNumberOfResults());
247 EXPECT_EQ(4U, matches.GetSize());
248 EXPECT_EQ(4U, descriptions.GetSize());
249 EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
250 EXPECT_STREQ("comment", descriptions.GetStringAtIndex(0));
251 EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
252 EXPECT_STREQ("comment", descriptions.GetStringAtIndex(1));
253 EXPECT_STREQ("bar", matches.GetStringAtIndex(2));
254 EXPECT_STREQ("another comment", descriptions.GetStringAtIndex(2));
255 EXPECT_STREQ("foo", matches.GetStringAtIndex(3));
256 EXPECT_STREQ("", descriptions.GetStringAtIndex(3));
257}
258
259TEST(CompletionRequest, TestCompletionOwnership) {
260 std::string command = "a bad c";
261 const unsigned cursor_pos = 3;
262 StringList matches;
263
264 CompletionResult result;
265 CompletionRequest request(command, cursor_pos, result);
266
267 std::string Temporary = "bar";
268 request.AddCompletion(completion: Temporary);
269 // Manipulate our completion. The request should have taken a copy, so that
270 // shouldn't influence anything.
271 Temporary[0] = 'f';
272
273 result.GetMatches(matches);
274 EXPECT_EQ(1U, result.GetNumberOfResults());
275 EXPECT_STREQ("bar", matches.GetStringAtIndex(0));
276}
277

source code of lldb/unittests/Utility/CompletionRequestTest.cpp