Files
SabreTools.CommandLine/SabreTools.CommandLine.Test/Features/ManpageTests.cs
gmipf 754aa6bc32 Add man page generation from the command-line model (#2)
* Add man page generation from the command-line model

Add CommandSet.OutputManPage (string and file overloads), a ManPageInfo
type for document-level metadata, a reference ManPage feature invoked as a
man command, and UserInput.FormatManPage which reuses FormatFlags so the
page cannot drift from --help. Output uses only portable man(7) macros and
validates warning-free under groff and mandoc -T lint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Address review feedback on man page generation

Rename the man page API to the single-word "Manpage" spelling throughout
(Manpage feature, ManpageInfo, CommandSet.OutputManpage,
UserInput.FormatManpage) for consistency with the "manpage" convention.

- Drop the redundant null check in OutputManpage; info is non-nullable
  under the enabled nullable context.
- Move the tests that exercise CommandSet.OutputManpage into
  CommandSetTests as a "Manpage Output" region, and relocate the Manpage
  feature test into a path-synced Features subfolder
  (SabreTools.CommandLine.Test.Features). Private test helpers now sit at
  the bottom of their classes.
- Fix the Manpage feature doc example to use the actual "man" command.

Builds clean across all target frameworks; the 235 tests pass and the
generated page still validates warning-free under groff -man -ww and
mandoc -T lint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 13:53:34 -04:00

81 lines
2.6 KiB
C#

using System;
using System.IO;
using SabreTools.CommandLine.Features;
using SabreTools.CommandLine.Inputs;
using Xunit;
namespace SabreTools.CommandLine.Test.Features
{
public class ManpageTests
{
[Fact]
public void ManpageFeature_WritesPageToStandardOutput()
{
var set = BuildSampleSet();
var info = new ManpageInfo("sample") { Version = "sample 1.0" };
set.Add(new Manpage(info));
var original = Console.Out;
var writer = new StringWriter();
string output;
try
{
Console.SetOut(writer);
bool result = set.ProcessArgs(["man"]);
Assert.True(result);
}
finally
{
Console.SetOut(original);
}
output = writer.ToString();
Assert.Contains(".TH \"SAMPLE\" \"1\"", output);
Assert.Contains(".SH NAME", output);
Assert.Contains(".B \\-\\-convert", output);
}
/// <summary>
/// Build a representative command set with nested inputs and detail text
/// </summary>
private static CommandSet BuildSampleSet()
{
var set = new CommandSet("Sample header line");
var help = new MockFeature("Help", ["?", "h", "help"], "Show this help",
"Built-in to most of the programs is a basic help text.");
set.Add(help);
var convert = new MockFeature("Convert", "--convert", "Convert input files",
"Converts the provided input files into the desired output format.");
convert.Add(new StringInput("output", "--output", "Set the output path"));
convert.Add(new FlagInput("force", "--force", "Overwrite existing files"));
set.Add(convert);
return set;
}
/// <summary>
/// Mock Feature implementation for testing
/// </summary>
private class MockFeature : Feature
{
public MockFeature(string name, string flag, string description, string? detailed = null)
: base(name, flag, description, detailed)
{
}
public MockFeature(string name, string[] flags, string description, string? detailed = null)
: base(name, flags, description, detailed)
{
}
/// <inheritdoc/>
public override bool Execute() => true;
/// <inheritdoc/>
public override bool VerifyInputs() => true;
}
}
}