diff --git a/src/Resources/ResourceManager/Implementation/Bicep/PublishAzureBicepModuleCmdlet.cs b/src/Resources/ResourceManager/Implementation/Bicep/PublishAzureBicepModuleCmdlet.cs index 43110d7c90fc..4e73688bda55 100644 --- a/src/Resources/ResourceManager/Implementation/Bicep/PublishAzureBicepModuleCmdlet.cs +++ b/src/Resources/ResourceManager/Implementation/Bicep/PublishAzureBicepModuleCmdlet.cs @@ -12,6 +12,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Microsoft.Azure.Commands.Common.Authentication.Abstractions; using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Utilities; using Microsoft.Azure.Commands.ResourceManager.Common; using Microsoft.WindowsAzure.Commands.Utilities.Common; @@ -41,7 +42,7 @@ public class PublishAzureBicepModuleCmdlet : AzureRMCmdlet public override void ExecuteCmdlet() { - BicepUtility.PublishFile(this.TryResolvePath(this.FilePath), this.Target, this.DocumentationUri, this.Force.IsPresent, this.WriteVerbose, this.WriteWarning); + BicepUtility.Create().PublishFile(this.TryResolvePath(this.FilePath), this.Target, this.DocumentationUri, this.Force.IsPresent, this.WriteVerbose, this.WriteWarning); if (this.PassThru.IsPresent) { diff --git a/src/Resources/ResourceManager/Implementation/CmdletBase/DeploymentCmdletBase.cs b/src/Resources/ResourceManager/Implementation/CmdletBase/DeploymentCmdletBase.cs index 2066a39cbd4e..ec65771d7ca8 100644 --- a/src/Resources/ResourceManager/Implementation/CmdletBase/DeploymentCmdletBase.cs +++ b/src/Resources/ResourceManager/Implementation/CmdletBase/DeploymentCmdletBase.cs @@ -475,7 +475,7 @@ protected string[] GetStaticParameterNames() protected void BuildAndUseBicepTemplate() { - TemplateFile = BicepUtility.BuildFile(this.ResolvePath(TemplateFile), this.WriteVerbose, this.WriteWarning); + TemplateFile = BicepUtility.Create().BuildFile(this.ResolvePath(TemplateFile), this.WriteVerbose, this.WriteWarning); } private IReadOnlyDictionary GetDynamicParametersDictionary() @@ -490,8 +490,8 @@ private IReadOnlyDictionary GetDynamicParametersDictionary() protected void BuildAndUseBicepParameters(bool emitWarnings) { BicepUtility.OutputCallback nullCallback = null; - var output = BicepUtility.BuildParams(this.ResolvePath(TemplateParameterFile), GetDynamicParametersDictionary(), this.WriteVerbose, emitWarnings ? this.WriteWarning : nullCallback); - bicepparamFileParameters = GetParametersFromJson(output.parametersJson); + var output = BicepUtility.Create().BuildParams(this.ResolvePath(TemplateParameterFile), GetDynamicParametersDictionary(), this.WriteVerbose, emitWarnings ? this.WriteWarning : nullCallback); + bicepparamFileParameters = TemplateUtility.ParseTemplateParameterJson(output.parametersJson); if (TemplateObject == null && string.IsNullOrEmpty(TemplateFile) && @@ -545,13 +545,5 @@ private Hashtable GetCombinedTemplateParameterObject() return TemplateParameterObject; } - - private IReadOnlyDictionary GetParametersFromJson(string parametersJson) - { - using (var reader = new StringReader(parametersJson)) - { - return TemplateUtility.ParseTemplateParameterJson(reader); - } - } } } diff --git a/src/Resources/ResourceManager/Implementation/CmdletBase/DeploymentStacksCmdletBase.cs b/src/Resources/ResourceManager/Implementation/CmdletBase/DeploymentStacksCmdletBase.cs index 4f1591eeda52..2c893058c635 100644 --- a/src/Resources/ResourceManager/Implementation/CmdletBase/DeploymentStacksCmdletBase.cs +++ b/src/Resources/ResourceManager/Implementation/CmdletBase/DeploymentStacksCmdletBase.cs @@ -60,7 +60,7 @@ protected string ResolveBicepFile(string TemplateFile) { if (BicepUtility.IsBicepFile(TemplateFile)) { - return BicepUtility.BuildFile(this.ResolvePath(TemplateFile), this.WriteVerbose, this.WriteWarning); + return BicepUtility.Create().BuildFile(this.ResolvePath(TemplateFile), this.WriteVerbose, this.WriteWarning); } else return TemplateFile; @@ -71,7 +71,7 @@ protected BicepBuildParamsStdout ResolveBicepParameterFile(string TemplateParame { if (BicepUtility.IsBicepparamFile(TemplateParameterFile)) { - return BicepUtility.BuildParams(this.ResolvePath(TemplateParameterFile), new Dictionary(), this.WriteVerbose, this.WriteWarning); + return BicepUtility.Create().BuildParams(this.ResolvePath(TemplateParameterFile), new Dictionary(), this.WriteVerbose, this.WriteWarning); } return null; diff --git a/src/Resources/ResourceManager/Implementation/TemplateSpecs/NewAzTemplateSpec.cs b/src/Resources/ResourceManager/Implementation/TemplateSpecs/NewAzTemplateSpec.cs index 9f51cfeb4725..4e29a619e272 100644 --- a/src/Resources/ResourceManager/Implementation/TemplateSpecs/NewAzTemplateSpec.cs +++ b/src/Resources/ResourceManager/Implementation/TemplateSpecs/NewAzTemplateSpec.cs @@ -166,7 +166,7 @@ public override void ExecuteCmdlet() if (BicepUtility.IsBicepFile(TemplateFile)) { - filePath = BicepUtility.BuildFile(this.ResolvePath(TemplateFile), this.WriteVerbose, this.WriteWarning); + filePath = BicepUtility.Create().BuildFile(this.ResolvePath(TemplateFile), this.WriteVerbose, this.WriteWarning); } // Note: We set uiFormDefinitionFilePath to null below because we process the UIFormDefinition diff --git a/src/Resources/ResourceManager/Implementation/TemplateSpecs/SetAzTemplateSpec.cs b/src/Resources/ResourceManager/Implementation/TemplateSpecs/SetAzTemplateSpec.cs index abc77ac9f084..eb80e7ac6eac 100644 --- a/src/Resources/ResourceManager/Implementation/TemplateSpecs/SetAzTemplateSpec.cs +++ b/src/Resources/ResourceManager/Implementation/TemplateSpecs/SetAzTemplateSpec.cs @@ -204,7 +204,7 @@ public override void ExecuteCmdlet() } if (BicepUtility.IsBicepFile(TemplateFile)) { - filePath = BicepUtility.BuildFile(this.ResolvePath(TemplateFile), this.WriteVerbose, this.WriteWarning); + filePath = BicepUtility.Create().BuildFile(this.ResolvePath(TemplateFile), this.WriteVerbose, this.WriteWarning); } // Note: We set uiFormDefinitionFilePath to null below because we process the UIFormDefinition diff --git a/src/Resources/ResourceManager/Utilities/BicepUtility.cs b/src/Resources/ResourceManager/Utilities/BicepUtility.cs index 266eb353243b..68c10476ba04 100644 --- a/src/Resources/ResourceManager/Utilities/BicepUtility.cs +++ b/src/Resources/ResourceManager/Utilities/BicepUtility.cs @@ -23,6 +23,7 @@ namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Utilities using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; + using Microsoft.Azure.Commands.Common.Authentication; public class BicepBuildParamsStdout { @@ -33,22 +34,10 @@ public class BicepBuildParamsStdout public string templateSpecId { get; set; } } - internal static class BicepUtility + internal class BicepUtility { - private static Lazy BicepVersionLazy = new Lazy(() => { - var processInvoker = ProcessInvoker.Create(); - if (!processInvoker.CheckExecutableExists(BicepExecutable)) - { - return null; - } - - var output = processInvoker.Invoke(new ProcessInput { Executable = BicepExecutable, Arguments = "-v" }); - - var pattern = new Regex("\\d+(\\.\\d+)+"); - return pattern.Match(output.Stdout)?.Value; - }); - - private static string BicepVersion => BicepVersionLazy.Value; + public static BicepUtility Create() + => new BicepUtility(ProcessInvoker.Create(), FileUtilities.DataStore); /// /// The Bicep executable to use. By default, this'll be resolved from the system PATH. @@ -72,15 +61,38 @@ internal static class BicepUtility public delegate void OutputCallback(string msg); + private readonly IProcessInvoker processInvoker; + private readonly IDataStore dataStore; + private readonly Lazy bicepVersionLazy; + + public BicepUtility(IProcessInvoker processInvoker, IDataStore dataStore) + { + this.processInvoker = processInvoker; + this.dataStore = dataStore; + this.bicepVersionLazy = new Lazy(() => { + if (!processInvoker.CheckExecutableExists(BicepExecutable)) + { + return null; + } + + var output = processInvoker.Invoke(new ProcessInput { Executable = BicepExecutable, Arguments = "-v" }); + + var pattern = new Regex("\\d+(\\.\\d+)+"); + return pattern.Match(output.Stdout)?.Value; + }); + } + + private string BicepVersion => bicepVersionLazy.Value; + public static bool IsBicepFile(string templateFilePath) => ".bicep".Equals(Path.GetExtension(templateFilePath), StringComparison.OrdinalIgnoreCase); public static bool IsBicepparamFile(string parametersFilePath) => ".bicepparam".Equals(Path.GetExtension(parametersFilePath), StringComparison.OrdinalIgnoreCase); - public static string BuildFile(string bicepTemplateFilePath, OutputCallback writeVerbose = null, OutputCallback writeWarning = null) + public string BuildFile(string bicepTemplateFilePath, OutputCallback writeVerbose = null, OutputCallback writeWarning = null) { - if (!FileUtilities.DataStore.FileExists(bicepTemplateFilePath)) + if (!dataStore.FileExists(bicepTemplateFilePath)) { throw new AzPSArgumentException(Properties.Resources.InvalidBicepFilePath, "TemplateFile"); } @@ -91,7 +103,7 @@ public static string BuildFile(string bicepTemplateFilePath, OutputCallback writ RunBicepCommand($"build {GetQuotedFilePath(bicepTemplateFilePath)} --outdir {GetQuotedFilePath(tempDirectory)}", MinimalVersionRequirement, writeVerbose, writeWarning); string buildResultPath = Path.Combine(tempDirectory, Path.GetFileName(bicepTemplateFilePath)).Replace(".bicep", ".json"); - if (!FileUtilities.DataStore.FileExists(buildResultPath)) + if (!dataStore.FileExists(buildResultPath)) { throw new AzPSApplicationException(string.Format(Properties.Resources.BuildBicepFileToJsonFailed, bicepTemplateFilePath)); } @@ -99,9 +111,9 @@ public static string BuildFile(string bicepTemplateFilePath, OutputCallback writ return buildResultPath; } - public static BicepBuildParamsStdout BuildParams(string bicepParamFilePath, IReadOnlyDictionary overrideParams, OutputCallback writeVerbose = null, OutputCallback writeWarning = null) + public BicepBuildParamsStdout BuildParams(string bicepParamFilePath, IReadOnlyDictionary overrideParams, OutputCallback writeVerbose = null, OutputCallback writeWarning = null) { - if (!FileUtilities.DataStore.FileExists(bicepParamFilePath)) + if (!dataStore.FileExists(bicepParamFilePath)) { throw new AzPSArgumentException(Properties.Resources.InvalidBicepparamFilePath, "TemplateParameterFile"); } @@ -124,9 +136,9 @@ public static BicepBuildParamsStdout BuildParams(string bicepParamFilePath, IRea return JsonConvert.DeserializeObject(stdout); } - public static void PublishFile(string bicepFilePath, string target, string documentationUri = null, bool force = false, OutputCallback writeVerbose = null, OutputCallback writeWarning = null) + public void PublishFile(string bicepFilePath, string target, string documentationUri = null, bool force = false, OutputCallback writeVerbose = null, OutputCallback writeWarning = null) { - if (!FileUtilities.DataStore.FileExists(bicepFilePath)) + if (!dataStore.FileExists(bicepFilePath)) { throw new AzPSArgumentException(Properties.Resources.InvalidBicepFilePath, "File"); } @@ -148,7 +160,7 @@ public static void PublishFile(string bicepFilePath, string target, string docum RunBicepCommand(bicepPublishCommand, MinimalVersionRequirementForBicepPublish, writeVerbose, writeWarning); } - private static void CheckBicepExecutable() + private void CheckBicepExecutable() { if (BicepVersion == null) { @@ -156,7 +168,7 @@ private static void CheckBicepExecutable() } } - private static string CheckMinimalVersionRequirement(string minimalVersionRequirement) + private string CheckMinimalVersionRequirement(string minimalVersionRequirement) { CheckBicepExecutable(); @@ -168,14 +180,13 @@ private static string CheckMinimalVersionRequirement(string minimalVersionRequir return BicepVersion; } - private static string RunBicepCommandWithStdoutCapture(string arguments, string minimalVersionRequirement, Dictionary envVars = null, OutputCallback writeVerbose = null, OutputCallback writeWarning = null) + private string RunBicepCommandWithStdoutCapture(string arguments, string minimalVersionRequirement, Dictionary envVars = null, OutputCallback writeVerbose = null, OutputCallback writeWarning = null) { string currentBicepVersion = CheckMinimalVersionRequirement(minimalVersionRequirement); writeVerbose?.Invoke($"Using Bicep v{currentBicepVersion}"); writeVerbose?.Invoke($"Calling Bicep with arguments: {arguments}"); - var processInvoker = ProcessInvoker.Create(); var output = processInvoker.Invoke(new ProcessInput { Executable = BicepExecutable, Arguments = arguments, EnvVars = envVars }); if (output.ExitCode != 0) @@ -192,14 +203,13 @@ private static string RunBicepCommandWithStdoutCapture(string arguments, string return output.Stdout; } - private static void RunBicepCommand(string arguments, string minimalVersionRequirement, OutputCallback writeVerbose = null, OutputCallback writeWarning = null) + private void RunBicepCommand(string arguments, string minimalVersionRequirement, OutputCallback writeVerbose = null, OutputCallback writeWarning = null) { string currentBicepVersion = CheckMinimalVersionRequirement(minimalVersionRequirement); writeVerbose?.Invoke($"Using Bicep v{currentBicepVersion}"); writeVerbose?.Invoke($"Calling Bicep with arguments: {arguments}"); - var processInvoker = ProcessInvoker.Create(); var output = processInvoker.Invoke(new ProcessInput { Executable = BicepExecutable, Arguments = arguments }); writeVerbose?.Invoke(output.Stdout); diff --git a/src/Resources/ResourceManager/Utilities/ProcessInvoker.cs b/src/Resources/ResourceManager/Utilities/ProcessInvoker.cs index 20336328292f..6e22a7c89a35 100644 --- a/src/Resources/ResourceManager/Utilities/ProcessInvoker.cs +++ b/src/Resources/ResourceManager/Utilities/ProcessInvoker.cs @@ -17,6 +17,7 @@ namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Utilities using System.Collections.Generic; using System.Diagnostics; using System.Management.Automation; + using System.Text; public class ProcessOutput { @@ -84,6 +85,8 @@ public ProcessOutput Invoke(ProcessInput input) UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, CreateNoWindow = true, } }; diff --git a/src/Resources/ResourceManager/Utilities/TemplateUtility.cs b/src/Resources/ResourceManager/Utilities/TemplateUtility.cs index 67d66e638e1a..4577c60c71c9 100644 --- a/src/Resources/ResourceManager/Utilities/TemplateUtility.cs +++ b/src/Resources/ResourceManager/Utilities/TemplateUtility.cs @@ -100,6 +100,14 @@ public static Dictionary ParseTemplatePa } } + public static Dictionary ParseTemplateParameterJson(string json) + { + using (var reader = new StringReader(json)) + { + return TemplateUtility.ParseTemplateParameterJson(reader); + } + } + public static Dictionary ParseTemplateParameterJson(TextReader reader) { // Read once to avoid having to rewind the stream diff --git a/src/Resources/Resources.Test/UnitTests/Utilities/BicepUtilityTests.cs b/src/Resources/Resources.Test/UnitTests/Utilities/BicepUtilityTests.cs new file mode 100644 index 000000000000..cb88e063d343 --- /dev/null +++ b/src/Resources/Resources.Test/UnitTests/Utilities/BicepUtilityTests.cs @@ -0,0 +1,145 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using FluentAssertions; +using Microsoft.Azure.Commands.Common.Authentication; +using Microsoft.Azure.Commands.Common.Exceptions; +using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Utilities; +using Microsoft.WindowsAzure.Commands.ScenarioTest; +using Moq; +using Xunit; + +namespace Microsoft.Azure.Commands.Resources.Test.UnitTests.Utilities +{ + public class BicepUtilityTests + { + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void TestIsBicepFile() + { + Assert.True(BicepUtility.IsBicepFile("test.bicep")); + Assert.False(BicepUtility.IsBicepFile("test.json")); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void TestIsBicepparamFile() + { + Assert.True(BicepUtility.IsBicepparamFile("test.bicepparam")); + Assert.False(BicepUtility.IsBicepparamFile("test.json")); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void BuildParams_returns_valid_parameter_output() + { + var invokerMock = new Mock(); + invokerMock.Setup(x => x.Invoke(It.Is(p => p.Arguments == "-v"))) + .Returns(new ProcessOutput { ExitCode = 0, Stderr = "", Stdout = "Bicep CLI version 0.22.6 (d62b94db31)" }); + invokerMock.Setup(x => x.Invoke(It.Is(p => p.Arguments == "build-params \"foo.bicepparam\" --stdout"))) + .Returns(new ProcessOutput { ExitCode = 0, Stderr = "", Stdout = "{\"parametersJson\":\"{\\n \\\"$schema\\\": \\\"https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#\\\",\\n \\\"contentVersion\\\": \\\"1.0.0.0\\\",\\n \\\"parameters\\\": {\\n \\\"tag1\\\": {\\n \\\"value\\\": \\\"日本語テスト_param\\\"\\n }\\n }\\n}\",\"templateJson\":\"{\\n \\\"$schema\\\": \\\"https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#\\\",\\n \\\"contentVersion\\\": \\\"1.0.0.0\\\",\\n \\\"metadata\\\": {\\n \\\"_generator\\\": {\\n \\\"name\\\": \\\"bicep\\\",\\n \\\"version\\\": \\\"0.22.6.54827\\\",\\n \\\"templateHash\\\": \\\"6645562165406558166\\\"\\n }\\n },\\n \\\"parameters\\\": {\\n \\\"tag1\\\": {\\n \\\"type\\\": \\\"string\\\"\\n }\\n },\\n \\\"variables\\\": {\\n \\\"tag2\\\": \\\"日本語テスト_var\\\"\\n },\\n \\\"resources\\\": [\\n {\\n \\\"type\\\": \\\"Microsoft.Resources/resourceGroups\\\",\\n \\\"apiVersion\\\": \\\"2022-09-01\\\",\\n \\\"name\\\": \\\"rg-bicepparam-test\\\",\\n \\\"location\\\": \\\"japaneast\\\",\\n \\\"tags\\\": {\\n \\\"tagName1\\\": \\\"[parameters('tag1')]\\\",\\n \\\"tagName2\\\": \\\"[variables('tag2')]\\\",\\n \\\"tagName3\\\": \\\"日本語テスト_literal\\\"\\n },\\n \\\"properties\\\": {}\\n }\\n ]\\n}\",\"templateSpecId\":null}" }); + invokerMock.Setup(x => x.CheckExecutableExists("bicep")) + .Returns(true); + + var dataStoreMock = new Mock(); + dataStoreMock.Setup(x => x.FileExists("foo.bicepparam")) + .Returns(true); + + var bicepUtility = new BicepUtility(invokerMock.Object, dataStoreMock.Object); + + var output = bicepUtility.BuildParams("foo.bicepparam", new Dictionary()); + var parameters = TemplateUtility.ParseTemplateParameterJson(output.parametersJson); + + parameters["tag1"].Value.Should().Be("日本語テスト_param"); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void BuildParams_fails_for_non_zero_exit_code() + { + var invokerMock = new Mock(); + invokerMock.Setup(x => x.Invoke(It.Is(p => p.Arguments == "-v"))) + .Returns(new ProcessOutput { ExitCode = 0, Stderr = "", Stdout = "Bicep CLI version 0.22.6 (d62b94db31)" }); + invokerMock.Setup(x => x.Invoke(It.Is(p => p.Arguments == "build-params \"foo.bicepparam\" --stdout"))) + .Returns(new ProcessOutput { ExitCode = 1, Stderr = "Oops something went wrong!", Stdout = "" }); + invokerMock.Setup(x => x.CheckExecutableExists("bicep")) + .Returns(true); + + var dataStoreMock = new Mock(); + dataStoreMock.Setup(x => x.FileExists("foo.bicepparam")) + .Returns(true); + + var bicepUtility = new BicepUtility(invokerMock.Object, dataStoreMock.Object); + + FluentActions.Invoking(() => bicepUtility.BuildParams("foo.bicepparam", new Dictionary())) + .Should().Throw().WithMessage("Oops something went wrong!"); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void BuildParams_fails_for_old_bicep_version() + { + var invokerMock = new Mock(); + invokerMock.Setup(x => x.Invoke(It.Is(p => p.Arguments == "-v"))) + .Returns(new ProcessOutput { ExitCode = 0, Stderr = "", Stdout = "Bicep CLI version 0.15.1 (d62b94db31)" }); + invokerMock.Setup(x => x.CheckExecutableExists("bicep")) + .Returns(true); + + var dataStoreMock = new Mock(); + dataStoreMock.Setup(x => x.FileExists("foo.bicepparam")) + .Returns(true); + + var bicepUtility = new BicepUtility(invokerMock.Object, dataStoreMock.Object); + + FluentActions.Invoking(() => bicepUtility.BuildParams("foo.bicepparam", new Dictionary())) + .Should().Throw().WithMessage("Please use bicep '0.16.1' or higher verison."); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void BuildParams_fails_for_missing_bicep() + { + var invokerMock = new Mock(); + invokerMock.Setup(x => x.CheckExecutableExists("bicep")) + .Returns(false); + + var dataStoreMock = new Mock(); + dataStoreMock.Setup(x => x.FileExists("foo.bicepparam")) + .Returns(true); + + var bicepUtility = new BicepUtility(invokerMock.Object, dataStoreMock.Object); + + FluentActions.Invoking(() => bicepUtility.BuildParams("foo.bicepparam", new Dictionary())) + .Should().Throw().WithMessage("Cannot find Bicep. Please add Bicep to your PATH or visit *"); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void BuildParams_fails_for_missing_param_file() + { + var invokerMock = new Mock(); + var dataStoreMock = new Mock(); + dataStoreMock.Setup(x => x.FileExists("foo.bicepparam")) + .Returns(false); + + var bicepUtility = new BicepUtility(invokerMock.Object, dataStoreMock.Object); + + FluentActions.Invoking(() => bicepUtility.BuildParams("foo.bicepparam", new Dictionary())) + .Should().Throw().WithMessage("Invalid Bicepparam file path."); + } + } +} diff --git a/src/Resources/Resources.Test/UnitTests/Utilities/TestBicepUtility.cs b/src/Resources/Resources.Test/UnitTests/Utilities/TestBicepUtility.cs deleted file mode 100644 index 8e6f9f12af59..000000000000 --- a/src/Resources/Resources.Test/UnitTests/Utilities/TestBicepUtility.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Utilities; -using Microsoft.WindowsAzure.Commands.ScenarioTest; - -using Xunit; - -namespace Microsoft.Azure.Commands.Resources.Test.UnitTests.Utilities -{ - public class TestBicepUtility - { - [Fact] - [Trait(Category.AcceptanceType, Category.CheckIn)] - public void TestIsBicepFile() - { - Assert.True(BicepUtility.IsBicepFile("test.bicep")); - Assert.False(BicepUtility.IsBicepFile("test.json")); - } - - [Fact] - [Trait(Category.AcceptanceType, Category.CheckIn)] - public void TestIsBicepparamFile() - { - Assert.True(BicepUtility.IsBicepparamFile("test.bicepparam")); - Assert.False(BicepUtility.IsBicepparamFile("test.json")); - } - } -} diff --git a/src/Resources/Resources/ChangeLog.md b/src/Resources/Resources/ChangeLog.md index bb2f8929bb69..4f91974c374b 100644 --- a/src/Resources/Resources/ChangeLog.md +++ b/src/Resources/Resources/ChangeLog.md @@ -19,6 +19,7 @@ --> ## Upcoming Release +* Used utf8 encoding for reading stdout & stderr when invoking Bicep. [#23246] ## Version 6.12.0 * Supported $ref statements for user-defined types in Bicep files.