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 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 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 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 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 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 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 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 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 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