|
4 | 4 | file system paths, and shell commands. |
5 | 5 | """ |
6 | 6 |
|
| 7 | +import argparse |
7 | 8 | import dataclasses |
8 | 9 | import enum |
9 | 10 | import os |
|
15 | 16 |
|
16 | 17 | import cmd2 |
17 | 18 | from cmd2 import ( |
| 19 | + Choices, |
18 | 20 | CompletionItem, |
19 | 21 | Completions, |
20 | 22 | utils, |
@@ -1300,3 +1302,123 @@ def test_subcommand_tab_completion_with_no_completer_scu(scu_app) -> None: |
1300 | 1302 |
|
1301 | 1303 | completions = scu_app.complete(text, line, begidx, endidx) |
1302 | 1304 | assert not completions |
| 1305 | + |
| 1306 | + |
| 1307 | +def test_set_completion_item_text() -> None: |
| 1308 | + """Test setting CompletionItem.text and how it affects CompletionItem.display.""" |
| 1309 | + value = 5 |
| 1310 | + |
| 1311 | + # Don't provide text |
| 1312 | + item = CompletionItem(value=value) |
| 1313 | + assert item.text == str(value) |
| 1314 | + |
| 1315 | + # Provide text |
| 1316 | + item = CompletionItem(value=value, text="my_text") |
| 1317 | + assert item.text == "my_text" |
| 1318 | + |
| 1319 | + # Provide blank text |
| 1320 | + item = CompletionItem(value=value, text="") |
| 1321 | + assert item.text == "" |
| 1322 | + |
| 1323 | + |
| 1324 | +def test_replace_completion_item_text() -> None: |
| 1325 | + """Test replacing the value of CompletionItem.text""" |
| 1326 | + value = 5 |
| 1327 | + |
| 1328 | + # Replace text value |
| 1329 | + item = CompletionItem(value=value, text="my_text") |
| 1330 | + updated_item = dataclasses.replace(item, text="new_text") |
| 1331 | + assert item.text == "my_text" |
| 1332 | + assert item.display == "my_text" |
| 1333 | + |
| 1334 | + # Text should be updated and display should be the same |
| 1335 | + assert updated_item.text == "new_text" |
| 1336 | + assert updated_item.display == "my_text" |
| 1337 | + |
| 1338 | + # Replace text value with blank |
| 1339 | + item = CompletionItem(value=value, text="my_text") |
| 1340 | + updated_item = dataclasses.replace(item, text="") |
| 1341 | + assert item.text == "my_text" |
| 1342 | + assert item.display == "my_text" |
| 1343 | + |
| 1344 | + # Text should be updated and display should be the same |
| 1345 | + assert updated_item.text == "" |
| 1346 | + assert updated_item.display == "my_text" |
| 1347 | + |
| 1348 | + |
| 1349 | +def test_set_completion_item_display() -> None: |
| 1350 | + """Test setting CompletionItem.display and how it is affected by CompletionItem.text.""" |
| 1351 | + value = 5 |
| 1352 | + |
| 1353 | + # Don't provide text or display |
| 1354 | + value = 5 |
| 1355 | + item = CompletionItem(value=value) |
| 1356 | + assert item.text == str(value) |
| 1357 | + assert item.display == item.text |
| 1358 | + |
| 1359 | + # Don't provide display but provide text |
| 1360 | + item = CompletionItem(value=value, text="my_text") |
| 1361 | + assert item.text == "my_text" |
| 1362 | + assert item.display == item.text |
| 1363 | + |
| 1364 | + # Provide display |
| 1365 | + item = CompletionItem(value=value, text="my_text", display="my_display") |
| 1366 | + assert item.text == "my_text" |
| 1367 | + assert item.display == "my_display" |
| 1368 | + |
| 1369 | + # Provide blank display |
| 1370 | + item = CompletionItem(value=value, text="my_text", display="") |
| 1371 | + assert item.text == "my_text" |
| 1372 | + assert item.display == "" |
| 1373 | + |
| 1374 | + |
| 1375 | +def test_replace_completion_item_display() -> None: |
| 1376 | + """Test replacing the value of CompletionItem.display""" |
| 1377 | + value = 5 |
| 1378 | + |
| 1379 | + # Replace display value |
| 1380 | + item = CompletionItem(value=value, display="my_display") |
| 1381 | + updated_item = dataclasses.replace(item, display="new_display") |
| 1382 | + |
| 1383 | + assert item.display == "my_display" |
| 1384 | + assert updated_item.display == "new_display" |
| 1385 | + |
| 1386 | + # Replace display value with blank |
| 1387 | + item = CompletionItem(value=value, display="my_display") |
| 1388 | + updated_item = dataclasses.replace(item, display="") |
| 1389 | + |
| 1390 | + assert item.display == "my_display" |
| 1391 | + assert updated_item.display == "" |
| 1392 | + |
| 1393 | + |
| 1394 | +def test_full_prefix_removal() -> None: |
| 1395 | + """Verify that Cmd._perform_completion() can clear item.text when |
| 1396 | + text_to_remove matches item.text exactly. This occurs when completing |
| 1397 | + a nested quoted string where the command line already contains the |
| 1398 | + full unquoted content of the completion match. |
| 1399 | + """ |
| 1400 | + |
| 1401 | + class TestApp(cmd2.Cmd): |
| 1402 | + def get_choices(self) -> Choices: |
| 1403 | + """Return choices.""" |
| 1404 | + choices = ["'This is a quoted item'"] |
| 1405 | + return cmd2.Choices.from_values(choices) |
| 1406 | + |
| 1407 | + parser = cmd2.Cmd2ArgumentParser() |
| 1408 | + parser.add_argument("arg", choices_provider=get_choices) |
| 1409 | + |
| 1410 | + @cmd2.with_argparser(parser) |
| 1411 | + def do_command(self, args: argparse.Namespace) -> None: |
| 1412 | + """Test stuff.""" |
| 1413 | + |
| 1414 | + text = "" |
| 1415 | + line = "command \"'This is a quoted item'" |
| 1416 | + endidx = len(line) |
| 1417 | + begidx = endidx |
| 1418 | + |
| 1419 | + app = TestApp() |
| 1420 | + completions = app.complete(text, line, begidx, endidx) |
| 1421 | + assert len(completions) == 1 |
| 1422 | + |
| 1423 | + item = completions[0] |
| 1424 | + assert item.text == "" |
0 commit comments