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