diff --git a/Heleonix.Build.sln b/Heleonix.Build.sln index c042b97..189419a 100644 --- a/Heleonix.Build.sln +++ b/Heleonix.Build.sln @@ -27,6 +27,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .github\workflows\hx-net-nuget.yml = .github\workflows\hx-net-nuget.yml EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Heleonix.Build.Tests.ExeMock", "test\Heleonix.Build.Tests.ExeMock\Heleonix.Build.Tests.ExeMock.csproj", "{3D5694BD-41EC-4E7B-8775-2757EA4059CA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -41,6 +43,10 @@ Global {F4CE21CC-39D4-43C0-81F2-BFED6436DC5C}.Debug|Any CPU.Build.0 = Debug|Any CPU {F4CE21CC-39D4-43C0-81F2-BFED6436DC5C}.Release|Any CPU.ActiveCfg = Release|Any CPU {F4CE21CC-39D4-43C0-81F2-BFED6436DC5C}.Release|Any CPU.Build.0 = Release|Any CPU + {3D5694BD-41EC-4E7B-8775-2757EA4059CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D5694BD-41EC-4E7B-8775-2757EA4059CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D5694BD-41EC-4E7B-8775-2757EA4059CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D5694BD-41EC-4E7B-8775-2757EA4059CA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -49,6 +55,7 @@ Global {44202B1B-5C68-40CE-B2C2-1FEB9AEC48E3} = {86666126-26CC-48EE-A647-28E94D1AE95A} {F4CE21CC-39D4-43C0-81F2-BFED6436DC5C} = {A3674ABC-7370-429D-8AE6-9AA33F4DE8F9} {34F2A7E3-FDE8-4425-BD9C-323F304F8EEE} = {3499A7EA-88BC-48DF-8E9B-1EB80C052AD0} + {3D5694BD-41EC-4E7B-8775-2757EA4059CA} = {A3674ABC-7370-429D-8AE6-9AA33F4DE8F9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DADF4FE8-717D-467C-948E-0F170CDA33E6} diff --git a/src/Heleonix.Build/Program.cs b/src/Heleonix.Build/Program.cs index 9a15fa3..b577457 100644 --- a/src/Heleonix.Build/Program.cs +++ b/src/Heleonix.Build/Program.cs @@ -27,8 +27,8 @@ public static int Main(string[] args) || "-h".Equals(args[0], StringComparison.OrdinalIgnoreCase))) { Console.WriteLine("Description:"); - Console.WriteLine(" The MSBuild-based build framework to use in CI/CD systems" + - " Version: " + Assembly.GetExecutingAssembly().GetName().Version); + Console.WriteLine(" The MSBuild-based build framework to use in CI/CD systems"); + Console.WriteLine(" Version: {0}", Assembly.GetExecutingAssembly().GetName().Version); Console.WriteLine(" More: https://heleonix.github.io/docs/api/Heleonix.Build/intro.html"); Console.WriteLine(); Console.WriteLine("Options:"); @@ -54,7 +54,8 @@ public static int Main(string[] args) { Console.ForegroundColor = ConsoleColor.Red; - Console.Error.WriteLine("The dotnet executable path is not defined for the specified argument '-exe'."); + Console.Error.WriteLine( + "The dotnet executable path is not defined for the specified argument '--exe'."); return 1; } diff --git a/src/Heleonix.Build/Tasks/Hx_MetadataToCmdArgs.cs b/src/Heleonix.Build/Tasks/Hx_MetadataToCmdArgs.cs index 0a860aa..edfa98c 100644 --- a/src/Heleonix.Build/Tasks/Hx_MetadataToCmdArgs.cs +++ b/src/Heleonix.Build/Tasks/Hx_MetadataToCmdArgs.cs @@ -63,7 +63,7 @@ protected override void ExecuteInternal() foreach (DictionaryEntry pair in metadata) { - var key = Regex.Replace(Regex.Replace(pair.Key.ToString(), "^_", "-"), "^_", "-"); + var key = Regex.Replace(Regex.Replace(pair.Key.ToString(), "^__", "--"), "^_", "-"); key = this.DottedKeys ? key.Replace("_", ".") : key; diff --git a/src/Heleonix.Build/Tasks/Hx_NetFindProjects.cs b/src/Heleonix.Build/Tasks/Hx_NetFindProjects.cs index f2fe013..7241e80 100644 --- a/src/Heleonix.Build/Tasks/Hx_NetFindProjects.cs +++ b/src/Heleonix.Build/Tasks/Hx_NetFindProjects.cs @@ -20,7 +20,7 @@ public class Hx_NetFindProjects : BaseTask /// Projects files found in the specified solution file [Output]. /// [Output] - public ITaskItem[] ProjectFiles { get; set; } + public string[] ProjectFiles { get; set; } /// /// Executes the implementation of the task. @@ -33,6 +33,6 @@ protected override void ExecuteInternal() slnContent, "(?<=Project.+=\\s*\".+\"\\s*,\\s*\")(.+proj)(?=\"\\s*,\\s*\".+\"\\s*EndProject)"); - this.ProjectFiles = matches.Select(m => new TaskItem(Path.Combine(slnDir, m.Value))).ToArray(); + this.ProjectFiles = matches.Select(m => Path.Combine(slnDir, m.Value)).ToArray(); } } diff --git a/src/Heleonix.Build/Tasks/Hx_NetFindSln.cs b/src/Heleonix.Build/Tasks/Hx_NetFindSln.cs index 185424b..7529390 100644 --- a/src/Heleonix.Build/Tasks/Hx_NetFindSln.cs +++ b/src/Heleonix.Build/Tasks/Hx_NetFindSln.cs @@ -27,6 +27,6 @@ public class Hx_NetFindSln : BaseTask /// protected override void ExecuteInternal() { - this.SlnFile = Directory.GetFiles(this.StartDir, "*.sln").Single(); + this.SlnFile = Directory.GetFiles(this.StartDir, "*.sln").SingleOrDefault(); } } diff --git a/src/Heleonix.Build/Tasks/Hx_NetSetupTool.cs b/src/Heleonix.Build/Tasks/Hx_NetSetupTool.cs index 90106f3..7ec7263 100644 --- a/src/Heleonix.Build/Tasks/Hx_NetSetupTool.cs +++ b/src/Heleonix.Build/Tasks/Hx_NetSetupTool.cs @@ -5,8 +5,6 @@ namespace Heleonix.Build.Tasks; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Collections; using System.IO; using System.Reflection; @@ -78,16 +76,16 @@ protected override void ExecuteInternal() this.Version = "2.74.1"; } - if ("NunitXml.TestLogger".Equals(this.Name, StringComparison.OrdinalIgnoreCase)) + if ("extent".Equals(this.Name, StringComparison.OrdinalIgnoreCase)) { this.IsPackage = true; - this.Version = "3.1.15"; + this.Version = "0.0.3"; } - if ("extent".Equals(this.Name, StringComparison.OrdinalIgnoreCase)) + if ("NunitXml.TestLogger".Equals(this.Name, StringComparison.OrdinalIgnoreCase)) { this.IsPackage = true; - this.Version = "0.0.3"; + this.Version = "3.1.15"; } if (this.IsPackage) @@ -154,8 +152,6 @@ protected override void ExecuteInternal() this.Log.LogMessage(MessageImportance.High, args); this.Log.LogError(result.Error); - - this.Log.LogMessage(MessageImportance.High, result.Output); } if (!this.IsPackage) @@ -165,17 +161,14 @@ protected override void ExecuteInternal() return; } - if (this.IsPackage && !string.IsNullOrEmpty(this.Version)) + if (string.IsNullOrEmpty(this.Version)) { - this.ToolPath = Path.Combine(toolsDir, this.PackageName, this.Version); + this.ToolPath = Hx_NetSetupTool.GetLatestVersionPath(Path.Combine(toolsDir, this.PackageName)); return; } - if (this.IsPackage && string.IsNullOrEmpty(this.Version)) - { - this.ToolPath = Hx_NetSetupTool.GetLatestVersionPath(Path.Combine(toolsDir, this.PackageName)); - } + this.ToolPath = Path.Combine(toolsDir, this.PackageName, this.Version); } /// @@ -185,15 +178,10 @@ protected override void ExecuteInternal() /// The path to the latest version folder of a given package path. private static string GetLatestVersionPath(string packagePath) { - var dirs = Directory.GetDirectories(packagePath); - - if (dirs.Length > 0) - { - Array.Sort(dirs, StringComparer.OrdinalIgnoreCase); + var dirs = Directory.Exists(packagePath) ? Directory.GetDirectories(packagePath) : Array.Empty(); - return dirs.Last(); - } + Array.Sort(dirs, StringComparer.OrdinalIgnoreCase); - return null; + return dirs.LastOrDefault(); } } diff --git a/test/Heleonix.Build.Tests.ExeMock/Heleonix.Build.Tests.ExeMock.csproj b/test/Heleonix.Build.Tests.ExeMock/Heleonix.Build.Tests.ExeMock.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/test/Heleonix.Build.Tests.ExeMock/Heleonix.Build.Tests.ExeMock.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/test/Heleonix.Build.Tests.ExeMock/Program.cs b/test/Heleonix.Build.Tests.ExeMock/Program.cs new file mode 100644 index 0000000..d8ece90 --- /dev/null +++ b/test/Heleonix.Build.Tests.ExeMock/Program.cs @@ -0,0 +1,12 @@ +if(args.Any(a => a.Contains("ERROR"))) +{ + Console.Error.Write("ERROR details"); + + Console.Write("ERROR simulated"); + + return 1; +} + +Console.Write(string.Join(' ', args)); + +return 0; \ No newline at end of file diff --git a/test/Heleonix.Build.Tests/Common/PathHelper.cs b/test/Heleonix.Build.Tests/Common/PathHelper.cs index ffa6c32..fb491ec 100644 --- a/test/Heleonix.Build.Tests/Common/PathHelper.cs +++ b/test/Heleonix.Build.Tests/Common/PathHelper.cs @@ -48,6 +48,11 @@ public static class PathHelper /// public static string SnkPairFile { get; } = Path.Combine(CurrentDir, "SnkPair.snk"); + /// + /// Gets the path to the ExeMoc file at runtime. + /// + public static string ExeMockFile { get; } = Path.Combine(CurrentDir, "Heleonix.Build.Tests.ExeMock.exe"); + /// /// Gets the random file name in current directory. /// diff --git a/test/Heleonix.Build.Tests/Common/TestBuildEngine.cs b/test/Heleonix.Build.Tests/Common/TestBuildEngine.cs index 57cd61d..1ca4a15 100644 --- a/test/Heleonix.Build.Tests/Common/TestBuildEngine.cs +++ b/test/Heleonix.Build.Tests/Common/TestBuildEngine.cs @@ -18,6 +18,11 @@ public class TestBuildEngine : IBuildEngine /// public List ErrorMessages { get; } = new List(); + /// + /// Gets logged messages. + /// + public List Messages { get; } = new List(); + /// /// Gets a value indicating whether the ContinueOnError flag was set to true /// for this particular task in the project file. @@ -66,7 +71,10 @@ public void LogWarningEvent(BuildWarningEventArgs e) /// The event data. public void LogMessageEvent(BuildMessageEventArgs e) { - // Dummy implementation. + if (!string.IsNullOrEmpty(e.Message)) + { + this.Messages.Add(e.Message); + } } /// diff --git a/test/Heleonix.Build.Tests/Heleonix.Build.Tests.csproj b/test/Heleonix.Build.Tests/Heleonix.Build.Tests.csproj index 382ad06..72f96b2 100644 --- a/test/Heleonix.Build.Tests/Heleonix.Build.Tests.csproj +++ b/test/Heleonix.Build.Tests/Heleonix.Build.Tests.csproj @@ -47,6 +47,7 @@ + diff --git a/test/Heleonix.Build.Tests/ProgramTests.cs b/test/Heleonix.Build.Tests/ProgramTests.cs new file mode 100644 index 0000000..ca2c115 --- /dev/null +++ b/test/Heleonix.Build.Tests/ProgramTests.cs @@ -0,0 +1,109 @@ +// +// Copyright (c) Heleonix - Hennadii Lutsyshyn. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the repository root for full license information. +// + +namespace Heleonix.Build.Tests; + +/// +/// Tests the . +/// +[ComponentTest(Type = typeof(Program))] + +public static class ProgramTests +{ + /// + /// Tests the . + /// + [MemberTest(Name = nameof(Program.Main))] + + public static void MainTests() + { + string[] args = null; + string outptut = null; + string errors = null; + var returnValue = 0; + + Act(() => + { + using var outWriter = new StringWriter(); + using var errorWriter = new StringWriter(); + + Console.SetOut(outWriter); + Console.SetError(errorWriter); + + returnValue = Program.Main(args); + + outptut = outWriter.ToString(); + errors = errorWriter.ToString(); + }); + + When("the help command is called", () => + { + And("the short form is specified", () => + { + args = new string[] { "-h" }; + + Should("display information about the tool", () => + { + Assert.That(returnValue, Is.Zero); + Assert.That(outptut, Contains.Substring("Description:")); + Assert.That(outptut, Contains.Substring("Version:")); + Assert.That(outptut, Contains.Substring("More:")); + Assert.That(outptut, Contains.Substring("Options:")); + Assert.That(outptut, Contains.Substring("Examples:")); + }); + }); + + And("the long form is specified", () => + { + args = new string[] { "--help" }; + + Should("display information about the tool", () => + { + Assert.That(returnValue, Is.Zero); + Assert.That(outptut, Contains.Substring("Description:")); + Assert.That(outptut, Contains.Substring("Version:")); + Assert.That(outptut, Contains.Substring("More:")); + Assert.That(outptut, Contains.Substring("Options:")); + Assert.That(outptut, Contains.Substring("Examples:")); + }); + }); + }); + + When("the '--exe' value is not provided", () => + { + args = new string[] { "--exe" }; + + Should("retun the error code: 1", () => + { + Assert.That(returnValue, Is.EqualTo(1)); + Assert.That( + errors, + Contains.Substring("The dotnet executable path is not defined for the specified argument '--exe'.")); + }); + }); + + When("the --exe value is provided", () => + { + args = new string[] { "--exe", "dotnet.exe", "-p:Hx_WS_RepositoryUrl=https://example.com" }; + + Should("run the provided dotnet executable with passed command-line arguments", () => + { + Assert.That(returnValue, Is.Zero); + Assert.That(outptut, Contains.Substring("https://example.com")); + }); + }); + + When("the default dotnet.exe is used", () => + { + args = new string[] { "-p:Hx_WS_RepositoryUrl=https://example.com" }; + + Should("run the provided dotnet executable with passed command-line arguments", () => + { + Assert.That(returnValue, Is.Zero); + Assert.That(outptut, Contains.Substring("https://example.com")); + }); + }); + } +} diff --git a/test/Heleonix.Build.Tests/Tasks/Hx_GitParseRepoUrlTests.cs b/test/Heleonix.Build.Tests/Tasks/Hx_GitParseRepoUrlTests.cs new file mode 100644 index 0000000..2f2f587 --- /dev/null +++ b/test/Heleonix.Build.Tests/Tasks/Hx_GitParseRepoUrlTests.cs @@ -0,0 +1,75 @@ +// +// Copyright (c) Heleonix - Hennadii Lutsyshyn. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the repository root for full license information. +// + +namespace Heleonix.Build.Tests.Tasks; + +/// +/// Tests the . +/// +[ComponentTest(Type = typeof(Hx_GitParseRepoUrl))] + +public static class Hx_GitParseRepoUrlTests +{ + /// + /// Tests the . + /// + [MemberTest(Name = nameof(Hx_GitParseRepoUrl.Execute))] + public static void Execute() + { + Hx_GitParseRepoUrl task = null; + string url = null; + var succeeded = false; + + Act(() => + { + task = new Hx_GitParseRepoUrl + { + BuildEngine = new TestBuildEngine(), + RepositoryUrl = url, + }; + + succeeded = task.Execute(); + }); + + When("the task is executed", () => + { + And("the url in SSH format is provided", () => + { + url = "git@github.com:SomeOwner/Some.Repo.git"; + + Should("succeed with parsed owner and repository names", () => + { + Assert.That(succeeded); + Assert.That(task.OwnerName, Is.EqualTo("SomeOwner")); + Assert.That(task.RepositoryName, Is.EqualTo("Some.Repo")); + }); + }); + + And("the url in HTTPS format is provided", () => + { + url = "https://github.com/SomeOwner/Some.Repo.git"; + + Should("succeed with parsed owner and repository names", () => + { + Assert.That(succeeded); + Assert.That(task.OwnerName, Is.EqualTo("SomeOwner")); + Assert.That(task.RepositoryName, Is.EqualTo("Some.Repo")); + }); + }); + + And("the url in an unsupported format is provided", () => + { + url = "https://heleonix.github.io/docs"; + + Should("succeed without found owner and repository names", () => + { + Assert.That(succeeded); + Assert.That(task.OwnerName, Is.Empty); + Assert.That(task.RepositoryName, Is.Empty); + }); + }); + }); + } +} diff --git a/test/Heleonix.Build.Tests/Tasks/Hx_MetadataToCmdArgsTests.cs b/test/Heleonix.Build.Tests/Tasks/Hx_MetadataToCmdArgsTests.cs new file mode 100644 index 0000000..540d5e0 --- /dev/null +++ b/test/Heleonix.Build.Tests/Tasks/Hx_MetadataToCmdArgsTests.cs @@ -0,0 +1,76 @@ +// +// Copyright (c) Heleonix - Hennadii Lutsyshyn. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the repository root for full license information. +// + +namespace Heleonix.Build.Tests.Tasks; + +/// +/// Tests the . +/// +[ComponentTest(Type = typeof(Hx_MetadataToCmdArgs))] + +public static class Hx_MetadataToCmdArgsTests +{ + /// + /// Tests the . + /// + [MemberTest(Name = nameof(Hx_MetadataToCmdArgs.Execute))] + public static void Execute() + { + Hx_MetadataToCmdArgs task = null; + ITaskItem item = null; + var dottedKeys = false; + var succeeded = false; + + Act(() => + { + task = new Hx_MetadataToCmdArgs + { + BuildEngine = new TestBuildEngine(), + DottedKeys = dottedKeys, + Item = item, + }; + + succeeded = task.Execute(); + }); + + When("the task is executed", () => + { + And("the item with metadata is not povided", () => + { + item = null; + + Should("succeed without stringified metadata", () => + { + Assert.That(succeeded); + Assert.That(task.Result, Is.Null); + }); + }); + + And("the item with metadata to stringify is povided", () => + { + item = new TaskItem( + "not-used", + new Dictionary { { "__Arg_One", "One" }, { "Arg_Two", string.Empty } }); + + Should("succeed with stringified metadata", () => + { + Assert.That(succeeded); + Assert.That(task.Result, Is.EqualTo("Arg_Two --Arg_One=One ")); + }); + + And("the keys should be dotted", () => + { + dottedKeys = true; + + Should("succeed with stringified dotted metadata", () => + { + Assert.That(succeeded); + Assert.That(task.Result, Is.EqualTo("Arg.Two --Arg.One=One ")); + }); + }); + }); + }); + } +} diff --git a/test/Heleonix.Build.Tests/Tasks/Hx_NetFindProjectsTests.cs b/test/Heleonix.Build.Tests/Tasks/Hx_NetFindProjectsTests.cs new file mode 100644 index 0000000..5f815a8 --- /dev/null +++ b/test/Heleonix.Build.Tests/Tasks/Hx_NetFindProjectsTests.cs @@ -0,0 +1,61 @@ +// +// Copyright (c) Heleonix - Hennadii Lutsyshyn. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the repository root for full license information. +// + +namespace Heleonix.Build.Tests.Tasks; + +/// +/// Tests the . +/// +[ComponentTest(Type = typeof(Hx_NetFindProjects))] + +public static class Hx_NetFindProjectsTests +{ + /// + /// Tests the . + /// + [MemberTest(Name = nameof(Hx_NetFindProjects.Execute))] + public static void Execute() + { + Hx_NetFindProjects task = null; + string slnFile = null; + NetSimulatorHelper simulator = null; + var succeeded = false; + + Act(() => + { + task = new Hx_NetFindProjects + { + BuildEngine = new TestBuildEngine(), + SlnFile = slnFile, + }; + + succeeded = task.Execute(); + }); + + When("the task is executed", () => + { + And("the sln file is povided", () => + { + Arrange(() => + { + simulator = new NetSimulatorHelper(); + slnFile = simulator.SolutionFile; + }); + + Teardown(() => + { + simulator.Clear(); + }); + + Should("succeed with found full paths to project files", () => + { + Assert.That(succeeded); + Assert.That(task.ProjectFiles[0], Is.EqualTo(simulator.SourceProjectFile)); + Assert.That(task.ProjectFiles[1], Is.EqualTo(simulator.TestProjectFile)); + }); + }); + }); + } +} diff --git a/test/Heleonix.Build.Tests/Tasks/Hx_NetFindSlnTests.cs b/test/Heleonix.Build.Tests/Tasks/Hx_NetFindSlnTests.cs new file mode 100644 index 0000000..06301ce --- /dev/null +++ b/test/Heleonix.Build.Tests/Tasks/Hx_NetFindSlnTests.cs @@ -0,0 +1,72 @@ +// +// Copyright (c) Heleonix - Hennadii Lutsyshyn. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the repository root for full license information. +// + +namespace Heleonix.Build.Tests.Tasks; + +/// +/// Tests the . +/// +[ComponentTest(Type = typeof(Hx_NetFindSln))] + +public static class Hx_NetFindSlnTests +{ + /// + /// Tests the . + /// + [MemberTest(Name = nameof(Hx_NetFindSln.Execute))] + public static void Execute() + { + Hx_NetFindSln task = null; + string workspaceDir = null; + var succeeded = false; + + Act(() => + { + task = new Hx_NetFindSln + { + BuildEngine = new TestBuildEngine(), + StartDir = workspaceDir, + }; + + succeeded = task.Execute(); + }); + + Teardown(() => + { + Directory.Delete(workspaceDir, true); + }); + + When("the task is executed", () => + { + And("the solution file exists", () => + { + workspaceDir = PathHelper.GetRandomFileNameInCurrentDir(); + + Directory.CreateDirectory(workspaceDir); + + File.WriteAllText(Path.Combine(workspaceDir, "My.sln"), "Solution's content"); + + Should("succeed with found solution file", () => + { + Assert.That(succeeded); + Assert.That(task.SlnFile, Is.EqualTo(Path.Combine(workspaceDir, "My.sln"))); + }); + }); + + And("the solution file does not exist", () => + { + workspaceDir = PathHelper.GetRandomFileNameInCurrentDir(); + + Directory.CreateDirectory(workspaceDir); + + Should("succeed without found solution file", () => + { + Assert.That(succeeded); + Assert.That(task.SlnFile, Is.Null); + }); + }); + }); + } +} diff --git a/test/Heleonix.Build.Tests/Tasks/Hx_NetSetupToolTests.cs b/test/Heleonix.Build.Tests/Tasks/Hx_NetSetupToolTests.cs new file mode 100644 index 0000000..cde76d3 --- /dev/null +++ b/test/Heleonix.Build.Tests/Tasks/Hx_NetSetupToolTests.cs @@ -0,0 +1,274 @@ +// +// Copyright (c) Heleonix - Hennadii Lutsyshyn. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the repository root for full license information. +// + +namespace Heleonix.Build.Tests.Tasks; + +/// +/// Tests the . +/// +[ComponentTest(Type = typeof(Hx_NetSetupTool))] + +public static class Hx_NetSetupToolTests +{ + /// + /// Tests the . + /// + [MemberTest(Name = nameof(Hx_NetSetupTool.Execute))] + public static void Execute() + { + Hx_NetSetupTool task = null; + string name = null; + string packageName = null; + string version = null; + var isPackage = false; + var succeeded = false; + TestBuildEngine buildEngine = null; + + Act(() => + { + buildEngine = new TestBuildEngine(); + + task = new Hx_NetSetupTool + { + BuildEngine = buildEngine, + Name = name, + PackageName = packageName, + IsPackage = isPackage, + Version = version, + DotnetExe = PathHelper.ExeMockFile, + }; + + succeeded = task.Execute(); + }); + + When("the task is executed", () => + { + And("the tool does not exist", () => + { + And("git tool is requested", () => + { + name = "git"; + + Should("succeed", () => + { + Assert.That(succeeded); + Assert.That(task.ToolPath, Is.EqualTo("git.exe")); + }); + }); + + And("reportgenerator is requested", () => + { + name = "reportgenerator"; + + Should("succeed", () => + { + Assert.That(succeeded); + Assert.That( + buildEngine.Messages, + Contains.Item( + "tool install dotnet-reportgenerator-globaltool" + + " --version 5.2.0 --tool-path " + Path.Combine(PathHelper.CurrentDir, "Tools"))); + Assert.That( + task.ToolPath, + Is.EqualTo(Path.Combine(PathHelper.CurrentDir, "Tools", "reportgenerator.exe"))); + }); + }); + + And("docfx is requested", () => + { + name = "docfx"; + + Should("succeed", () => + { + Assert.That(succeeded); + Assert.That( + buildEngine.Messages, + Contains.Item( + "tool install docfx" + + " --version 2.74.1 --tool-path " + Path.Combine(PathHelper.CurrentDir, "Tools"))); + Assert.That( + task.ToolPath, + Is.EqualTo(Path.Combine(PathHelper.CurrentDir, "Tools", "docfx.exe"))); + }); + }); + + And("extent is requested", () => + { + name = "extent"; + + Should("succeed", () => + { + Assert.That(succeeded); + Assert.That( + buildEngine.Messages, + Contains.Item( + "add package extent" + + " --version 0.0.3 --package-directory " + Path.Combine(PathHelper.CurrentDir, "Tools"))); + Assert.That( + task.ToolPath, + Is.EqualTo(Path.Combine(PathHelper.CurrentDir, "Tools", "extent", "0.0.3"))); + }); + }); + + And("NunitXml.TestLogger is requested", () => + { + name = "NunitXml.TestLogger"; + + Should("succeed", () => + { + Assert.That(succeeded); + Assert.That( + buildEngine.Messages, + Contains.Item( + "add package NunitXml.TestLogger" + + " --version 3.1.15 --package-directory " + Path.Combine(PathHelper.CurrentDir, "Tools"))); + Assert.That( + task.ToolPath, + Is.EqualTo(Path.Combine(PathHelper.CurrentDir, "Tools", "NunitXml.TestLogger", "3.1.15"))); + }); + }); + }); + + And("the package tool does not exist", () => + { + name = "SomeTool"; + isPackage = true; + + And("no versions are installed", () => + { + Arrange(() => + { + Directory.CreateDirectory(Path.Combine(PathHelper.CurrentDir, "Tools", name)); + }); + + Teardown(() => + { + Directory.Delete(Path.Combine(PathHelper.CurrentDir, "Tools", name), true); + }); + + Should("succeed and install the latest version", () => + { + Assert.That(succeeded); + Assert.That( + buildEngine.Messages, + Contains.Item( + "add package SomeTool" + + " --package-directory " + Path.Combine(PathHelper.CurrentDir, "Tools"))); + Assert.That(task.ToolPath, Is.Null); + }); + }); + + And("there is no package folder", () => + { + Should("succeed and install the latest version", () => + { + Assert.That(succeeded); + Assert.That( + buildEngine.Messages, + Contains.Item( + "add package SomeTool" + + " --package-directory " + Path.Combine(PathHelper.CurrentDir, "Tools"))); + Assert.That(task.ToolPath, Is.Null); + }); + }); + }); + + And("the dotnet tool exists", () => + { + isPackage = false; + + Arrange(() => + { + name = "docfx"; + + File.WriteAllText(Path.Combine(PathHelper.CurrentDir, "Tools", "docfx.exe"), "dummy exe"); + }); + + Teardown(() => + { + File.Delete(Path.Combine(PathHelper.CurrentDir, "Tools", "docfx.exe")); + }); + + Should("succeed", () => + { + Assert.That(succeeded); + Assert.That(buildEngine.Messages, Is.Empty); + Assert.That(task.ToolPath, Is.EqualTo(Path.Combine(PathHelper.CurrentDir, "Tools", "docfx.exe"))); + }); + }); + + And("the package tool exists", () => + { + isPackage = true; + + And("specific version is requested", () => + { + Arrange(() => + { + name = "SomeTool"; + version = "1.0.0"; + + Directory.CreateDirectory(Path.Combine(PathHelper.CurrentDir, "Tools", name, version)); + }); + + Teardown(() => + { + Directory.Delete(Path.Combine(PathHelper.CurrentDir, "Tools", name), true); + }); + + Should("succeed", () => + { + Assert.That(succeeded); + Assert.That(buildEngine.Messages, Is.Empty); + Assert.That(task.ToolPath, Is.EqualTo(Path.Combine(PathHelper.CurrentDir, "Tools", name, version))); + }); + }); + + And("version is not requested", () => + { + name = "SomeTool"; + version = null; + + And("several versions are installed", () => + { + Arrange(() => + { + Directory.CreateDirectory(Path.Combine(PathHelper.CurrentDir, "Tools", name, "1.0.0")); + Directory.CreateDirectory(Path.Combine(PathHelper.CurrentDir, "Tools", name, "1.0.1")); + }); + + Teardown(() => + { + Directory.Delete(Path.Combine(PathHelper.CurrentDir, "Tools", name), true); + }); + + Should("succeed and provide the latest version", () => + { + Assert.That(succeeded); + Assert.That(buildEngine.Messages, Is.Empty); + Assert.That(task.ToolPath, Is.EqualTo(Path.Combine(PathHelper.CurrentDir, "Tools", name, "1.0.1"))); + }); + }); + }); + }); + + And("installation fails", () => + { + name = "ERROR"; + isPackage = true; + + Should("fail", () => + { + Assert.That(!succeeded); + Assert.That(buildEngine.ErrorMessages, Contains.Item("ERROR details")); + Assert.That(buildEngine.Messages, Contains.Item("ERROR simulated")); + Assert.That( + buildEngine.Messages, + Contains.Item($"add package ERROR --package-directory \"{Path.Combine(PathHelper.CurrentDir, "Tools")}\"")); + }); + }); + }); + } +}