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