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"
12 using namespace lldb_private;
13 
TEST(CompletionRequest,Constructor)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   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 
TEST(CompletionRequest,FakeLastArg)33 TEST(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 
TEST(CompletionRequest,TryCompleteCurrentArgGood)51 TEST(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("boo", "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 
TEST(CompletionRequest,TryCompleteCurrentArgBad)67 TEST(CompletionRequest, TryCompleteCurrentArgBad) {
68   std::string command = "a bad c";
69   CompletionResult result;
70 
71   CompletionRequest request(command, 3, result);
72   request.TryCompleteCurrentArg("car", "card");
73 
74   EXPECT_EQ(0U, result.GetResults().size());
75 }
76 
TEST(CompletionRequest,TryCompleteCurrentArgMode)77 TEST(CompletionRequest, TryCompleteCurrentArgMode) {
78   std::string command = "a bad c";
79   CompletionResult result;
80 
81   CompletionRequest request(command, 3, result);
82   request.TryCompleteCurrentArg<CompletionMode::Partial>("bar", "bard");
83 
84   EXPECT_EQ(1U, result.GetResults().size());
85   EXPECT_EQ(CompletionMode::Partial, result.GetResults()[0].GetMode());
86 }
87 
TEST(CompletionRequest,ShiftArguments)88 TEST(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 
TEST(CompletionRequest,DuplicateFiltering)120 TEST(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("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("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("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("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("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("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 
TEST(CompletionRequest,DuplicateFilteringWithComments)183 TEST(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("foo", "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("foo", "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("bar", "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("bar", "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("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 
TEST(CompletionRequest,TestCompletionOwnership)259 TEST(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(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