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