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