Files
Cursor Agentandrmcrackan 1652f63770 test(cli): replace obsolete DataTestMethod with TestMethod
MSTest 4 marks DataTestMethod obsolete (MSTEST0044); TestMethod + DataRow
is the supported form.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
2026-08-13 19:48:04 +00:00

216 lines
7.0 KiB
C#

using AssertionHelper;
using LibationCli;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Linq;
namespace LibationCli.Tests;
[TestClass]
public class CliCommandRouterTests
{
[TestMethod]
[DataRow("abs")]
[DataRow("help", "abs")]
[DataRow("abs", "--help")]
public void Abs_group_help_forms_request_group_help(params string[] args)
{
var route = CliCommandRouter.Route(args, CliCommandGroups.All);
Assert.AreEqual(CliRouteKind.GroupHelp, route.Kind);
route.Group!.Name.Should().Be("abs");
}
[TestMethod]
public void Abs_upload_rewrites_only_the_command_path()
{
var route = CliCommandRouter.Route(
["abs", "upload", "B017V4IM1G", "--id", "B000000001", "--id", "B000000002"],
CliCommandGroups.All);
CollectionAssert.AreEqual(
new[] { "upload", "B017V4IM1G", "--id", "B000000001", "--id", "B000000002" },
route.ParserArgs);
}
[TestMethod]
[DataRow(new[] { "help", "abs", "upload" }, new[] { "upload", "--help" })]
[DataRow(new[] { "abs", "upload", "--help" }, new[] { "upload", "--help" })]
[DataRow(new[] { "abs", "upload", "-h" }, new[] { "upload", "-h" })]
public void Nested_help_forms_resolve_to_upload(string[] input, string[] expected)
=> CollectionAssert.AreEqual(expected, CliCommandRouter.Route(input, CliCommandGroups.All).ParserArgs);
[TestMethod]
[DataRow("abs-upload", "--help")]
[DataRow("upload", "--help")]
public void Root_upload_aliases_are_rejected(params string[] args)
{
using var error = new StringWriter();
var outcome = Program.ParseInvocation(args, error);
Assert.AreEqual(ExitCode.ParseError, outcome.ExitCode);
Assert.IsFalse(error.ToString().Contains("--id", StringComparison.Ordinal));
}
[TestMethod]
[DataRow("--help")]
[DataRow("help")]
[DataRow("-h")]
public void Global_help_lists_the_abs_group_without_legacy_upload_verb(string helpArg)
{
using var error = new StringWriter();
var outcome = Program.ParseInvocation([helpArg], error);
Assert.AreEqual(ExitCode.ProcessCompletedSuccessfully, outcome.ExitCode);
StringAssert.Contains(error.ToString(), " abs Audiobookshelf commands.");
Assert.IsFalse(error.ToString().Contains("abs-upload", StringComparison.Ordinal));
}
[TestMethod]
public void Empty_args_lists_the_abs_group()
{
using var error = new StringWriter();
var outcome = Program.ParseInvocation([], error);
Assert.AreEqual(ExitCode.ParseError, outcome.ExitCode);
StringAssert.Contains(error.ToString(), "No verb selected");
StringAssert.Contains(error.ToString(), " abs Audiobookshelf commands.");
}
[TestMethod]
[DataRow("abs")]
[DataRow("help", "abs")]
[DataRow("abs", "--help")]
public void Abs_group_help_forms_are_handled_by_program(params string[] args)
{
using var error = new StringWriter();
var outcome = Program.ParseInvocation(args, error);
Assert.AreEqual(ExitCode.ProcessCompletedSuccessfully, outcome.ExitCode);
Assert.IsNull(outcome.Result);
StringAssert.Contains(error.ToString(), "Audiobookshelf commands.");
StringAssert.Contains(error.ToString(), "abs upload");
}
[TestMethod]
public void Nested_abs_upload_help_reaches_upload_help_path()
{
using var error = new StringWriter();
var outcome = Program.ParseInvocation(["abs", "upload", "--help"], error);
var output = error.ToString();
Assert.AreEqual(ExitCode.ProcessCompletedSuccessfully, outcome.ExitCode);
Assert.AreEqual(typeof(AbsUploadOptions), outcome.Result!.TypeInfo.Current);
StringAssert.Contains(output, "abs upload");
StringAssert.Contains(output, "Upload liberated audiobooks to Audiobookshelf.");
StringAssert.Contains(output, "--id");
Assert.IsFalse(output.Contains("\nupload\n", StringComparison.Ordinal));
}
[TestMethod]
public void Nested_abs_upload_parses_positional_and_repeatable_ids()
{
using var error = new StringWriter();
var outcome = Program.ParseInvocation(["abs", "upload", "B017V4IM1G", "--id", "B000000001", "--id", "B000000002"], error);
Assert.IsNull(outcome.ExitCode);
var options = outcome.Result!.Value as AbsUploadOptions;
Assert.IsNotNull(options);
CollectionAssert.AreEqual(new[] { "B017V4IM1G" }, options.Asins!.ToArray());
CollectionAssert.AreEqual(new[] { "B000000001", "B000000002" }, options.Ids!.ToArray());
}
[TestMethod]
public void Abs_upload_group_and_subcommand_are_case_insensitive()
{
using var error = new StringWriter();
var outcome = Program.ParseInvocation(["ABS", "UPLOAD", "B017V4IM1G"], error);
Assert.IsNull(outcome.ExitCode);
Assert.AreEqual(typeof(AbsUploadOptions), outcome.Result!.TypeInfo.Current);
}
[TestMethod]
[DataRow("help", "abs", "upload")]
[DataRow("abs", "upload", "-h")]
public void Additional_nested_upload_help_forms_are_handled_by_program(params string[] args)
{
using var error = new StringWriter();
var outcome = Program.ParseInvocation(args, error);
var output = error.ToString();
Assert.AreEqual(ExitCode.ProcessCompletedSuccessfully, outcome.ExitCode);
StringAssert.Contains(output, "abs upload");
StringAssert.Contains(output, "--id");
}
[TestMethod]
public void Unknown_abs_subcommand_writes_error_before_group_help_and_exits_parse_error()
{
using var error = new StringWriter();
var outcome = Program.ParseInvocation(["abs", "download"], error);
var output = error.ToString();
Assert.AreEqual(ExitCode.ParseError, outcome.ExitCode);
Assert.AreEqual("Unknown ABS command 'download'.", new StringReader(output).ReadLine());
StringAssert.Contains(output, "Audiobookshelf commands.");
}
[TestMethod]
public void Inverse_abs_help_upload_form_is_rejected()
{
using var error = new StringWriter();
var outcome = Program.ParseInvocation(["abs", "help", "upload"], error);
var output = error.ToString();
Assert.AreEqual(ExitCode.ParseError, outcome.ExitCode);
Assert.AreEqual("Unknown ABS command 'help'.", new StringReader(output).ReadLine());
StringAssert.Contains(output, "Audiobookshelf commands.");
}
[TestMethod]
public void Unknown_subcommand_uses_the_routed_group_name_in_diagnostic()
{
var group = new CliCommandGroup(
"library",
"Library commands.",
[new("sync", "library-sync", "Sync the library.", typeof(AbsUploadOptions))]);
using var error = new StringWriter();
var outcome = Program.ParseInvocation(["library", "delete"], error, [group]);
var output = error.ToString();
Assert.AreEqual(ExitCode.ParseError, outcome.ExitCode);
Assert.IsTrue(output.StartsWith($"Unknown LIBRARY command 'delete'.{Environment.NewLine}", StringComparison.Ordinal));
StringAssert.Contains(output, "Library commands.");
}
[TestMethod]
public void Non_group_command_passes_through_unchanged()
{
var route = CliCommandRouter.Route(["status", "--verbose"], CliCommandGroups.All);
Assert.AreEqual(CliRouteKind.PassThrough, route.Kind);
CollectionAssert.AreEqual(new[] { "status", "--verbose" }, route.ParserArgs);
}
[TestMethod]
public void Abs_unknown_subcommand_is_reported()
{
var route = CliCommandRouter.Route(["abs", "delete"], CliCommandGroups.All);
Assert.AreEqual(CliRouteKind.UnknownSubcommand, route.Kind);
route.Group!.Name.Should().Be("abs");
}
}