diff --git a/TrayApp.Test/StatusReportTests.cs b/TrayApp.Test/StatusReportTests.cs index c8c756c..6c52589 100644 --- a/TrayApp.Test/StatusReportTests.cs +++ b/TrayApp.Test/StatusReportTests.cs @@ -47,6 +47,32 @@ public void Build_WithAStatusAndDetails_AppendsThemInOrder() Assert.Contains("systemd-inhibit", report, StringComparison.Ordinal); } + [TestMethod] + public void Build_WithALongDetailLabel_KeepsAGapAndAlignsEveryValue() + { + string report = StatusReport.Build( + "demo", + "on", + [new StatusDetail("Power assertion", () => "held"), new StatusDetail("Inhibitor path", () => "/usr/bin/systemd-inhibit")]); + + Assert.Contains("Power assertion: ", report, StringComparison.Ordinal); + Assert.Contains("Inhibitor path: ", report, StringComparison.Ordinal); + + string[] rows = report.Split('\n')[1..]; + int column = rows[0].IndexOf(':', StringComparison.Ordinal) + 1; + while (rows[0][column] == ' ') + { + column++; + } + + foreach (string row in rows) + { + string line = row.TrimEnd('\r'); + Assert.AreEqual(' ', line[column - 1], $"Row \"{line}\" has no gap before its value column."); + Assert.AreNotEqual(' ', line[column], $"Row \"{line}\" does not start its value at column {column}."); + } + } + [TestMethod] public void Build_WithAThrowingDetail_ReportsTheErrorInItsRowAndKeepsTheRest() { diff --git a/TrayApp/StatusReport.cs b/TrayApp/StatusReport.cs index c34a138..ad2e336 100644 --- a/TrayApp/StatusReport.cs +++ b/TrayApp/StatusReport.cs @@ -19,6 +19,7 @@ namespace ktsu.TrayApp; public static class StatusReport { private const int LabelWidth = 15; + private const int MinimumGap = 1; /// /// Describes what a tool can do on this machine. @@ -33,19 +34,35 @@ public static string Build(string name, string? status, IReadOnlyList rows = + [ + ("Platform", string.Create(CultureInfo.InvariantCulture, $"{RuntimeInformation.OSDescription.Trim()} ({RuntimeInformation.RuntimeIdentifier})")), + ("Tray icon", DesktopSession.Explanation), + ]; if (status is not null) { - AppendRow(report, "State", status); + rows.Add(("State", status)); } foreach (StatusDetail detail in details) { - AppendRow(report, detail.Label, Read(detail.Value)); + rows.Add((detail.Label, Read(detail.Value))); + } + + // The value column starts after the longest label, so a long label still has a gap before its value + // and every value lines up with the others. + int labelWidth = LabelWidth; + foreach ((string label, _) in rows) + { + labelWidth = Math.Max(labelWidth, label.Length + MinimumGap + 1); + } + + StringBuilder report = new(); + report.AppendLine(HelpText.Version(name)); + foreach ((string label, string value) in rows) + { + report.AppendLine($"{(label + ':').PadRight(labelWidth)}{value}"); } // Every row above appended a newline; the report is quoted and compared in tests, so it ends where @@ -74,7 +91,4 @@ internal static string Read(Func getter) return "error: " + ex.Message; } } - - private static void AppendRow(StringBuilder report, string label, string value) => - report.AppendLine($"{(label + ':').PadRight(LabelWidth)}{value}"); }