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")}\""));
+ });
+ });
+ });
+ }
+}