diff --git a/README.md b/README.md index a29b9e4..65568ad 100644 --- a/README.md +++ b/README.md @@ -36,10 +36,11 @@ A simple measure of dependency freshness `-r`, `--recursive`: search recursively for all compatible files, even if one is found in a directory passed as an argument +`-o`, `--output`: sets how the output is displayed, valid options are `table` (default) or `json`. If `json` is selected, `--quiet` minifies the outputted JSON. + #### Limits: `-l`, `--limit`: exits with error code if total libyears behind is greater than this value `-p`, `--limit-project`: exits with error code if any project is more libyears behind than this value - `-a`, `--limit-any`: exits with error code if any dependency is more libyears behind than this value \ No newline at end of file diff --git a/src/LibYear.Core/LibYear.Core.csproj b/src/LibYear.Core/LibYear.Core.csproj index d5064ce..92dfaa3 100644 --- a/src/LibYear.Core/LibYear.Core.csproj +++ b/src/LibYear.Core/LibYear.Core.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/LibYear/App.cs b/src/LibYear/App.cs index b2e4fc9..1bdd055 100644 --- a/src/LibYear/App.cs +++ b/src/LibYear/App.cs @@ -1,4 +1,7 @@ using LibYear.Core; +using LibYear.Output; +using LibYear.Output.Json; +using LibYear.Output.Table; using Spectre.Console; namespace LibYear; @@ -27,7 +30,8 @@ public async Task Run(Settings settings) } var result = await _checker.GetPackages(projects); - DisplayAllResultsTables(result, settings.QuietMode); + var output = GetOutputMethod(settings); + output.DisplayAllResults(result, settings.QuietMode); if (settings.Update) { @@ -44,63 +48,11 @@ public async Task Run(Settings settings) : 0; } - private void DisplayAllResultsTables(SolutionResult allResults, bool quietMode) - { - if (!allResults.Details.Any()) - return; - - int MaxLength(Func field) => allResults.Details.Max(results => results.Details.Any() ? results.Details.Max(field) : 0); - var namePad = Math.Max("Package".Length, MaxLength(r => r.Name.Length)); - var installedPad = Math.Max("Installed".Length, MaxLength(r => r.Installed?.Version.ToString().Length ?? 0)); - var latestPad = Math.Max("Latest".Length, MaxLength(r => r.Latest?.Version.ToString().Length ?? 0)); - - var width = allResults.Details.Max(r => r.ProjectFile.FileName.Length); - foreach (var results in allResults.Details) - GetResultsTable(results, width, namePad, installedPad, latestPad, quietMode); - - if (allResults.Details.Count > 1) - { - _console.WriteLine($"Total is {allResults.YearsBehind:F1} libyears behind"); - } - } - - private void GetResultsTable(ProjectResult results, int titlePad, int namePad, int installedPad, int latestPad, bool quietMode) - { - if (results.Details.Count == 0) - return; - - var width = Math.Max(titlePad + 2, namePad + installedPad + latestPad + 48) + 2; - var table = new Table + private IOutput GetOutputMethod(Settings settings) => + settings.Output switch { - Title = new TableTitle($" {results.ProjectFile.FileName}".PadRight(width)), - Caption = new TableTitle(($" Project is {results.YearsBehind:F1} libyears behind").PadRight(width)), - Width = width + OutputOption.Table => new TableOutput(_console), + OutputOption.Json => new JsonOutput(_console), + _ => throw new NotImplementedException() }; - table.AddColumn(new TableColumn("Package").Width(namePad)); - table.AddColumn(new TableColumn("Installed").Width(installedPad)); - table.AddColumn(new TableColumn("Released")); - table.AddColumn(new TableColumn("Latest").Width(latestPad)); - table.AddColumn(new TableColumn("Released")); - table.AddColumn(new TableColumn("Age (y)")); - - foreach (var result in results.Details.Where(r => !quietMode || r.YearsBehind > 0)) - { - table.AddRow( - result.Name, - result.Installed?.Version.ToString() ?? string.Empty, - result.Installed?.Date.ToString("yyyy-MM-dd") ?? string.Empty, - result.Latest?.Version.ToString() ?? string.Empty, - result.Latest?.Date.ToString("yyyy-MM-dd") ?? string.Empty, - result.YearsBehind.ToString("F1") - ); - } - - if (quietMode && Math.Abs(results.YearsBehind) < double.Epsilon) - { - table.ShowHeaders = false; - } - - _console.Write(table); - _console.WriteLine(); - } } \ No newline at end of file diff --git a/src/LibYear/LibYear.csproj b/src/LibYear/LibYear.csproj index eccbe80..44f9cb8 100644 --- a/src/LibYear/LibYear.csproj +++ b/src/LibYear/LibYear.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/LibYear/Output/IOutput.cs b/src/LibYear/Output/IOutput.cs new file mode 100644 index 0000000..f0cda37 --- /dev/null +++ b/src/LibYear/Output/IOutput.cs @@ -0,0 +1,8 @@ +using LibYear.Core; + +namespace LibYear.Output; + +public interface IOutput +{ + public void DisplayAllResults(SolutionResult allResults, bool quietMode); +} \ No newline at end of file diff --git a/src/LibYear/Output/Json/DateTimeConverter.cs b/src/LibYear/Output/Json/DateTimeConverter.cs new file mode 100644 index 0000000..2c9d6d4 --- /dev/null +++ b/src/LibYear/Output/Json/DateTimeConverter.cs @@ -0,0 +1,22 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace LibYear.Output.Json; + +public sealed class DateTimeConverter : JsonConverter +{ + public override DateTime Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) => + DateTime.ParseExact(reader.GetString()!, + "yyyy-MM-dd", CultureInfo.InvariantCulture); + + public override void Write( + Utf8JsonWriter writer, + DateTime dateTimeValue, + JsonSerializerOptions options) => + writer.WriteStringValue(dateTimeValue.ToString( + "yyyy-MM-dd", CultureInfo.InvariantCulture)); +} \ No newline at end of file diff --git a/src/LibYear/Output/Json/DisplayVersion.cs b/src/LibYear/Output/Json/DisplayVersion.cs new file mode 100644 index 0000000..9952e53 --- /dev/null +++ b/src/LibYear/Output/Json/DisplayVersion.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; +using LibYear.Core; + +namespace LibYear.Output.Json; + +internal sealed record DisplayVersion +{ + public string VersionNumber { get; init; } = string.Empty; + public DateTime ReleaseDate { get; init; } + public DisplayVersion(Release release) + { + VersionNumber = release.Version.ToString(); + ReleaseDate = release.Date; + } +} \ No newline at end of file diff --git a/src/LibYear/Output/Json/DoubleFormatter.cs b/src/LibYear/Output/Json/DoubleFormatter.cs new file mode 100644 index 0000000..707943d --- /dev/null +++ b/src/LibYear/Output/Json/DoubleFormatter.cs @@ -0,0 +1,18 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace LibYear.Output.Json; + +internal sealed class DoubleFormatter : JsonConverter +{ + public override double Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) => reader.GetDouble(); + + public override void Write( + Utf8JsonWriter writer, + double value, + JsonSerializerOptions options) => + writer.WriteNumberValue(Math.Round(value, 1)); +} \ No newline at end of file diff --git a/src/LibYear/Output/Json/JsonOutput.cs b/src/LibYear/Output/Json/JsonOutput.cs new file mode 100644 index 0000000..7af18ee --- /dev/null +++ b/src/LibYear/Output/Json/JsonOutput.cs @@ -0,0 +1,39 @@ +using System.Text.Json; +using LibYear.Core; +using Spectre.Console; + +namespace LibYear.Output.Json; + +public sealed class JsonOutput : IOutput +{ + private readonly IAnsiConsole _console; + + public JsonOutput(IAnsiConsole console) + { + _console = console; + } + + public void DisplayAllResults(SolutionResult allResults, bool quietMode) + { + if (allResults.Details.Count == 0) + return; + var output = FormatOutput(allResults, quietMode); + _console.WriteLine(output); + } + + public static string FormatOutput(SolutionResult allResults, bool quietMode) + { + var model = new ResultOutput(allResults); + var serializerOptions = new JsonSerializerOptions + { + Converters = + { + new DoubleFormatter(), + new DateTimeConverter() + }, + WriteIndented = !quietMode + }; + var output = JsonSerializer.Serialize(model, serializerOptions); + return output; + } +} \ No newline at end of file diff --git a/src/LibYear/Output/Json/PackageResult.cs b/src/LibYear/Output/Json/PackageResult.cs new file mode 100644 index 0000000..f81b3e2 --- /dev/null +++ b/src/LibYear/Output/Json/PackageResult.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; +using LibYear.Core; + +namespace LibYear.Output.Json; + +internal sealed record PackageResult +{ + public string PackageName { get; set; } = string.Empty; + public DisplayVersion? CurrentVersion { get; init; } + public DisplayVersion? LatestVersion { get; init; } + public double YearsBehind { get; init; } + + public PackageResult(Result result) + { + PackageName = result.Name; + YearsBehind = result.YearsBehind; + CurrentVersion = result.Installed is null ? null : new DisplayVersion(result.Installed); + LatestVersion = result.Latest is null ? null : new DisplayVersion(result.Latest); + } +} \ No newline at end of file diff --git a/src/LibYear/Output/Json/ProjectFormatResult.cs b/src/LibYear/Output/Json/ProjectFormatResult.cs new file mode 100644 index 0000000..2bb6a0b --- /dev/null +++ b/src/LibYear/Output/Json/ProjectFormatResult.cs @@ -0,0 +1,17 @@ +using LibYear.Core; + +namespace LibYear.Output.Json; + +internal sealed record ProjectFormatResult +{ + public string Project { get; init; } = string.Empty; + public double YearsBehind { get; init; } + public IReadOnlyCollection Packages { get; init; } = []; + + public ProjectFormatResult(ProjectResult projectResult) + { + Project = projectResult.ProjectFile.FileName; + YearsBehind = projectResult.YearsBehind; + Packages = projectResult.Details.Select(result => new PackageResult(result)).ToArray(); + } +} \ No newline at end of file diff --git a/src/LibYear/Output/Json/ResultOutput.cs b/src/LibYear/Output/Json/ResultOutput.cs new file mode 100644 index 0000000..05daeca --- /dev/null +++ b/src/LibYear/Output/Json/ResultOutput.cs @@ -0,0 +1,22 @@ +using System.Text.Json.Serialization; +using LibYear.Core; + +namespace LibYear.Output.Json; + +internal sealed record ResultOutput +{ + public double YearsBehind { get; init; } + public double DaysBehind { get; init; } + public IReadOnlyCollection Projects { get; set; } = []; + + public ResultOutput() + { + } + + public ResultOutput(SolutionResult solutionResult) + { + YearsBehind = solutionResult.YearsBehind; + DaysBehind = solutionResult.DaysBehind; + Projects = solutionResult.Details?.Select(project => new ProjectFormatResult(project)).ToArray() ?? Array.Empty(); + } +} \ No newline at end of file diff --git a/src/LibYear/Output/OutputOption.cs b/src/LibYear/Output/OutputOption.cs new file mode 100644 index 0000000..15ed072 --- /dev/null +++ b/src/LibYear/Output/OutputOption.cs @@ -0,0 +1,7 @@ +namespace LibYear.Output; + +public enum OutputOption +{ + Table, + Json +} \ No newline at end of file diff --git a/src/LibYear/Output/Table/TableOutput.cs b/src/LibYear/Output/Table/TableOutput.cs new file mode 100644 index 0000000..d7a3df1 --- /dev/null +++ b/src/LibYear/Output/Table/TableOutput.cs @@ -0,0 +1,73 @@ +using LibYear.Core; +using Spectre.Console; + +namespace LibYear.Output.Table; + +public sealed class TableOutput : IOutput +{ + private readonly IAnsiConsole _console; + + public TableOutput(IAnsiConsole console) + { + _console = console; + } + + public void DisplayAllResults(SolutionResult allResults, bool quietMode) + { + if (!allResults.Details.Any()) + return; + + int MaxLength(Func field) => allResults.Details.Max(results => results.Details.Any() ? results.Details.Max(field) : 0); + var namePad = Math.Max("Package".Length, MaxLength(r => r.Name.Length)); + var installedPad = Math.Max("Installed".Length, MaxLength(r => r.Installed?.Version.ToString().Length ?? 0)); + var latestPad = Math.Max("Latest".Length, MaxLength(r => r.Latest?.Version.ToString().Length ?? 0)); + var width = allResults.Details.Max(r => r.ProjectFile.FileName.Length); + foreach (var results in allResults.Details) + GetResultsTable(results, width, namePad, installedPad, latestPad, quietMode); + + if (allResults.Details.Count > 1) + { + _console.WriteLine($"Total is {allResults.YearsBehind:F1} libyears behind"); + } + } + + private void GetResultsTable(ProjectResult results, int titlePad, int namePad, int installedPad, int latestPad, bool quietMode) + { + if (results.Details.Count == 0) + return; + + var width = Math.Max(titlePad + 2, namePad + installedPad + latestPad + 48) + 2; + var table = new Spectre.Console.Table + { + Title = new TableTitle($" {results.ProjectFile.FileName}".PadRight(width)), + Caption = new TableTitle(($" Project is {results.YearsBehind:F1} libyears behind").PadRight(width)), + Width = width + }; + table.AddColumn(new TableColumn("Package").Width(namePad)); + table.AddColumn(new TableColumn("Installed").Width(installedPad)); + table.AddColumn(new TableColumn("Released")); + table.AddColumn(new TableColumn("Latest").Width(latestPad)); + table.AddColumn(new TableColumn("Released")); + table.AddColumn(new TableColumn("Age (y)")); + + foreach (var result in results.Details.Where(r => !quietMode || r.YearsBehind > 0)) + { + table.AddRow( + result.Name, + result.Installed?.Version.ToString() ?? string.Empty, + result.Installed?.Date.ToString("yyyy-MM-dd") ?? string.Empty, + result.Latest?.Version.ToString() ?? string.Empty, + result.Latest?.Date.ToString("yyyy-MM-dd") ?? string.Empty, + result.YearsBehind.ToString("F1") + ); + } + + if (quietMode && Math.Abs(results.YearsBehind) < double.Epsilon) + { + table.ShowHeaders = false; + } + + _console.Write(table); + _console.WriteLine(); + } +} \ No newline at end of file diff --git a/src/LibYear/Settings.cs b/src/LibYear/Settings.cs index 3658a3d..b61a697 100644 --- a/src/LibYear/Settings.cs +++ b/src/LibYear/Settings.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using LibYear.Output; using Spectre.Console.Cli; namespace LibYear; @@ -32,4 +33,8 @@ public class Settings : CommandSettings [CommandOption("-r|--recursive")] [Description("search recursively for all compatible files, even if one is found in a directory passed as an argument")] public bool Recursive { get; set; } -} \ No newline at end of file + + [CommandOption("-o|--output")] + [Description("output format (table or JSON)")] + public OutputOption Output { get; set; } = OutputOption.Table; +} diff --git a/test/LibYear.Core.Tests/LibYear.Core.Tests.csproj b/test/LibYear.Core.Tests/LibYear.Core.Tests.csproj index e5e4b32..9db7eab 100644 --- a/test/LibYear.Core.Tests/LibYear.Core.Tests.csproj +++ b/test/LibYear.Core.Tests/LibYear.Core.Tests.csproj @@ -6,14 +6,13 @@ - + - + - - + + - diff --git a/test/LibYear.Tests/AppTests.cs b/test/LibYear.Tests/AppTests.cs index 092b375..6c1e8bf 100644 --- a/test/LibYear.Tests/AppTests.cs +++ b/test/LibYear.Tests/AppTests.cs @@ -1,6 +1,7 @@ using LibYear.Core; using LibYear.Core.FileTypes; using LibYear.Core.Tests; +using LibYear.Output; using NSubstitute; using Spectre.Console.Testing; using Xunit; @@ -105,6 +106,36 @@ public async Task MultiplePackagesShowsGrandTotal() Assert.Contains("Total", console.Output); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task ShouldUseJsonIfSelected(bool quiet) + { + //arrange + var checker = Substitute.For(); + var projectFile1 = new TestProjectFile("test project 1"); + var projectFile2 = new TestProjectFile("test project 2"); + var results = new SolutionResult(new [] + { + new ProjectResult(projectFile1, new[] { new Result("test1", new Release(new PackageVersion(1, 2, 3), DateTime.Today), new Release(new PackageVersion(1, 2, 3), DateTime.Today)) }), + new ProjectResult(projectFile2, new[] { new Result("test1", new Release(new PackageVersion(1, 2, 3), DateTime.Today), new Release(new PackageVersion(1, 2, 3), DateTime.Today)) }) + }); + checker.GetPackages(Arg.Any>()).Returns(results); + + var manager = Substitute.For(); + manager.GetAllProjects(Arg.Any>()).Returns(new IProjectFile[] { projectFile1, projectFile2 }); + + var console = new TestConsole(); + var app = new App(checker, manager, console); + + //act + await app.Run(new Settings { QuietMode = quiet, Output = OutputOption.Json}); + + //assert + Assert.StartsWith("{", console.Output.Trim()); + Assert.EndsWith("}", console.Output.Trim()); + } + [Fact] public async Task EmptyResultsAreSkipped() { diff --git a/test/LibYear.Tests/LibYear.Tests.csproj b/test/LibYear.Tests/LibYear.Tests.csproj index 0e292b5..90f2264 100644 --- a/test/LibYear.Tests/LibYear.Tests.csproj +++ b/test/LibYear.Tests/LibYear.Tests.csproj @@ -6,11 +6,11 @@ - + - - - + + + diff --git a/test/LibYear.Tests/Output/Json/DateTimeConverterTests.cs b/test/LibYear.Tests/Output/Json/DateTimeConverterTests.cs new file mode 100644 index 0000000..7f80fd8 --- /dev/null +++ b/test/LibYear.Tests/Output/Json/DateTimeConverterTests.cs @@ -0,0 +1,40 @@ +using LibYear.Output.Json; +using System.Text.Json; +using Xunit; + +namespace LibYear.Tests.Output.Json; + +public class DateTimeConverterTests +{ + private static TestObject DateTimeObject = new() + { + Test = new DateTime(2020, 01, 01) + }; + private static string ExpectedJson = @"{""Test"":""2020-01-01""}"; + private static JsonSerializerOptions Options = new JsonSerializerOptions + { + Converters = + { + new DateTimeConverter() + } + }; + + [Fact] + public void ShouldSerializeProperly() + { + var serialized = JsonSerializer.Serialize(DateTimeObject, Options); + Assert.Equal(ExpectedJson, serialized); + } + + [Fact] + public void ShouldDeserializeProperly() + { + var deserialized = JsonSerializer.Deserialize(ExpectedJson, Options); + Assert.Equal(DateTimeObject, deserialized); + } + + private sealed record TestObject + { + public DateTime Test { get; set; } + } +} \ No newline at end of file diff --git a/test/LibYear.Tests/Output/Json/DoubleConverterTests.cs b/test/LibYear.Tests/Output/Json/DoubleConverterTests.cs new file mode 100644 index 0000000..a42c305 --- /dev/null +++ b/test/LibYear.Tests/Output/Json/DoubleConverterTests.cs @@ -0,0 +1,40 @@ +using System.Text.Json; +using LibYear.Output.Json; +using Xunit; + +namespace LibYear.Tests.Output.Json; + +public class DoubleConverterTests +{ + private static TestObject DateTimeObject = new() + { + Test = 15 + }; + private static string ExpectedJson = @"{""Test"":15}"; + private static JsonSerializerOptions Options = new JsonSerializerOptions + { + Converters = + { + new DateTimeConverter() + } + }; + + [Fact] + public void ShouldSerializeProperly() + { + var serialized = JsonSerializer.Serialize(DateTimeObject, Options); + Assert.Equal(ExpectedJson, serialized); + } + + [Fact] + public void ShouldDeserializeProperly() + { + var deserialized = JsonSerializer.Deserialize(ExpectedJson, Options); + Assert.Equal(DateTimeObject, deserialized); + } + + private sealed record TestObject + { + public double Test { get; set; } + } +} \ No newline at end of file diff --git a/test/LibYear.Tests/Output/Json/JsonOutputTests.cs b/test/LibYear.Tests/Output/Json/JsonOutputTests.cs new file mode 100644 index 0000000..15b00da --- /dev/null +++ b/test/LibYear.Tests/Output/Json/JsonOutputTests.cs @@ -0,0 +1,113 @@ +using System.Security.AccessControl; +using LibYear.Core; +using LibYear.Core.Tests; +using LibYear.Output.Json; +using NSubstitute; +using Spectre.Console; +using Spectre.Console.Testing; +using Xunit; + +namespace LibYear.Tests.Output.Json; + +public class JsonOutputTests +{ + [Fact] + public void NoResultsProducesNoOutput() + { + //arrange + var console = Substitute.For(); + + // act + var output = new JsonOutput(console); + var result = new SolutionResult(Array.Empty()); + output.DisplayAllResults(result, false); + + // assert + console.DidNotReceive().WriteLine(); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void ResultsShouldPrintToConsole(bool quietMode) + { + //arrange + var console = new TestConsole(); + var projectFile1 = new TestProjectFile("test project 1"); + var solutionResults = new SolutionResult(new[] + { + new ProjectResult(projectFile1, new[] { new Result("test1", new Release(new PackageVersion(1, 2, 3), DateTime.Today), new Release(new PackageVersion(1, 2, 3), DateTime.Today)) }), + }); + + // act + var sut = new JsonOutput(console); + sut.DisplayAllResults(solutionResults, quietMode); + + // assert + Assert.NotEmpty(console.Output); + } + + [Fact] + public void QuietModeResultInSingleLineOutput() + { + //arrange + var projectFile1 = new TestProjectFile("test project 1"); + var dateTime = new DateTime(2020, 01, 02); + var solutionResults = new SolutionResult(new[] + { + new ProjectResult(projectFile1, new[] { new Result("test1", new Release(new PackageVersion(1, 2, 3), dateTime), new Release(new PackageVersion(1, 2, 3), dateTime)) }), + }); + + // act + var result = JsonOutput.FormatOutput(solutionResults, true); + + // assert + var expectedJsonOutput = @"{""YearsBehind"":0,""DaysBehind"":0,""Projects"":[{""Project"":""test project 1"",""YearsBehind"":0,""Packages"":[{""PackageName"":""test1"",""CurrentVersion"":{""VersionNumber"":""1.2.3"",""ReleaseDate"":""2020-01-02""},""LatestVersion"":{""VersionNumber"":""1.2.3"",""ReleaseDate"":""2020-01-02""},""YearsBehind"":0}]}]}"; + Assert.Equal(expectedJsonOutput, result); + } + + [Fact] + public void NonQuietModeShouldResultInMultiLineOutput() + { + //arrange + + var projectFile1 = new TestProjectFile("test project 1"); + var dateTime = new DateTime(2020, 01, 02); + var results = new SolutionResult(new [] + { + new ProjectResult(projectFile1, new[] { new Result("test1", new Release(new PackageVersion(1, 2, 3), dateTime), new Release(new PackageVersion(1, 2, 3), dateTime)) }), + }); + + // act + var result = JsonOutput.FormatOutput(results, false); + + // assert + var expectedOutput = """ + { + "YearsBehind": 0, + "DaysBehind": 0, + "Projects": [ + { + "Project": "test project 1", + "YearsBehind": 0, + "Packages": [ + { + "PackageName": "test1", + "CurrentVersion": { + "VersionNumber": "1.2.3", + "ReleaseDate": "2020-01-02" + }, + "LatestVersion": { + "VersionNumber": "1.2.3", + "ReleaseDate": "2020-01-02" + }, + "YearsBehind": 0 + } + ] + } + ] + } + """; + Assert.Equal(expectedOutput.ReplaceLineEndings(), result); + } +} \ No newline at end of file diff --git a/test/LibYear.Tests/Output/Table/TableOutputTests.cs b/test/LibYear.Tests/Output/Table/TableOutputTests.cs new file mode 100644 index 0000000..bb6f7c2 --- /dev/null +++ b/test/LibYear.Tests/Output/Table/TableOutputTests.cs @@ -0,0 +1,70 @@ +using System.Text.RegularExpressions; +using LibYear.Core; +using LibYear.Core.Tests; +using LibYear.Output.Table; +using Spectre.Console.Testing; +using Xunit; + +namespace LibYear.Tests.Output.Table; + +public class TableOutputTests +{ + [Fact] + public void NoResultsProducesNoOutput() + { + // arrange + var console = new TestConsole(); + + // act + var output = new TableOutput(console); + var result = new SolutionResult(Array.Empty()); + output.DisplayAllResults(result, false); + + // assert + Assert.Empty(console.Output); + } + + [Fact] + public void ShouldPrintATableIfQuietModeDisabled() + { + //arrange + var console = new TestConsole(); + var legacyDateTime = new DateTime(2020, 01, 03); + var newDateTime = new DateTime(2020, 01, 05); + + // act + var output = new TableOutput(console); + var projectFile1 = new TestProjectFile("test project 1"); + var results = new SolutionResult(new [] + { + new ProjectResult(projectFile1, new[] { new Result("test1", new Release(new PackageVersion(1, 2, 3), legacyDateTime), new Release(new PackageVersion(1, 2, 3), newDateTime)) }), + }); + output.DisplayAllResults(results, false); + + // assert + + Assert.NotEmpty(console.Output); + Assert.Contains("│ Package │ Installed │ Released │ Latest │ Released │ Age (y) │", console.Output); + Assert.Contains("│ test1 │ 1.2.3 │ 2020-01-03 │ 1.2.3 │ 2020-01-05 │ 0.0 │", console.Output); + } + + [Fact] + public void ShouldPrintSimplifiedIfInQuietMode() + { + // arrange + var console = new TestConsole(); + + // act + var output = new TableOutput(console); + var projectFile1 = new TestProjectFile("test project 1"); + var results = new SolutionResult(new [] + { + new ProjectResult(projectFile1, new[] { new Result("test1", new Release(new PackageVersion(1, 2, 3), DateTime.Today), new Release(new PackageVersion(1, 2, 3), DateTime.Today)) }), + }); + output.DisplayAllResults(results, true); + + // assert + Assert.NotEmpty(console.Output); + Assert.Contains(" Project is 0.0 libyears ", console.Output); + } +} \ No newline at end of file