From 42fba23dd6d7dcdcd6f77a8ff6b3cbe376c1e932 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Sat, 25 Sep 2021 23:03:50 +1000 Subject: [PATCH] WIP before line endings normalisation --- .vscode/launch.json | 24 +++ tests/console.tests/CommandTreeTests.cs | 216 ++++++++++++++++++++++- tests/console.tests/console.tests.csproj | 2 +- 3 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..be74324 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/tests/console.tests/bin/Debug/net5.0/console.tests.dll", + "args": [], + "cwd": "${workspaceFolder}/tests/console.tests", + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/tests/console.tests/CommandTreeTests.cs b/tests/console.tests/CommandTreeTests.cs index 4104d63..a781ea8 100644 --- a/tests/console.tests/CommandTreeTests.cs +++ b/tests/console.tests/CommandTreeTests.cs @@ -1,18 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; using NUnit.Framework; namespace Shamir.Console.Tests { - public class Tests + public class CommandTreeTests { [SetUp] public void Setup() { + tree = new DefaultCommandTree( + "root", + "top level", + ImmutableArray.Create( + new DefaultCommandTree( + "bar", + "child command tree", + ImmutableArray.Empty, + ImmutableArray.Create( + new SimpleTextCommand("one", "bar/1 command"), + new SimpleTextCommand("two", "bar/2 command") + ))), + ImmutableArray.Create( + new SimpleTextCommand("foo", "foo command") + )); } + ICommandTree tree; + [Test] - public void Test1() + public void ConstructsHelpTextWithNoArgs() { - Assert.Pass(); + var command = tree.FindCommand(Array.Empty()); + Assert.That(command, Is.InstanceOf()); + var helpText = ((DefaultHelpTextCommand)command).GetHelpText(); + Assert.That(helpText, Is.EqualTo(@" +Group + root : top level + +Subgroups: + bar : child command tree + +Commands: + foo : foo command +".TrimStart())); + } + + [Test] + public void ConstructsHelpTextForSubTree() + { + var command = tree.FindCommand(new[] { "bar" }); + Assert.That(command, Is.InstanceOf()); + var helpText = ((DefaultHelpTextCommand)command).GetHelpText(); + Assert.That(helpText, Is.EqualTo(@" +Group + root bar : child command tree + +Commands: + one : bar/1 command + two : bar/1 command +")); + } + + [TestCase((object)new string[] { "foo" }, ExpectedResult = "foo command")] + [TestCase((object)new string[] { "bar", "one" }, ExpectedResult = "bar/1 command")] + [TestCase((object)new string[] { "bar", "two" }, ExpectedResult = "bar/2 command")] + public string FindsCommand(string[] args) + { + var command = tree.FindCommand(args); + return command?.Description; + } + + + class SimpleTextCommand : ICommand + { + public SimpleTextCommand(string name, string description) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + Description = description ?? throw new ArgumentNullException(nameof(description)); + } + + public string Name { get; } + + public string Description { get; } + + public ValueTask ExecuteAsync() + { + return ValueTask.FromResult(0); + } + } + } + + interface IOperationsNode + { + string Name { get; } + string Description { get; } + } + + interface ICommand : IOperationsNode + { + ValueTask ExecuteAsync(); + } + + interface ICommandTree : IOperationsNode + { + ImmutableArray SubTrees { get; } + ImmutableArray Commands { get; } + ICommand FindCommand(ReadOnlySpan args); + } + + class DefaultCommandTree : ICommandTree + { + public DefaultCommandTree(string name, string description, ImmutableArray subtrees, ImmutableArray commands) + { + this.Name = name ?? throw new ArgumentNullException(nameof(name)); + this.Description = description ?? throw new ArgumentNullException(nameof(description)); + this.SubTrees = subtrees; + this.Commands = commands; + } + + public string Name { get; } + public string Description { get; } + public ImmutableArray SubTrees { get; } + public ImmutableArray Commands { get; } + + public ICommand FindCommand(ReadOnlySpan args) + { + if (args.Length > 0) + { + foreach (var command in Commands) + { + if (command.Name == args[0]) + { + return command; + } + } + + foreach (var tree in SubTrees) + { + if (tree.Name == args[0]) + { + return tree.FindCommand(args[1..]); + } + } + } + + return new DefaultHelpTextCommand(this); + } + } + + class DefaultHelpTextCommand : ICommand + { + public DefaultHelpTextCommand(ICommandTree tree) + { + this.CommandTree = tree ?? throw new ArgumentNullException(nameof(tree)); + } + + public string Name => "help"; + public string Description => "Print help text"; + + public ICommandTree CommandTree { get; } + + public ValueTask ExecuteAsync() + { + System.Console.Error.WriteLine(GetHelpText()); + return ValueTask.FromResult(1); // TODO: const + } + + public string GetHelpText() => CommandTree.BuildHelpText(); + } + + static class ICommandTreeExtensions + { + public static string BuildHelpText(this ICommandTree tree) + { + var sb = new StringBuilder(); + sb.AppendLine("Group"); + sb.Append(" "); + sb.AppendLine(tree.Name); + sb.AppendLine(); + + if (!tree.SubTrees.IsEmpty) + { + sb.AppendLine("Subgroups:"); + + var maxSpacing = tree.SubTrees.Max(c => c.Name.Length) + 1; + + foreach (var child in tree.SubTrees) + { + sb.Append(" "); + sb.Append(child.Name); + for (var i = 0; i < maxSpacing; i++) + { + sb.Append(' '); + } + sb.Append(": "); + sb.AppendLine(child.Description); + } + } + + if (!tree.Commands.IsEmpty) + { + sb.AppendLine("Commands:"); + + var maxSpacing = tree.Commands.Max(c => c.Name.Length) + 1; + + foreach (var command in tree.Commands) + { + sb.Append(" "); + sb.Append(command.Name); + for (var i = 0; i < maxSpacing; i++) + { + sb.Append(' '); + } + sb.Append(": "); + sb.AppendLine(command.Description); + } + } + + return sb.ToString(); } } } \ No newline at end of file diff --git a/tests/console.tests/console.tests.csproj b/tests/console.tests/console.tests.csproj index 4a6731e..16748f3 100644 --- a/tests/console.tests/console.tests.csproj +++ b/tests/console.tests/console.tests.csproj @@ -3,7 +3,7 @@ net5.0 false - Shamir.Console.Tests + Shamir.Console.Tests