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