From c70a8b8fc55bfa388773f923e648a9f7e51287b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Luthi?= Date: Tue, 10 Sep 2024 14:01:32 +0200 Subject: [PATCH] Improve exception if a (multi)selection prompt is used incorrectly Before this commit, the selection prompt would throw an `InvalidOperationException` (Sequence contains no elements) and the multi selection prompt would throw an `ArgumentOutOfRangeException` (Index was out of range. Must be non-negative and less than the size of the collection.) Both would occur because the prompts were never meant to be empty. --- src/Spectre.Console/Prompts/List/ListPrompt.cs | 5 +++++ .../Unit/Prompts/MultiSelectionPromptTests.cs | 17 +++++++++++++++++ .../Unit/Prompts/SelectionPromptTests.cs | 16 ++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/Spectre.Console/Prompts/List/ListPrompt.cs b/src/Spectre.Console/Prompts/List/ListPrompt.cs index c668502..ca0fa3f 100644 --- a/src/Spectre.Console/Prompts/List/ListPrompt.cs +++ b/src/Spectre.Console/Prompts/List/ListPrompt.cs @@ -42,6 +42,11 @@ internal sealed class ListPrompt } var nodes = tree.Traverse().ToList(); + if (nodes.Count == 0) + { + throw new InvalidOperationException("Cannot show an empty selection prompt. Please call the AddChoice() method to configure the prompt."); + } + var state = new ListPromptState(nodes, converter, _strategy.CalculatePageSize(_console, nodes.Count, requestedPageSize), wrapAround, selectionMode, skipUnselectableItems, searchEnabled); var hook = new ListPromptRenderHook(_console, () => BuildRenderable(state)); diff --git a/src/Tests/Spectre.Console.Tests/Unit/Prompts/MultiSelectionPromptTests.cs b/src/Tests/Spectre.Console.Tests/Unit/Prompts/MultiSelectionPromptTests.cs index 405e154..43b1d5c 100644 --- a/src/Tests/Spectre.Console.Tests/Unit/Prompts/MultiSelectionPromptTests.cs +++ b/src/Tests/Spectre.Console.Tests/Unit/Prompts/MultiSelectionPromptTests.cs @@ -127,6 +127,23 @@ public sealed class MultiSelectionPromptTests // Then action.ShouldThrow(); } + + [Fact] public void Should_Throw_Meaningful_Exception_For_Empty_Prompt() + { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Spacebar); + + var prompt = new MultiSelectionPrompt(); + + // When + Action action = () => prompt.Show(console); + + // Then + var exception = action.ShouldThrow(); + exception.Message.ShouldBe("Cannot show an empty selection prompt. Please call the AddChoice() method to configure the prompt."); + } } file sealed class CustomItem diff --git a/src/Tests/Spectre.Console.Tests/Unit/Prompts/SelectionPromptTests.cs b/src/Tests/Spectre.Console.Tests/Unit/Prompts/SelectionPromptTests.cs index 9d3e7ac..2e066c5 100644 --- a/src/Tests/Spectre.Console.Tests/Unit/Prompts/SelectionPromptTests.cs +++ b/src/Tests/Spectre.Console.Tests/Unit/Prompts/SelectionPromptTests.cs @@ -114,6 +114,22 @@ public sealed class SelectionPromptTests // Then selection.ShouldBe(choices[1]); } + + [Fact] public void Should_Throw_Meaningful_Exception_For_Empty_Prompt() + { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + + var prompt = new SelectionPrompt(); + + // When + Action action = () => prompt.Show(console); + + // Then + var exception = action.ShouldThrow(); + exception.Message.ShouldBe("Cannot show an empty selection prompt. Please call the AddChoice() method to configure the prompt."); + } } file sealed class CustomSelectionItem