diff --git a/README.md b/README.md index e87954d..02bc95c 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ In this example: - `Arm`: Inputs are Azure ARM template parameter files with a `.json` extension. - `Yaml`: Inputs are YAML files with a `.yml` or `.yaml` extension. - **AdditionalProperties** *(optional)*: A collection of custom top-level properties to inject into the final output. Use the `ItemGroup` syntax to pass key-value pairs. +- **IsQuietMode** *(optional, default=false)*: Only emits warning and error level logs if true. ## Example YAML Input diff --git a/src/Task/AggregateConfig.cs b/src/Task/AggregateConfig.cs index f073261..261b895 100644 --- a/src/Task/AggregateConfig.cs +++ b/src/Task/AggregateConfig.cs @@ -14,7 +14,9 @@ namespace AggregateConfigBuildTask public class AggregateConfig : Task { private readonly IFileSystem fileSystem; + private ITaskLogger logger; + /* Start incoming properties */ [Required] public string InputDirectory { get; set; } @@ -30,14 +32,29 @@ public class AggregateConfig : Task public string[] AdditionalProperties { get; set; } + public bool IsQuietMode + { + get + { + return logger is QuietTaskLogger; + } + set + { + logger = value && !(logger is QuietTaskLogger) ? new QuietTaskLogger(Log) : logger; + } + } + /* End incoming properties */ + public AggregateConfig() { this.fileSystem = new FileSystem(); + this.logger = new TaskLogger(Log); } - internal AggregateConfig(IFileSystem fileSystem) + internal AggregateConfig(IFileSystem fileSystem, ITaskLogger logger) { this.fileSystem = fileSystem; + this.logger = logger; } public override bool Execute() @@ -51,7 +68,7 @@ public override bool Execute() if (!Enum.TryParse(OutputType, true, out OutputType outputType) || !Enum.IsDefined(typeof(OutputType), outputType)) { - Log.LogError("Invalid OutputType: {0}. Available options: {1}", OutputType, string.Join(", ", Enum.GetNames(typeof(OutputType)))); + logger.LogError("Invalid OutputType: {0}. Available options: {1}", OutputType, string.Join(", ", Enum.GetNames(typeof(OutputType)))); return false; } @@ -59,11 +76,11 @@ public override bool Execute() if (!string.IsNullOrEmpty(InputType) && (!Enum.TryParse(InputType, true, out inputType) || !Enum.IsDefined(typeof(InputType), inputType))) { - Log.LogError("Invalid InputType: {0}. Available options: {1}", InputType, string.Join(", ", Enum.GetNames(typeof(InputType)))); + logger.LogError("Invalid InputType: {0}. Available options: {1}", InputType, string.Join(", ", Enum.GetNames(typeof(InputType)))); return false; } - Log.LogMessage(MessageImportance.High, "Aggregating {0} to {1} in folder {2}", inputType, outputType, InputDirectory); + logger.LogMessage(MessageImportance.High, "Aggregating {0} to {1} in folder {2}", inputType, outputType, InputDirectory); string directoryPath = Path.GetDirectoryName(OutputFile); if (!fileSystem.DirectoryExists(directoryPath)) @@ -71,27 +88,27 @@ public override bool Execute() fileSystem.CreateDirectory(directoryPath); } - var finalResult = ObjectManager.MergeFileObjects(InputDirectory, inputType, AddSourceProperty, fileSystem, Log).GetAwaiter().GetResult(); + var finalResult = ObjectManager.MergeFileObjects(InputDirectory, inputType, AddSourceProperty, fileSystem, logger).GetAwaiter().GetResult(); if (finalResult == null) { - Log.LogError("No input was found! Check the input directory."); + logger.LogError("No input was found! Check the input directory."); return false; } var additionalPropertiesDictionary = JsonHelper.ParseAdditionalProperties(AdditionalProperties); - finalResult = ObjectManager.InjectAdditionalProperties(finalResult, additionalPropertiesDictionary, Log).GetAwaiter().GetResult(); + finalResult = ObjectManager.InjectAdditionalProperties(finalResult, additionalPropertiesDictionary, logger).GetAwaiter().GetResult(); var writer = FileHandlerFactory.GetOutputWriter(fileSystem, outputType); writer.WriteOutput(finalResult, OutputFile); - Log.LogMessage(MessageImportance.High, "Wrote aggregated configuration file to {0}", OutputFile); + logger.LogMessage(MessageImportance.High, "Wrote aggregated configuration file to {0}", OutputFile); return true; } catch (Exception ex) { - Log.LogError("An unknown exception occurred: {0}", ex.Message); - Log.LogErrorFromException(ex, true, true, null); + logger.LogError("An unknown exception occurred: {0}", ex.Message); + logger.LogErrorFromException(ex, true, true, null); return false; } } @@ -103,7 +120,7 @@ private void EmitHeader() .GetCustomAttribute()? .InformationalVersion; - Log.LogMessage(MessageImportance.High, $"AggregateConfig Version: {informationalVersion}"); + logger.LogMessage(MessageImportance.Normal, $"AggregateConfig Version: {informationalVersion}"); } } } diff --git a/src/Task/ObjectManager.cs b/src/Task/ObjectManager.cs index 1c1d91d..1f96d88 100644 --- a/src/Task/ObjectManager.cs +++ b/src/Task/ObjectManager.cs @@ -1,7 +1,6 @@ using AggregateConfigBuildTask.Contracts; using AggregateConfigBuildTask.FileHandlers; using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -14,7 +13,11 @@ namespace AggregateConfigBuildTask { internal static class ObjectManager { - public static async Task MergeFileObjects(string fileObjectDirectoryPath, InputType inputType, bool addSourceProperty, IFileSystem fileSystem, TaskLoggingHelper log) + public static async Task MergeFileObjects(string fileObjectDirectoryPath, + InputType inputType, + bool addSourceProperty, + IFileSystem fileSystem, + ITaskLogger log) { var finalResults = new ConcurrentBag(); JsonElement? finalResult = null; @@ -177,7 +180,7 @@ public static async Task MergeObjects(JsonElement? obj1, JsonElemen /// A dictionary of additional properties to inject. /// Logger reference. /// True if the properties were successfully injected, false otherwise. - public static async Task InjectAdditionalProperties(JsonElement? finalResult, Dictionary additionalPropertiesDictionary, TaskLoggingHelper log) + public static async Task InjectAdditionalProperties(JsonElement? finalResult, Dictionary additionalPropertiesDictionary, ITaskLogger log) { if (additionalPropertiesDictionary?.Count > 0) { diff --git a/src/Task/TaskLogger.cs b/src/Task/TaskLogger.cs new file mode 100644 index 0000000..85f4e1b --- /dev/null +++ b/src/Task/TaskLogger.cs @@ -0,0 +1,300 @@ +using System; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace AggregateConfigBuildTask +{ + /// + /// Interface for task logging helper methods. + /// + public interface ITaskLogger + { + /// + /// Logs an error message. + /// + /// The error message to log. + /// Optional arguments for formatting the message. + void LogError(string message = null, params object[] messageArgs); + + /// + /// Logs an error message with additional parameters. + /// + /// The subcategory of the error. + /// The error code. + /// The help keyword associated with the error. + /// The file in which the error occurred. + /// The line number where the error occurred. + /// The column number where the error occurred. + /// The end line number of the error. + /// The end column number of the error. + /// The error message to log. + /// Optional arguments for formatting the message. + void LogError( + string subcategory = null, + string errorCode = null, + string helpKeyword = null, + string file = null, + int lineNumber = 0, + int columnNumber = 0, + int endLineNumber = 0, + int endColumnNumber = 0, + string message = null, + params object[] messageArgs); + + /// + /// Logs an error message from an exception. + /// + /// The exception to log. + /// Indicates whether to show the stack trace. + /// Indicates whether to show detailed information. + /// The file where the exception occurred. + void LogErrorFromException(Exception exception, + bool showStackTrace = false, + bool showDetail = false, + string file = null); + + /// + /// Logs a warning message. + /// + /// The warning message to log. + /// Optional arguments for formatting the message. + void LogWarning(string message = null, params object[] messageArgs); + + /// + /// Logs a warning message with additional parameters. + /// + /// The subcategory of the warning. + /// The warning code. + /// The help keyword associated with the warning. + /// The file in which the warning occurred. + /// The line number where the warning occurred. + /// The column number where the warning occurred. + /// The end line number of the warning. + /// The end column number of the warning. + /// The warning message to log. + /// Optional arguments for formatting the message. + void LogWarning( + string subcategory = null, + string warningCode = null, + string helpKeyword = null, + string file = null, + int lineNumber = 0, + int columnNumber = 0, + int endLineNumber = 0, + int endColumnNumber = 0, + string message = null, + params object[] messageArgs); + + /// + /// Logs a message with specified importance. + /// + /// The importance level of the message. + /// The message to log. + /// Optional arguments for formatting the message. + void LogMessage(MessageImportance importance = MessageImportance.Normal, string message = null, params object[] messageArgs); + } + + /// + public class TaskLogger : ITaskLogger + { + /// + /// Gets the underlying TaskLoggingHelper. + /// + public TaskLoggingHelper Log { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The task that will be used for logging. + public TaskLogger(TaskLoggingHelper task) + { + if (task == null) + { + throw new ArgumentNullException(nameof(task)); + } + + Log = task; + } + + /// + public void LogError(string message = null, params object[] messageArgs) + { + Log.LogError(message, messageArgs); + } + + /// + public void LogError( + string subcategory = null, + string errorCode = null, + string helpKeyword = null, + string file = null, + int lineNumber = 0, + int columnNumber = 0, + int endLineNumber = 0, + int endColumnNumber = 0, + string message = null, + params object[] messageArgs) + { + Log.LogError( + subcategory, + errorCode, + helpKeyword, + file, + lineNumber, + columnNumber, + endLineNumber, + endColumnNumber, + message, + messageArgs); + } + + /// + public void LogErrorFromException(Exception exception, + bool showStackTrace = false, + bool showDetail = false, + string file = null) + { + Log.LogErrorFromException(exception, showStackTrace, showDetail, file); + } + + /// + public void LogWarning(string message = null, params object[] messageArgs) + { + Log.LogWarning(message, messageArgs); + } + + /// + public void LogWarning( + string subcategory = null, + string warningCode = null, + string helpKeyword = null, + string file = null, + int lineNumber = 0, + int columnNumber = 0, + int endLineNumber = 0, + int endColumnNumber = 0, + string message = null, + params object[] messageArgs) + { + Log.LogWarning( + subcategory, + warningCode, + helpKeyword, + file, + lineNumber, + columnNumber, + endLineNumber, + endColumnNumber, + message, + messageArgs); + } + + /// + public void LogMessage(MessageImportance importance = MessageImportance.Normal, string message = null, params object[] messageArgs) + { + Log.LogMessage(importance, message, messageArgs); + } + } + + /// + public class QuietTaskLogger : ITaskLogger + { + /// + /// Gets the underlying TaskLoggingHelper. + /// + public TaskLoggingHelper Log { get; } + + /// + /// Initializes a new instance of the class which + /// doesn't emit message level logs. + /// + /// The task that will be used for logging. + public QuietTaskLogger(TaskLoggingHelper task) + { + if (task == null) + { + throw new ArgumentNullException(nameof(task)); + } + + Log = task; + } + + /// + public void LogError(string message = null, params object[] messageArgs) + { + Log.LogError(message, messageArgs); + } + + /// + public void LogError( + string subcategory = null, + string errorCode = null, + string helpKeyword = null, + string file = null, + int lineNumber = 0, + int columnNumber = 0, + int endLineNumber = 0, + int endColumnNumber = 0, + string message = null, + params object[] messageArgs) + { + Log.LogError( + subcategory, + errorCode, + helpKeyword, + file, + lineNumber, + columnNumber, + endLineNumber, + endColumnNumber, + message, + messageArgs); + } + + /// + public void LogErrorFromException(Exception exception, + bool showStackTrace = false, + bool showDetail = false, + string file = null) + { + Log.LogErrorFromException(exception, showStackTrace, showDetail, file); + } + + /// + public void LogWarning(string message = null, params object[] messageArgs) + { + Log.LogWarning(message, messageArgs); + } + + /// + public void LogWarning( + string subcategory = null, + string warningCode = null, + string helpKeyword = null, + string file = null, + int lineNumber = 0, + int columnNumber = 0, + int endLineNumber = 0, + int endColumnNumber = 0, + string message = null, + params object[] messageArgs) + { + Log.LogWarning( + subcategory, + warningCode, + helpKeyword, + file, + lineNumber, + columnNumber, + endLineNumber, + endColumnNumber, + message, + messageArgs); + } + + /// + public void LogMessage(MessageImportance importance = MessageImportance.Normal, string message = null, params object[] messageArgs) + { + } + } +} diff --git a/src/UnitTests/TaskTestBase.cs b/src/UnitTests/TaskTestBase.cs index c1354b5..1b4a9ab 100644 --- a/src/UnitTests/TaskTestBase.cs +++ b/src/UnitTests/TaskTestBase.cs @@ -13,14 +13,17 @@ namespace AggregateConfigBuildTask.Tests.Unit public class TaskTestBase { private string testPath; - internal IFileSystem mockFileSystem; private StringComparison comparison = StringComparison.OrdinalIgnoreCase; + private Mock mockLogger; + internal IFileSystem virtualFileSystem; + public void TestInitialize(bool isWindowsMode, string testPath) { this.testPath = testPath; - this.mockFileSystem = new VirtualFileSystem(isWindowsMode); - mockFileSystem.CreateDirectory(testPath); + this.mockLogger = new Mock { DefaultValue = DefaultValue.Mock }; + this.virtualFileSystem = new VirtualFileSystem(isWindowsMode); + this.virtualFileSystem.CreateDirectory(testPath); } [TestMethod] @@ -28,16 +31,16 @@ public void TestInitialize(bool isWindowsMode, string testPath) public void ShouldGenerateJsonOutput() { // Arrange: Prepare sample YAML data in the mock file system. - mockFileSystem.WriteAllText($"{testPath}\\file1.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\file1.yml", @" options: - name: 'Option 1' description: 'First option'"); - mockFileSystem.WriteAllText($"{testPath}\\file2.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\file2.yml", @" options: - name: 'Option 2' description: 'Second option'"); - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputDirectory = testPath, OutputFile = testPath + @"\output.json", @@ -51,7 +54,7 @@ public void ShouldGenerateJsonOutput() // Assert: Check that output was generated correctly. Assert.IsTrue(result); - string output = mockFileSystem.ReadAllText($"{testPath}\\output.json"); + string output = virtualFileSystem.ReadAllText($"{testPath}\\output.json"); var json = JsonConvert.DeserializeObject>(output); Assert.IsTrue(json.ContainsKey("options")); Assert.AreEqual(2, ((IEnumerable)json.GetValueOrDefault("options")).Count()); @@ -62,17 +65,17 @@ public void ShouldGenerateJsonOutput() public void ShouldGenerateArmParameterOutput() { // Arrange: Prepare sample YAML data in the mock file system. - mockFileSystem.WriteAllText($"{testPath}\\file1.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\file1.yml", @" options: - name: 'Option 1' description: 'First option'"); - mockFileSystem.WriteAllText($"{testPath}\\file2.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\file2.yml", @" options: - name: 'Option 2' description: 'Second option'"); // Create the task instance with the mock file system - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputDirectory = testPath, OutputFile = testPath + @"\output.parameters.json", @@ -86,7 +89,7 @@ public void ShouldGenerateArmParameterOutput() // Assert: Check the ARM output structure Assert.IsTrue(result); - string output = mockFileSystem.ReadAllText($"{testPath}\\output.parameters.json"); + string output = virtualFileSystem.ReadAllText($"{testPath}\\output.parameters.json"); var armTemplate = JsonConvert.DeserializeObject>(output); Assert.IsTrue(armTemplate.ContainsKey("parameters")); @@ -100,13 +103,13 @@ public void ShouldGenerateArmParameterOutput() public void ShouldAddSourceProperty() { // Arrange: Prepare sample YAML data with source property enabled. - mockFileSystem.WriteAllText($"{testPath}\\file1.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\file1.yml", @" options: - name: 'Option 1' description: 'First option'"); // Create the task instance with the mock file system - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputDirectory = testPath, OutputFile = testPath + @"\output.json", @@ -120,7 +123,7 @@ public void ShouldAddSourceProperty() // Assert: Verify that the source property was added Assert.IsTrue(result); - string output = mockFileSystem.ReadAllText($"{testPath}\\output.json"); + string output = virtualFileSystem.ReadAllText($"{testPath}\\output.json"); var json = JsonConvert.DeserializeObject>>>(output); Assert.IsTrue(json["options"][0].ContainsKey("source")); Assert.AreEqual("file1", json["options"][0]["source"]); @@ -131,17 +134,17 @@ public void ShouldAddSourceProperty() public void ShouldAddSourcePropertyMultipleFiles() { // Arrange: Prepare sample YAML data with source property enabled. - mockFileSystem.WriteAllText($"{testPath}\\file1.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\file1.yml", @" options: - name: 'Option 1' description: 'First option' additionalOptions: value: 'Good day'"); - mockFileSystem.WriteAllText($"{testPath}\\file2.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\file2.yml", @" options: - name: 'Option 2' description: 'Second option' - - name: 'Option 3' + - name: '''Option 3''' description: 'Third option' additionalOptions: value: 'Good night' @@ -150,7 +153,7 @@ public void ShouldAddSourcePropertyMultipleFiles() description: 'Text'"); // Create the task instance with the mock file system - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputDirectory = testPath, OutputFile = testPath + @"\output.json", @@ -164,11 +167,11 @@ public void ShouldAddSourcePropertyMultipleFiles() // Assert: Verify that the source property was added Assert.IsTrue(result); - string output = mockFileSystem.ReadAllText($"{testPath}\\output.json"); + string output = virtualFileSystem.ReadAllText($"{testPath}\\output.json"); var json = JsonConvert.DeserializeObject>>>(output); Assert.IsTrue(OptionExistsWithSource(json["options"], "Option 1", "file1")); Assert.IsTrue(OptionExistsWithSource(json["options"], "Option 2", "file2")); - Assert.IsTrue(OptionExistsWithSource(json["options"], "Option 3", "file2")); + Assert.IsTrue(OptionExistsWithSource(json["options"], "'Option 3'", "file2")); Assert.IsTrue(OptionExistsWithSource(json["text"], "Text 1", "file2")); } @@ -177,12 +180,12 @@ public void ShouldAddSourcePropertyMultipleFiles() public void ShouldIncludeAdditionalPropertiesInJson() { // Arrange: Prepare sample YAML data. - mockFileSystem.WriteAllText($"{testPath}\\file1.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\file1.yml", @" options: - name: 'Option 1' description: 'First option'"); - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputDirectory = testPath, OutputFile = testPath + @"\output.json", @@ -201,7 +204,7 @@ public void ShouldIncludeAdditionalPropertiesInJson() // Assert: Verify additional properties are included Assert.IsTrue(result); - string output = mockFileSystem.ReadAllText($"{testPath}\\output.json"); + string output = virtualFileSystem.ReadAllText($"{testPath}\\output.json"); var json = JsonConvert.DeserializeObject>(output); Assert.AreEqual("TestRG", json["Group"]); Assert.AreEqual("Prod=West", json["Environment=Key"]); @@ -212,12 +215,12 @@ public void ShouldIncludeAdditionalPropertiesInJson() public void ShouldIncludeAdditionalPropertiesInArmParameters() { // Arrange: Prepare sample YAML data. - mockFileSystem.WriteAllText($"{testPath}\\file1.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\file1.yml", @" options: - name: 'Option 1' description: 'First option'"); - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputDirectory = testPath, OutputFile = testPath + @"\output.json", @@ -236,7 +239,7 @@ public void ShouldIncludeAdditionalPropertiesInArmParameters() // Assert: Verify additional properties are included in ARM output Assert.IsTrue(result); - string output = mockFileSystem.ReadAllText($"{testPath}\\output.json"); + string output = virtualFileSystem.ReadAllText($"{testPath}\\output.json"); var armTemplate = JsonConvert.DeserializeObject>(output); JObject parameters = (JObject)armTemplate["parameters"]; Assert.AreEqual("array", parameters.GetValue("options", comparison)["type"].ToString()); @@ -249,7 +252,7 @@ public void ShouldIncludeAdditionalPropertiesInArmParameters() public void ShouldHandleEmptyDirectory() { // Arrange: No files added to the mock file system (empty directory). - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputDirectory = testPath, OutputFile = testPath + @"\output.json", @@ -262,7 +265,7 @@ public void ShouldHandleEmptyDirectory() // Assert: Ensure the task fails and output is empty Assert.IsFalse(result); - bool outputExists = mockFileSystem.FileExists($"{testPath}\\output.json"); + bool outputExists = virtualFileSystem.FileExists($"{testPath}\\output.json"); Assert.IsFalse(outputExists, "No file should have been created!"); } @@ -271,12 +274,12 @@ public void ShouldHandleEmptyDirectory() public void ShouldHandleInvalidYamlFormat() { // Arrange: Add invalid YAML file to the mock file system. - mockFileSystem.WriteAllText($"{testPath}\\invalid.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\invalid.yml", @" options: - name: 'Option 1' description: 'Unclosed value"); - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputDirectory = testPath, OutputFile = testPath + @"\output.json", @@ -296,13 +299,13 @@ public void ShouldHandleInvalidYamlFormat() public void ShouldCorrectlyParseBooleanValues() { // Arrange: Prepare sample YAML data. - mockFileSystem.WriteAllText($"{testPath}\\file1.yml", @" + virtualFileSystem.WriteAllText($"{testPath}\\file1.yml", @" options: - name: 'Option 1' description: 'First option' isEnabled: true"); - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputDirectory = testPath, OutputFile = testPath + @"\output.json", @@ -315,7 +318,7 @@ public void ShouldCorrectlyParseBooleanValues() // Assert: Verify additional properties are included in ARM output Assert.IsTrue(result); - string output = mockFileSystem.ReadAllText($"{testPath}\\output.json"); + string output = virtualFileSystem.ReadAllText($"{testPath}\\output.json"); var armTemplate = JsonConvert.DeserializeObject>(output); JObject parameters = (JObject)armTemplate["parameters"]; Assert.AreEqual("array", parameters.GetValue("options", comparison)["type"].ToString()); @@ -328,7 +331,7 @@ public void ShouldCorrectlyParseBooleanValues() public void ShouldIncludeAdditionalPropertiesInJsonInput() { // Arrange: Prepare sample JSON data. - mockFileSystem.WriteAllText($"{testPath}\\file1.json", @" + virtualFileSystem.WriteAllText($"{testPath}\\file1.json", @" { ""options"": [ { @@ -339,7 +342,7 @@ public void ShouldIncludeAdditionalPropertiesInJsonInput() ] }"); - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputType = InputType.Json.ToString(), InputDirectory = testPath, @@ -359,7 +362,7 @@ public void ShouldIncludeAdditionalPropertiesInJsonInput() // Assert: Verify additional properties are included in ARM output Assert.IsTrue(result); - string output = mockFileSystem.ReadAllText($"{testPath}\\output.json"); + string output = virtualFileSystem.ReadAllText($"{testPath}\\output.json"); var armTemplate = JsonConvert.DeserializeObject>(output); JObject parameters = (JObject)armTemplate["parameters"]; Assert.AreEqual("TestRG", parameters.GetValue("Group", comparison)["value"].Value()); @@ -375,7 +378,7 @@ public void ShouldIncludeAdditionalPropertiesInJsonInput() public void ShouldIncludeAdditionalPropertiesInArmParameterFile() { // Arrange: Prepare ARM template parameter file data in 'file1.parameters.json'. - mockFileSystem.WriteAllText($"{testPath}\\file1.parameters.json", @" + virtualFileSystem.WriteAllText($"{testPath}\\file1.parameters.json", @" { ""parameters"": { ""options"": { @@ -391,7 +394,7 @@ public void ShouldIncludeAdditionalPropertiesInArmParameterFile() } }"); - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputType = InputType.Arm.ToString(), InputDirectory = testPath, @@ -401,7 +404,7 @@ public void ShouldIncludeAdditionalPropertiesInArmParameterFile() AdditionalProperties = new Dictionary { { "Group", "TestRG" }, - { "Environment", "Prod" } + { "Environment", "'Prod'" } }.Select(q => $"{q.Key}={q.Value}").ToArray(), BuildEngine = Mock.Of() }; @@ -411,11 +414,11 @@ public void ShouldIncludeAdditionalPropertiesInArmParameterFile() // Assert: Verify additional properties are included in ARM output Assert.IsTrue(result); - string output = mockFileSystem.ReadAllText($"{testPath}\\output.parameters.json"); + string output = virtualFileSystem.ReadAllText($"{testPath}\\output.parameters.json"); var armTemplate = JsonConvert.DeserializeObject>(output); JObject parameters = (JObject)armTemplate["parameters"]; Assert.AreEqual("TestRG", parameters.GetValue("Group", comparison)["value"].Value()); - Assert.AreEqual("Prod", parameters.GetValue("Environment", comparison)["value"].Value()); + Assert.AreEqual("'Prod'", parameters.GetValue("Environment", comparison)["value"].Value()); Assert.AreEqual("String", parameters.GetValue("options", comparison)["value"].First()["source"].Type.ToString()); Assert.AreEqual("file1.parameters", parameters.GetValue("options", comparison)["value"].First()["source"].Value()); Assert.AreEqual("Boolean", parameters.GetValue("options", comparison)["value"].First()["isEnabled"].Type.ToString()); @@ -443,10 +446,10 @@ public void StressTest_ShouldAddSourcePropertyManyFiles() } // Write each YAML file to the mock file system - mockFileSystem.WriteAllText($"{testPath}\\file{fileIndex}.yml", sb.ToString()); + virtualFileSystem.WriteAllText($"{testPath}\\file{fileIndex}.yml", sb.ToString()); } - var task = new AggregateConfig(mockFileSystem) + var task = new AggregateConfig(virtualFileSystem, mockLogger.Object) { InputDirectory = testPath, OutputFile = testPath + @"\output.json", @@ -460,7 +463,7 @@ public void StressTest_ShouldAddSourcePropertyManyFiles() // Assert: Verify that the source property was added correctly for all files and options Assert.IsTrue(result); - string output = mockFileSystem.ReadAllText($"{testPath}\\output.json"); + string output = virtualFileSystem.ReadAllText($"{testPath}\\output.json"); var json = JsonConvert.DeserializeObject>>>(output); int optionIndexInTotal = 0; diff --git a/test/IntegrationTests/IntegrationTests.csproj b/test/IntegrationTests/IntegrationTests.csproj index 174a210..ba711d9 100644 --- a/test/IntegrationTests/IntegrationTests.csproj +++ b/test/IntegrationTests/IntegrationTests.csproj @@ -1,4 +1,4 @@ - + AggregateConfig.Tests.Integration @@ -63,7 +63,8 @@ InputDirectory="$(MSBuildProjectDirectory)\out\arm" OutputFile="$(MSBuildProjectDirectory)\out\arm2yml\out.yml" OutputType="Yaml" - AddSourceProperty="true" /> + AddSourceProperty="true" + IsQuietMode="true" />