diff --git a/src/.editorconfig b/src/.editorconfig
index 1f62320..bcabf23 100644
--- a/src/.editorconfig
+++ b/src/.editorconfig
@@ -2,3 +2,10 @@
# CS1591: Missing XML comment for publicly visible type or member
dotnet_diagnostic.CS1591.severity = suggestion
+
+# Organize usings
+dotnet_sort_system_directives_first = true
+dotnet_separate_import_directive_groups = true
+
+# Missing usings should be reported as error (IDE0005)
+dotnet_diagnostic.IDE0005.severity = error
diff --git a/src/AggregateConfigBuildTask.sln b/src/AggregateConfigBuildTask.sln
index 17957ab..d4bf6f8 100644
--- a/src/AggregateConfigBuildTask.sln
+++ b/src/AggregateConfigBuildTask.sln
@@ -12,6 +12,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{29D0AE56-C184-4741-824F-521198552928}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
+ Directory.Build.props = Directory.Build.props
Directory.Packages.props = Directory.Packages.props
EndProjectSection
EndProject
diff --git a/src/Contracts/Contracts.csproj b/src/Contracts/Contracts.csproj
index 56a26c6..077033a 100644
--- a/src/Contracts/Contracts.csproj
+++ b/src/Contracts/Contracts.csproj
@@ -2,7 +2,7 @@
netstandard2.0
- true
+ CA1027
diff --git a/src/Contracts/InputOutputEnums.cs b/src/Contracts/InputOutputEnums.cs
index e81f362..f5d8fd3 100644
--- a/src/Contracts/InputOutputEnums.cs
+++ b/src/Contracts/InputOutputEnums.cs
@@ -1,20 +1,20 @@
namespace AggregateConfigBuildTask.Contracts
{
- public enum OutputTypeEnum
+ public enum OutputType
{
- Json,
- Arm,
+ Json = 0,
+ Arm = 1,
ArmParameter = Arm,
- Yml,
+ Yml = 2,
Yaml = Yml
}
- public enum InputTypeEnum
+ public enum InputType
{
- Json,
- Arm,
+ Json = 0,
+ Arm = 1,
ArmParameter = Arm,
- Yml,
+ Yml = 2,
Yaml = Yml
}
}
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
new file mode 100644
index 0000000..5766305
--- /dev/null
+++ b/src/Directory.Build.props
@@ -0,0 +1,13 @@
+
+
+
+ true
+ true
+ true
+ latest
+ false
+ false
+ AllEnabledByDefault
+
+
+
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 6233193..ff1e112 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -25,6 +25,8 @@
+
+
diff --git a/src/Task/AggregateConfig.cs b/src/Task/AggregateConfig.cs
index bc9aaf0..f073261 100644
--- a/src/Task/AggregateConfig.cs
+++ b/src/Task/AggregateConfig.cs
@@ -26,7 +26,7 @@ public class AggregateConfig : Task
[Required]
public string OutputType { get; set; }
- public bool AddSourceProperty { get; set; } = false;
+ public bool AddSourceProperty { get; set; }
public string[] AdditionalProperties { get; set; }
@@ -48,18 +48,18 @@ public override bool Execute()
OutputFile = Path.GetFullPath(OutputFile);
- if (!Enum.TryParse(OutputType, true, out OutputTypeEnum outputType) ||
- !Enum.IsDefined(typeof(OutputTypeEnum), outputType))
+ 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(OutputTypeEnum))));
+ Log.LogError("Invalid OutputType: {0}. Available options: {1}", OutputType, string.Join(", ", Enum.GetNames(typeof(OutputType))));
return false;
}
- InputTypeEnum inputType = InputTypeEnum.Yaml;
+ InputType inputType = Contracts.InputType.Yaml;
if (!string.IsNullOrEmpty(InputType) &&
- (!Enum.TryParse(InputType, true, out inputType) || !Enum.IsDefined(typeof(InputTypeEnum), 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(InputTypeEnum))));
+ Log.LogError("Invalid InputType: {0}. Available options: {1}", InputType, string.Join(", ", Enum.GetNames(typeof(InputType))));
return false;
}
@@ -103,7 +103,7 @@ private void EmitHeader()
.GetCustomAttribute()?
.InformationalVersion;
- Log.LogMessage($"AggregateConfig Version: {informationalVersion}");
+ Log.LogMessage(MessageImportance.High, $"AggregateConfig Version: {informationalVersion}");
}
}
}
diff --git a/src/Task/AggregateConfigBuildTask.csproj b/src/Task/AggregateConfigBuildTask.csproj
index af74e8f..a1ed647 100644
--- a/src/Task/AggregateConfigBuildTask.csproj
+++ b/src/Task/AggregateConfigBuildTask.csproj
@@ -2,13 +2,11 @@
netstandard2.0
- true
true
- true
true
true
true
- NU5100
+ NU5100,CA1031,CA1819
diff --git a/src/Task/FileHandlers/ArmParametersFileHandler.cs b/src/Task/FileHandlers/ArmParametersFileHandler.cs
index 51ef876..7a659b2 100644
--- a/src/Task/FileHandlers/ArmParametersFileHandler.cs
+++ b/src/Task/FileHandlers/ArmParametersFileHandler.cs
@@ -8,7 +8,9 @@ namespace AggregateConfigBuildTask.FileHandlers
{
public class ArmParametersFileHandler : IOutputWriter, IInputReader
{
- readonly IFileSystem fileSystem;
+ private readonly IFileSystem fileSystem;
+
+ private readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions { WriteIndented = true };
internal ArmParametersFileHandler(IFileSystem fileSystem)
{
@@ -16,11 +18,11 @@ internal ArmParametersFileHandler(IFileSystem fileSystem)
}
///
- public ValueTask ReadInput(string inputPath)
+ public async ValueTask ReadInput(string inputPath)
{
using (var stream = fileSystem.OpenRead(inputPath))
{
- using (var jsonDoc = JsonDocument.Parse(stream))
+ using (var jsonDoc = await JsonDocument.ParseAsync(stream).ConfigureAwait(false))
{
if (jsonDoc.RootElement.TryGetProperty("parameters", out JsonElement parameters))
{
@@ -41,10 +43,10 @@ public ValueTask ReadInput(string inputPath)
}
var modifiedJson = modifiedParameters.ToJsonString();
- return new ValueTask(Task.FromResult(JsonSerializer.Deserialize(modifiedJson)));
+ return JsonSerializer.Deserialize(modifiedJson);
}
- return new ValueTask(Task.FromResult(jsonDoc.RootElement.Clone()));
+ return jsonDoc.RootElement.Clone();
}
}
}
@@ -74,8 +76,6 @@ public void WriteOutput(JsonElement? mergedData, string outputPath)
["contentVersion"] = "1.0.0.0",
["parameters"] = parameters
};
-
- var jsonOptions = new JsonSerializerOptions { WriteIndented = true };
var jsonContent = JsonSerializer.Serialize(armTemplate, jsonOptions);
fileSystem.WriteAllText(outputPath, jsonContent);
}
@@ -90,7 +90,7 @@ public void WriteOutput(JsonElement? mergedData, string outputPath)
///
/// The JsonElement value to evaluate.
/// A string representing the ARM template parameter type.
- private string GetParameterType(JsonElement value)
+ private static string GetParameterType(JsonElement value)
{
switch (value.ValueKind)
{
@@ -115,7 +115,7 @@ private string GetParameterType(JsonElement value)
}
}
- private JsonNode ConvertElementToNode(JsonElement element)
+ private static JsonNode ConvertElementToNode(JsonElement element)
{
// Use GetRawText to get the JSON string representation of the JsonElement
var jsonString = element.GetRawText();
diff --git a/src/Task/FileHandlers/FileHandlerFactory.cs b/src/Task/FileHandlers/FileHandlerFactory.cs
index bc13876..a7f9c0d 100644
--- a/src/Task/FileHandlers/FileHandlerFactory.cs
+++ b/src/Task/FileHandlers/FileHandlerFactory.cs
@@ -6,45 +6,45 @@ namespace AggregateConfigBuildTask.FileHandlers
{
public static class FileHandlerFactory
{
- internal static IOutputWriter GetOutputWriter(IFileSystem fileSystem, OutputTypeEnum format)
+ internal static IOutputWriter GetOutputWriter(IFileSystem fileSystem, OutputType format)
{
switch (format)
{
- case OutputTypeEnum.Json:
+ case OutputType.Json:
return new JsonFileHandler(fileSystem);
- case OutputTypeEnum.Yaml:
+ case OutputType.Yaml:
return new YamlFileHandler(fileSystem);
- case OutputTypeEnum.Arm:
+ case OutputType.Arm:
return new ArmParametersFileHandler(fileSystem);
default:
throw new ArgumentException("Unsupported format");
}
}
- internal static IInputReader GetInputReader(IFileSystem fileSystem, InputTypeEnum format)
+ internal static IInputReader GetInputReader(IFileSystem fileSystem, InputType format)
{
switch (format)
{
- case InputTypeEnum.Yaml:
+ case InputType.Yaml:
return new YamlFileHandler(fileSystem);
- case InputTypeEnum.Json:
+ case InputType.Json:
return new JsonFileHandler(fileSystem);
- case InputTypeEnum.Arm:
+ case InputType.Arm:
return new ArmParametersFileHandler(fileSystem);
default:
throw new ArgumentException("Unsupported input format");
}
}
- internal static List GetExpectedFileExtensions(InputTypeEnum inputType)
+ internal static List GetExpectedFileExtensions(InputType inputType)
{
switch (inputType)
{
- case InputTypeEnum.Json:
+ case InputType.Json:
return new List { ".json" };
- case InputTypeEnum.Yaml:
+ case InputType.Yaml:
return new List { ".yml", ".yaml" };
- case InputTypeEnum.Arm:
+ case InputType.Arm:
return new List { ".json" };
default:
throw new ArgumentException("Unsupported input type");
diff --git a/src/Task/FileHandlers/JsonFileHandler.cs b/src/Task/FileHandlers/JsonFileHandler.cs
index 5f67e7a..b64e343 100644
--- a/src/Task/FileHandlers/JsonFileHandler.cs
+++ b/src/Task/FileHandlers/JsonFileHandler.cs
@@ -7,6 +7,8 @@ public class JsonFileHandler : IOutputWriter, IInputReader
{
readonly IFileSystem fileSystem;
+ private readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions { WriteIndented = true };
+
internal JsonFileHandler(IFileSystem fileSystem)
{
this.fileSystem = fileSystem;
@@ -24,7 +26,6 @@ public ValueTask ReadInput(string inputPath)
///
public void WriteOutput(JsonElement? mergedData, string outputPath)
{
- var jsonOptions = new JsonSerializerOptions { WriteIndented = true };
var jsonContent = JsonSerializer.Serialize(mergedData, jsonOptions);
fileSystem.WriteAllText(outputPath, jsonContent);
}
diff --git a/src/Task/FileSystem/FileSystem.cs b/src/Task/FileSystem/FileSystem.cs
index 70914bc..f3d3c8a 100644
--- a/src/Task/FileSystem/FileSystem.cs
+++ b/src/Task/FileSystem/FileSystem.cs
@@ -2,7 +2,7 @@
namespace AggregateConfigBuildTask
{
- internal class FileSystem : IFileSystem
+ internal sealed class FileSystem : IFileSystem
{
///
public string[] GetFiles(string path, string searchPattern)
diff --git a/src/Task/JsonHelper.cs b/src/Task/JsonHelper.cs
index 46a1073..b48ebb3 100644
--- a/src/Task/JsonHelper.cs
+++ b/src/Task/JsonHelper.cs
@@ -72,6 +72,7 @@ public static Dictionary ParseAdditionalProperties(string[] prop
{
var additionalPropertiesDict = new Dictionary();
const string unicodeEscape = "\u001F";
+ char[] split = new[] { '=' };
if (properties != null)
{
@@ -79,7 +80,7 @@ public static Dictionary ParseAdditionalProperties(string[] prop
{
var sanitizedProperty = property.Replace(@"\=", unicodeEscape);
- var keyValue = sanitizedProperty.Split(new[] { '=' }, 2);
+ var keyValue = sanitizedProperty.Split(split, 2);
if (keyValue.Length == 2)
{
@@ -104,10 +105,10 @@ public static async Task ConvertObjectToJsonElement(object value)
using (var memoryStream = new MemoryStream())
{
- await JsonSerializer.SerializeAsync(memoryStream, value);
+ await JsonSerializer.SerializeAsync(memoryStream, value).ConfigureAwait(false);
memoryStream.Seek(0, SeekOrigin.Begin);
- using (var jsonDocument = await JsonDocument.ParseAsync(memoryStream))
+ using (var jsonDocument = await JsonDocument.ParseAsync(memoryStream).ConfigureAwait(false))
{
return jsonDocument.RootElement.Clone();
}
diff --git a/src/Task/ObjectManager.cs b/src/Task/ObjectManager.cs
index 8a5ad02..1c1d91d 100644
--- a/src/Task/ObjectManager.cs
+++ b/src/Task/ObjectManager.cs
@@ -14,7 +14,7 @@ namespace AggregateConfigBuildTask
{
internal static class ObjectManager
{
- public static async Task MergeFileObjects(string fileObjectDirectoryPath, InputTypeEnum inputType, bool addSourceProperty, IFileSystem fileSystem, TaskLoggingHelper log)
+ public static async Task MergeFileObjects(string fileObjectDirectoryPath, InputType inputType, bool addSourceProperty, IFileSystem fileSystem, TaskLoggingHelper log)
{
var finalResults = new ConcurrentBag();
JsonElement? finalResult = null;
@@ -22,7 +22,7 @@ internal static class ObjectManager
var expectedExtensions = FileHandlerFactory.GetExpectedFileExtensions(inputType);
var fileGroups = fileSystem.GetFiles(fileObjectDirectoryPath, "*.*")
- .Where(file => expectedExtensions.Contains(Path.GetExtension(file).ToLower()))
+ .Where(file => expectedExtensions.Contains(Path.GetExtension(file), StringComparer.OrdinalIgnoreCase))
.ToList()
.Chunk(100);
@@ -48,7 +48,7 @@ await fileGroups.ForEachAsync(Environment.ProcessorCount,
JsonElement fileData;
try
{
- fileData = await outputWriter.ReadInput(file);
+ fileData = await outputWriter.ReadInput(file).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -59,9 +59,9 @@ await fileGroups.ForEachAsync(Environment.ProcessorCount,
}
// Merge the deserialized object into the final result
- finalResults.Add(await ObjectManager.MergeObjects(intermediateResult, fileData, file, addSourceProperty));
+ finalResults.Add(await MergeObjects(intermediateResult, fileData, file, addSourceProperty).ConfigureAwait(false));
}
- });
+ }).ConfigureAwait(false);
if (hasError)
{
@@ -70,7 +70,7 @@ await fileGroups.ForEachAsync(Environment.ProcessorCount,
foreach (var result in finalResults)
{
- finalResult = await ObjectManager.MergeObjects(finalResult, result, null, false);
+ finalResult = await MergeObjects(finalResult, result, null, false).ConfigureAwait(false);
}
return finalResult;
@@ -106,14 +106,14 @@ await fileGroups.ForEachAsync(Environment.ProcessorCount,
nestedDict["source"] = JsonDocument.Parse($"\"{Path.GetFileNameWithoutExtension(source2)}\"").RootElement;
// Update the list at the correct index
- obj2NestedList[index] = await JsonHelper.ConvertToJsonElement(nestedDict);
+ obj2NestedList[index] = await JsonHelper.ConvertToJsonElement(nestedDict).ConfigureAwait(false);
}
}
- jsonObject[key] = await JsonHelper.ConvertToJsonElement(obj2NestedList);
+ jsonObject[key] = await JsonHelper.ConvertToJsonElement(obj2NestedList).ConfigureAwait(false);
}
}
- obj2 = await JsonHelper.ConvertObjectToJsonElement(jsonObject);
+ obj2 = await JsonHelper.ConvertObjectToJsonElement(jsonObject).ConfigureAwait(false);
}
return obj2;
@@ -124,11 +124,11 @@ await fileGroups.ForEachAsync(Environment.ProcessorCount,
///
public static async Task MergeObjects(JsonElement? obj1, JsonElement? obj2, string source2, bool injectSourceProperty)
{
- obj1 = await InjectSourceProperty(obj1, source2, injectSourceProperty);
- obj2 = await InjectSourceProperty(obj2, source2, injectSourceProperty);
+ obj1 = await InjectSourceProperty(obj1, source2, injectSourceProperty).ConfigureAwait(false);
+ obj2 = await InjectSourceProperty(obj2, source2, injectSourceProperty).ConfigureAwait(false);
if (obj1 == null) return obj2 ?? default;
- if (obj2 == null) return obj1 ?? default;
+ if (obj2 == null) return obj1.Value;
// Handle merging of objects
if (obj1.Value.ValueKind == JsonValueKind.Object && obj2.Value.ValueKind == JsonValueKind.Object)
@@ -138,9 +138,9 @@ public static async Task MergeObjects(JsonElement? obj1, JsonElemen
foreach (var key in dict2.Keys)
{
- if (dict1.ContainsKey(key))
+ if (dict1.TryGetValue(key, out JsonElement dict1Value))
{
- dict1[key] = await MergeObjects(dict1[key], dict2[key], source2, injectSourceProperty);
+ dict1[key] = await MergeObjects(dict1Value, dict2[key], source2, injectSourceProperty).ConfigureAwait(false);
}
else
{
@@ -148,7 +148,7 @@ public static async Task MergeObjects(JsonElement? obj1, JsonElemen
}
}
- return await JsonHelper.ConvertToJsonElement(dict1);
+ return await JsonHelper.ConvertToJsonElement(dict1).ConfigureAwait(false);
}
// Handle merging of arrays
else if (obj1.Value.ValueKind == JsonValueKind.Array && obj2.Value.ValueKind == JsonValueKind.Array)
@@ -161,7 +161,7 @@ public static async Task MergeObjects(JsonElement? obj1, JsonElemen
list1.Add(item);
}
- return await JsonHelper.ConvertToJsonElement(list1);
+ return await JsonHelper.ConvertToJsonElement(list1).ConfigureAwait(false);
}
// For scalar values, obj2 overwrites obj1
else
@@ -188,10 +188,10 @@ public static async Task MergeObjects(JsonElement? obj1, JsonElemen
// Add the properties from additionalPropertiesDictionary, converting values to JsonElement
foreach (var property in additionalPropertiesDictionary)
{
- jsonDictionary[property.Key] = await JsonHelper.ConvertObjectToJsonElement(property.Value);
+ jsonDictionary[property.Key] = await JsonHelper.ConvertObjectToJsonElement(property.Value).ConfigureAwait(false);
}
- return await JsonHelper.ConvertToJsonElement(jsonDictionary);
+ return await JsonHelper.ConvertToJsonElement(jsonDictionary).ConfigureAwait(false);
}
else
{
diff --git a/src/UnitTests/TaskTestBase.cs b/src/UnitTests/TaskTestBase.cs
index d604c17..c1354b5 100644
--- a/src/UnitTests/TaskTestBase.cs
+++ b/src/UnitTests/TaskTestBase.cs
@@ -1,4 +1,4 @@
-using AggregateConfigBuildTask.Contracts;
+using AggregateConfigBuildTask.Contracts;
using Microsoft.Build.Framework;
using Moq;
using Newtonsoft.Json;
@@ -14,6 +14,7 @@ public class TaskTestBase
{
private string testPath;
internal IFileSystem mockFileSystem;
+ private StringComparison comparison = StringComparison.OrdinalIgnoreCase;
public void TestInitialize(bool isWindowsMode, string testPath)
{
@@ -40,7 +41,7 @@ public void ShouldGenerateJsonOutput()
{
InputDirectory = testPath,
OutputFile = testPath + @"\output.json",
- OutputType = OutputTypeEnum.Json.ToString(),
+ OutputType = OutputType.Json.ToString(),
AddSourceProperty = true,
BuildEngine = Mock.Of()
};
@@ -75,7 +76,7 @@ public void ShouldGenerateArmParameterOutput()
{
InputDirectory = testPath,
OutputFile = testPath + @"\output.parameters.json",
- OutputType = OutputTypeEnum.Arm.ToString(),
+ OutputType = OutputType.Arm.ToString(),
AddSourceProperty = true,
BuildEngine = Mock.Of()
};
@@ -90,8 +91,8 @@ public void ShouldGenerateArmParameterOutput()
Assert.IsTrue(armTemplate.ContainsKey("parameters"));
JObject parameters = (JObject)armTemplate["parameters"];
- Assert.IsNotNull(parameters.GetValue("options"));
- Assert.AreEqual("array", parameters.GetValue("options")["type"].ToString());
+ Assert.IsNotNull(parameters.GetValue("options", comparison));
+ Assert.AreEqual("array", parameters.GetValue("options", comparison)["type"].ToString());
}
[TestMethod]
@@ -109,7 +110,7 @@ public void ShouldAddSourceProperty()
{
InputDirectory = testPath,
OutputFile = testPath + @"\output.json",
- OutputType = OutputTypeEnum.Json.ToString(),
+ OutputType = OutputType.Json.ToString(),
AddSourceProperty = true,
BuildEngine = Mock.Of()
};
@@ -153,7 +154,7 @@ public void ShouldAddSourcePropertyMultipleFiles()
{
InputDirectory = testPath,
OutputFile = testPath + @"\output.json",
- OutputType = OutputTypeEnum.Json.ToString(),
+ OutputType = OutputType.Json.ToString(),
AddSourceProperty = true,
BuildEngine = Mock.Of()
};
@@ -185,7 +186,7 @@ public void ShouldIncludeAdditionalPropertiesInJson()
{
InputDirectory = testPath,
OutputFile = testPath + @"\output.json",
- OutputType = OutputTypeEnum.Json.ToString(),
+ OutputType = OutputType.Json.ToString(),
AddSourceProperty = true,
AdditionalProperties = new Dictionary
{
@@ -220,7 +221,7 @@ public void ShouldIncludeAdditionalPropertiesInArmParameters()
{
InputDirectory = testPath,
OutputFile = testPath + @"\output.json",
- OutputType = OutputTypeEnum.Arm.ToString(),
+ OutputType = OutputType.Arm.ToString(),
AddSourceProperty = true,
AdditionalProperties = new Dictionary
{
@@ -238,9 +239,9 @@ public void ShouldIncludeAdditionalPropertiesInArmParameters()
string output = mockFileSystem.ReadAllText($"{testPath}\\output.json");
var armTemplate = JsonConvert.DeserializeObject>(output);
JObject parameters = (JObject)armTemplate["parameters"];
- Assert.AreEqual("array", parameters.GetValue("options")["type"].ToString());
- Assert.AreEqual("TestRG", parameters.GetValue("Group")["value"].Value());
- Assert.AreEqual("Prod", parameters.GetValue("Environment")["value"].Value());
+ Assert.AreEqual("array", parameters.GetValue("options", comparison)["type"].ToString());
+ Assert.AreEqual("TestRG", parameters.GetValue("Group", comparison)["value"].Value());
+ Assert.AreEqual("Prod", parameters.GetValue("Environment", comparison)["value"].Value());
}
[TestMethod]
@@ -252,7 +253,7 @@ public void ShouldHandleEmptyDirectory()
{
InputDirectory = testPath,
OutputFile = testPath + @"\output.json",
- OutputType = OutputTypeEnum.Json.ToString(),
+ OutputType = OutputType.Json.ToString(),
BuildEngine = Mock.Of()
};
@@ -279,7 +280,7 @@ public void ShouldHandleInvalidYamlFormat()
{
InputDirectory = testPath,
OutputFile = testPath + @"\output.json",
- OutputType = OutputTypeEnum.Json.ToString(),
+ OutputType = OutputType.Json.ToString(),
BuildEngine = Mock.Of()
};
@@ -305,7 +306,7 @@ public void ShouldCorrectlyParseBooleanValues()
{
InputDirectory = testPath,
OutputFile = testPath + @"\output.json",
- OutputType = OutputTypeEnum.Arm.ToString(),
+ OutputType = OutputType.Arm.ToString(),
BuildEngine = Mock.Of()
};
@@ -317,9 +318,9 @@ public void ShouldCorrectlyParseBooleanValues()
string output = mockFileSystem.ReadAllText($"{testPath}\\output.json");
var armTemplate = JsonConvert.DeserializeObject>(output);
JObject parameters = (JObject)armTemplate["parameters"];
- Assert.AreEqual("array", parameters.GetValue("options")["type"].ToString());
- Assert.AreEqual("Boolean", parameters.GetValue("options")["value"].First()["isEnabled"].Type.ToString());
- Assert.AreEqual(true, parameters.GetValue("options")["value"].First()["isEnabled"].Value());
+ Assert.AreEqual("array", parameters.GetValue("options", comparison)["type"].ToString());
+ Assert.AreEqual("Boolean", parameters.GetValue("options", comparison)["value"].First()["isEnabled"].Type.ToString());
+ Assert.AreEqual(true, parameters.GetValue("options", comparison)["value"].First()["isEnabled"].Value());
}
[TestMethod]
@@ -340,10 +341,10 @@ public void ShouldIncludeAdditionalPropertiesInJsonInput()
var task = new AggregateConfig(mockFileSystem)
{
- InputType = InputTypeEnum.Json.ToString(),
+ InputType = InputType.Json.ToString(),
InputDirectory = testPath,
OutputFile = testPath + @"\output.json",
- OutputType = OutputTypeEnum.Arm.ToString(),
+ OutputType = OutputType.Arm.ToString(),
AddSourceProperty = true,
AdditionalProperties = new Dictionary
{
@@ -361,12 +362,12 @@ public void ShouldIncludeAdditionalPropertiesInJsonInput()
string output = mockFileSystem.ReadAllText($"{testPath}\\output.json");
var armTemplate = JsonConvert.DeserializeObject>(output);
JObject parameters = (JObject)armTemplate["parameters"];
- Assert.AreEqual("TestRG", parameters.GetValue("Group")["value"].Value());
- Assert.AreEqual("Prod", parameters.GetValue("Environment")["value"].Value());
- Assert.AreEqual("String", parameters.GetValue("options")["value"].First()["source"].Type.ToString());
- Assert.AreEqual("file1", parameters.GetValue("options")["value"].First()["source"].Value());
- Assert.AreEqual("Boolean", parameters.GetValue("options")["value"].First()["isEnabled"].Type.ToString());
- Assert.AreEqual(true, parameters.GetValue("options")["value"].First()["isEnabled"].Value());
+ Assert.AreEqual("TestRG", parameters.GetValue("Group", 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.GetValue("options", comparison)["value"].First()["source"].Value());
+ Assert.AreEqual("Boolean", parameters.GetValue("options", comparison)["value"].First()["isEnabled"].Type.ToString());
+ Assert.AreEqual(true, parameters.GetValue("options", comparison)["value"].First()["isEnabled"].Value());
}
[TestMethod]
@@ -392,10 +393,10 @@ public void ShouldIncludeAdditionalPropertiesInArmParameterFile()
var task = new AggregateConfig(mockFileSystem)
{
- InputType = InputTypeEnum.Arm.ToString(),
+ InputType = InputType.Arm.ToString(),
InputDirectory = testPath,
OutputFile = testPath + @"\output.parameters.json",
- OutputType = OutputTypeEnum.Arm.ToString(),
+ OutputType = OutputType.Arm.ToString(),
AddSourceProperty = true,
AdditionalProperties = new Dictionary
{
@@ -413,12 +414,12 @@ public void ShouldIncludeAdditionalPropertiesInArmParameterFile()
string output = mockFileSystem.ReadAllText($"{testPath}\\output.parameters.json");
var armTemplate = JsonConvert.DeserializeObject>(output);
JObject parameters = (JObject)armTemplate["parameters"];
- Assert.AreEqual("TestRG", parameters.GetValue("Group")["value"].Value());
- Assert.AreEqual("Prod", parameters.GetValue("Environment")["value"].Value());
- Assert.AreEqual("String", parameters.GetValue("options")["value"].First()["source"].Type.ToString());
- Assert.AreEqual("file1.parameters", parameters.GetValue("options")["value"].First()["source"].Value());
- Assert.AreEqual("Boolean", parameters.GetValue("options")["value"].First()["isEnabled"].Type.ToString());
- Assert.AreEqual(true, parameters.GetValue("options")["value"].First()["isEnabled"].Value());
+ Assert.AreEqual("TestRG", parameters.GetValue("Group", 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());
+ Assert.AreEqual(true, parameters.GetValue("options", comparison)["value"].First()["isEnabled"].Value());
}
[TestMethod]
@@ -449,7 +450,7 @@ public void StressTest_ShouldAddSourcePropertyManyFiles()
{
InputDirectory = testPath,
OutputFile = testPath + @"\output.json",
- OutputType = OutputTypeEnum.Json.ToString(),
+ OutputType = OutputType.Json.ToString(),
AddSourceProperty = true,
BuildEngine = Mock.Of()
};
diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj
index 9b933be..ae115c3 100644
--- a/src/UnitTests/UnitTests.csproj
+++ b/src/UnitTests/UnitTests.csproj
@@ -5,10 +5,9 @@
net8.0
false
disable
- true
false
true
- CS1591
+ CS1591,CA1707,CA5394,CA1305
diff --git a/src/UnitTests/VirtualFileSystem.cs b/src/UnitTests/VirtualFileSystem.cs
index c4f5654..973a546 100644
--- a/src/UnitTests/VirtualFileSystem.cs
+++ b/src/UnitTests/VirtualFileSystem.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Text;
@@ -6,12 +7,11 @@
namespace AggregateConfigBuildTask.Tests.Unit
{
- internal class VirtualFileSystem(bool isWindowsMode = true) : IFileSystem
+ internal sealed class VirtualFileSystem(bool isWindowsMode = true) : IFileSystem
{
private readonly bool isWindowsMode = isWindowsMode;
- private readonly Dictionary fileSystem = new(
- isWindowsMode ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal
- );
+ private ConcurrentDictionary fileSystem = new(
+ isWindowsMode ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal);
private RegexOptions RegexOptions => isWindowsMode ? RegexOptions.IgnoreCase : RegexOptions.None;
private StringComparison StringComparison => isWindowsMode ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
@@ -132,6 +132,14 @@ public Stream OpenRead(string inputPath)
return new MemoryStream(byteArray);
}
+ ///
+ /// Delete all files on the virtual file system.
+ ///
+ public void FormatSystem()
+ {
+ fileSystem = new ConcurrentDictionary();
+ }
+
///
/// Ensures that the provided directory path ends with a directory separator character.
///
@@ -146,7 +154,7 @@ private string EnsureTrailingDirectorySeparator(string directoryPath)
char directorySeparator = isWindowsMode ? '\\' : '/';
// Ensure the directory path ends with the correct directory separator
- if (!directoryPath.EndsWith(directorySeparator.ToString()))
+ if (!directoryPath.EndsWith(directorySeparator.ToString(), StringComparison.Ordinal))
{
directoryPath += directorySeparator;
}
@@ -163,7 +171,7 @@ private static string ConvertPatternToRegex(string searchPattern)
string escapedPattern = Regex.Escape(searchPattern);
// Replace escaped * and ? with their regex equivalents
- escapedPattern = escapedPattern.Replace("\\*", ".*").Replace("\\?", ".");
+ escapedPattern = escapedPattern.Replace("\\*", ".*", StringComparison.Ordinal).Replace("\\?", ".", StringComparison.Ordinal);
// Add start and end anchors to ensure full-string match
return "^" + escapedPattern + "$";
@@ -185,7 +193,7 @@ private string NormalizePath(string path)
string normalizedPath = path.Replace(alternativeSeparator, directorySeparator);
// Trim any redundant trailing slashes except for root directory ("/" or "C:\\")
- if (normalizedPath.Length > 1 && normalizedPath.EndsWith(directorySeparator.ToString()))
+ if (normalizedPath.Length > 1 && normalizedPath.EndsWith(directorySeparator.ToString(), StringComparison.Ordinal))
{
normalizedPath = normalizedPath.TrimEnd(directorySeparator);
}