From ca6e44d496b0c589fdaabad69a00643f539c47cd Mon Sep 17 00:00:00 2001 From: Bob Arnson Date: Fri, 14 Feb 2025 22:29:39 -0500 Subject: Convert ext\ to MSTest and traversal projects. - Move ext\ unit tests to MSTest. - MSBuildify ext projects with MSTest execution. - Fork test support projects for MSTest: - WixInternal.TestSupport - WixInternal.Core.TestPackage --- src/Directory.Build.props | 4 +- src/Directory.csproj.targets | 20 +- src/clean.cmd | 2 + src/ext/Bal/bal.cmd | 55 --- src/ext/Bal/bal_t.proj | 33 +- .../BalExtensionFixture.cs | 49 +-- .../InternalUIBAFixture.cs | 95 +++--- .../WixToolsetTest.BootstrapperApplications.csproj | 7 +- src/ext/ComPlus/complus.cmd | 21 -- src/ext/ComPlus/complus_t.proj | 17 + .../ComPlusExtensionFixture.cs | 9 +- .../WixToolsetTest.ComPlus.csproj | 7 +- src/ext/Dependency/dependency.cmd | 21 -- src/ext/Dependency/dependency_t.proj | 17 + .../DependencyExtensionFixture.cs | 9 +- .../WixToolsetTest.Dependency.csproj | 7 +- src/ext/DirectX/directx.cmd | 24 -- src/ext/DirectX/directx_t.proj | 17 + .../DirectXExtensionFixture.cs | 9 +- .../WixToolsetTest.DirectX.csproj | 7 +- src/ext/Firewall/firewall.cmd | 21 -- src/ext/Firewall/firewall_t.proj | 17 + .../FirewallExtensionFixture.cs | 61 ++-- .../WixToolsetTest.Firewall.csproj | 7 +- src/ext/Http/http.cmd | 21 -- src/ext/Http/http_t.proj | 17 + .../WixToolsetTest.Http/HttpExtensionFixture.cs | 11 +- .../WixToolsetTest.Http/WixToolsetTest.Http.csproj | 7 +- src/ext/Iis/iis.cmd | 21 -- src/ext/Iis/iis_t.proj | 17 + .../test/WixToolsetTest.Iis/IisExtensionFixture.cs | 9 +- .../WixToolsetTest.Iis/WixToolsetTest.Iis.csproj | 7 +- src/ext/Msmq/msmq.cmd | 21 -- src/ext/Msmq/msmq_t.proj | 17 + .../WixToolsetTest.Msmq/MsmqExtensionFixture.cs | 12 +- .../WixToolsetTest.Msmq/WixToolsetTest.Msmq.csproj | 7 +- src/ext/NetFx/netfx.cmd | 48 --- src/ext/NetFx/netfx_t.proj | 26 ++ .../WixToolsetTest.Netfx/NetfxExtensionFixture.cs | 67 ++-- .../WixToolsetTest.Netfx.csproj | 7 +- src/ext/PowerShell/powershell_t.proj | 17 + src/ext/PowerShell/ps.cmd | 21 -- .../PowerShellExtensionFixture.cs | 13 +- .../WixToolsetTest.Powershell.csproj | 7 +- src/ext/Sql/sql.cmd | 21 -- src/ext/Sql/sql_t.proj | 17 + .../test/WixToolsetTest.Sql/SqlExtensionFixture.cs | 9 +- .../WixToolsetTest.Sql/WixToolsetTest.Sql.csproj | 7 +- .../test/WixToolsetTest.UI/UIExtensionFixture.cs | 89 ++--- .../WixToolsetTest.UI/WixToolsetTest.UI.csproj | 7 +- src/ext/UI/ui.cmd | 42 --- src/ext/UI/ui_t.proj | 17 + .../WixToolsetTest.Util/UtilExtensionFixture.cs | 61 ++-- .../WixToolsetTest.Util/WixToolsetTest.Util.csproj | 7 +- src/ext/Util/util.cmd | 45 --- src/ext/Util/util_t.proj | 17 + .../VisualStudioExtensionFixture.cs | 11 +- .../WixToolsetTest.VisualStudio.csproj | 7 +- src/ext/VisualStudio/visualstudio_t.proj | 17 + src/ext/VisualStudio/vs.cmd | 21 -- src/ext/ext.cmd | 53 +-- src/ext/ext_t.proj | 30 ++ .../SetBuildNumber/Directory.Packages.props.pp | 6 + src/internal/SetBuildNumber/global.json.pp | 3 +- src/internal/WixInternal.MSTestSupport/Builder.cs | 204 +++++++++++ .../DisposableFileSystem.cs | 94 ++++++ .../WixInternal.MSTestSupport/DotnetRunner.cs | 57 ++++ .../ExternalExecutable.cs | 374 +++++++++++++++++++++ .../ExternalExecutableResult.cs | 19 ++ .../WixInternal.MSTestSupport/FakeBuildEngine.cs | 33 ++ .../WixInternal.MSTestSupport/MsbuildRunner.cs | 112 ++++++ .../MsbuildRunnerResult.cs | 19 ++ .../WixInternal.MSTestSupport/MsbuildUtilities.cs | 99 ++++++ src/internal/WixInternal.MSTestSupport/Pushd.cs | 46 +++ src/internal/WixInternal.MSTestSupport/Query.cs | 207 ++++++++++++ .../WixInternal.MSTestSupport/RobocopyRunner.cs | 16 + src/internal/WixInternal.MSTestSupport/TestData.cs | 78 +++++ .../TestDataFolderFileSystem.cs | 42 +++ .../WixInternal.MSTestSupport/VswhereRunner.cs | 41 +++ .../WixInternal.MSTestSupport/WixAssert.cs | 164 +++++++++ .../WixInternal.MSTestSupport.csproj | 27 ++ src/internal/WixInternal.TestSupport/WixAssert.cs | 143 ++++++++ .../XunitExtensions/WixAssert.cs | 26 ++ src/internal/internal.sln | 36 ++ src/internal/internal_t.proj | 1 + src/wix.runsettings | 7 + .../BundleExtractor.cs | 156 +++++++++ .../ExtractBAContainerResult.cs | 156 +++++++++ .../TestMessageListener.cs | 57 ++++ .../WixInternal.Core.MSTestPackage.csproj | 35 ++ .../WixMessageFormatter.cs | 40 +++ .../WixInternal.Core.MSTestPackage/WixRunner.cs | 90 +++++ .../WixRunnerResult.cs | 62 ++++ .../XmlNodeExtensions.cs | 115 +++++++ src/wix/pack_t.proj | 1 + src/wix/wix.sln | 18 + 96 files changed, 3204 insertions(+), 767 deletions(-) delete mode 100644 src/ext/Bal/bal.cmd delete mode 100644 src/ext/ComPlus/complus.cmd create mode 100644 src/ext/ComPlus/complus_t.proj delete mode 100644 src/ext/Dependency/dependency.cmd create mode 100644 src/ext/Dependency/dependency_t.proj delete mode 100644 src/ext/DirectX/directx.cmd create mode 100644 src/ext/DirectX/directx_t.proj delete mode 100644 src/ext/Firewall/firewall.cmd create mode 100644 src/ext/Firewall/firewall_t.proj delete mode 100644 src/ext/Http/http.cmd create mode 100644 src/ext/Http/http_t.proj delete mode 100644 src/ext/Iis/iis.cmd create mode 100644 src/ext/Iis/iis_t.proj delete mode 100644 src/ext/Msmq/msmq.cmd create mode 100644 src/ext/Msmq/msmq_t.proj delete mode 100644 src/ext/NetFx/netfx.cmd create mode 100644 src/ext/NetFx/netfx_t.proj create mode 100644 src/ext/PowerShell/powershell_t.proj delete mode 100644 src/ext/PowerShell/ps.cmd delete mode 100644 src/ext/Sql/sql.cmd create mode 100644 src/ext/Sql/sql_t.proj delete mode 100644 src/ext/UI/ui.cmd create mode 100644 src/ext/UI/ui_t.proj delete mode 100644 src/ext/Util/util.cmd create mode 100644 src/ext/Util/util_t.proj create mode 100644 src/ext/VisualStudio/visualstudio_t.proj delete mode 100644 src/ext/VisualStudio/vs.cmd create mode 100644 src/ext/ext_t.proj create mode 100644 src/internal/WixInternal.MSTestSupport/Builder.cs create mode 100644 src/internal/WixInternal.MSTestSupport/DisposableFileSystem.cs create mode 100644 src/internal/WixInternal.MSTestSupport/DotnetRunner.cs create mode 100644 src/internal/WixInternal.MSTestSupport/ExternalExecutable.cs create mode 100644 src/internal/WixInternal.MSTestSupport/ExternalExecutableResult.cs create mode 100644 src/internal/WixInternal.MSTestSupport/FakeBuildEngine.cs create mode 100644 src/internal/WixInternal.MSTestSupport/MsbuildRunner.cs create mode 100644 src/internal/WixInternal.MSTestSupport/MsbuildRunnerResult.cs create mode 100644 src/internal/WixInternal.MSTestSupport/MsbuildUtilities.cs create mode 100644 src/internal/WixInternal.MSTestSupport/Pushd.cs create mode 100644 src/internal/WixInternal.MSTestSupport/Query.cs create mode 100644 src/internal/WixInternal.MSTestSupport/RobocopyRunner.cs create mode 100644 src/internal/WixInternal.MSTestSupport/TestData.cs create mode 100644 src/internal/WixInternal.MSTestSupport/TestDataFolderFileSystem.cs create mode 100644 src/internal/WixInternal.MSTestSupport/VswhereRunner.cs create mode 100644 src/internal/WixInternal.MSTestSupport/WixAssert.cs create mode 100644 src/internal/WixInternal.MSTestSupport/WixInternal.MSTestSupport.csproj create mode 100644 src/internal/WixInternal.TestSupport/WixAssert.cs create mode 100644 src/wix.runsettings create mode 100644 src/wix/WixInternal.Core.MSTestPackage/BundleExtractor.cs create mode 100644 src/wix/WixInternal.Core.MSTestPackage/ExtractBAContainerResult.cs create mode 100644 src/wix/WixInternal.Core.MSTestPackage/TestMessageListener.cs create mode 100644 src/wix/WixInternal.Core.MSTestPackage/WixInternal.Core.MSTestPackage.csproj create mode 100644 src/wix/WixInternal.Core.MSTestPackage/WixMessageFormatter.cs create mode 100644 src/wix/WixInternal.Core.MSTestPackage/WixRunner.cs create mode 100644 src/wix/WixInternal.Core.MSTestPackage/WixRunnerResult.cs create mode 100644 src/wix/WixInternal.Core.MSTestPackage/XmlNodeExtensions.cs (limited to 'src') diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 2de04127..883aba42 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -11,7 +11,9 @@ $(MSBuildProjectName) $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\)) $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\packages\)) - $(RootBuildFolder)logs\pdbs\$(Configuration)\ + $(RootBuildFolder)logs\ + $(LogsFolder)TestResults\ + $(LogsFolder)pdbs\$(Configuration)\ $(RootBuildFolder)artifacts\ $(RootBuildFolder).tools $(ArtifactsFolder) diff --git a/src/Directory.csproj.targets b/src/Directory.csproj.targets index 2c6abce3..ed041bb8 100644 --- a/src/Directory.csproj.targets +++ b/src/Directory.csproj.targets @@ -7,18 +7,36 @@ $(DefineConstants);DEBUG - + Major false false + + + + 17.11.5 + true + + + + + + + + + + diff --git a/src/clean.cmd b/src/clean.cmd index 6164a8f9..dc69f855 100644 --- a/src/clean.cmd +++ b/src/clean.cmd @@ -19,7 +19,9 @@ if exist ..\global.json (del ..\global.json) if exist "%_NUGET_CACHE%\wixinternal.basebuildtasks.sources" rd /s/q "%_NUGET_CACHE%\wixinternal.basebuildtasks.sources" if exist "%_NUGET_CACHE%\wixinternal.testsupport" rd /s/q "%_NUGET_CACHE%\wixinternal.testsupport" +if exist "%_NUGET_CACHE%\wixinternal.mstestsupport" rd /s/q "%_NUGET_CACHE%\wixinternal.mstestsupport" if exist "%_NUGET_CACHE%\wixinternal.core.testpackage" rd /s/q "%_NUGET_CACHE%\wixinternal.core.testpackage" +if exist "%_NUGET_CACHE%\wixinternal.core.mstestpackage" rd /s/q "%_NUGET_CACHE%\wixinternal.core.mstestpackage" if exist "%_NUGET_CACHE%\wixtoolset.bal.wixext" rd /s/q "%_NUGET_CACHE%\wixtoolset.bal.wixext" if exist "%_NUGET_CACHE%\wixtoolset.bootstrapperapplications.wixext" rd /s/q "%_NUGET_CACHE%\wixtoolset.bootstrapperapplications.wixext" if exist "%_NUGET_CACHE%\wixtoolset.bootstrapperextensionapi" rd /s/q "%_NUGET_CACHE%\wixtoolset.bootstrapperextensionapi" diff --git a/src/ext/Bal/bal.cmd b/src/ext/Bal/bal.cmd deleted file mode 100644 index df9ceca4..00000000 --- a/src/ext/Bal/bal.cmd +++ /dev/null @@ -1,55 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -@set _L=%~dp0..\..\..\build\logs - -:parse_args -@if /i "%1"=="release" set _C=Release -@if /i "%1"=="inc" set _INC=1 -@if /i "%1"=="clean" set _CLEAN=1 -@if not "%1"=="" shift & goto parse_args - -@set _B=%~dp0..\..\..\build\Bal.wixext\%_C% - -:: Clean - -@if "%_INC%"=="" call :clean -@if NOT "%_CLEAN%"=="" goto :end - -@echo Building ext\Bal %_C% using %_N% - -:: Restore -:: Build -:: Pack -:: Note: This test project must be restored and built directly to get all its support files laid out correctly. -:: Everything else is built by the traversal project. -msbuild -Restore -p:Configuration=%_C% -tl -nologo -m -warnaserror test\WixToolsetTest.BootstrapperApplications\WixToolsetTest.BootstrapperApplications.csproj -bl:%_L%\ext_bal_build.binlog || exit /b - -msbuild bal_t.proj -p:Configuration=%_C% -tl -nologo -warnaserror -bl:%_L%\bal_build.binlog || exit /b - -:: Test -dotnet test ^ - %_B%\x86\WixStdFnUnitTest.dll ^ - %_B%\net6.0\WixToolsetTest.BootstrapperApplications.dll ^ - --nologo -l "trx;LogFileName=%_L%\TestResults\bal.wixext.trx" || exit /b - -@goto :end - -:clean -@rd /s/q "..\..\..\build\Bal.wixext" 2> nul -@del "..\..\..\build\artifacts\WixToolset.Bal.wixext.*.nupkg" 2> nul -@del "..\..\..\build\artifacts\WixToolset.BootstrapperApplications.wixext.*.nupkg" 2> nul -@del "..\..\..\build\artifacts\WixToolset.WixStandardBootstrapperApplicationFunctionApi.*.nupkg" 2> nul -@del "%_L%\ext_bal_build.binlog" 2> nul -@del "%_L%\bal_fnsapi_build.binlog" 2> nul -@del "%_L%\bal_examples_build.binlog" 2> nul -@del "%_L%\TestResults\bal.wixext.trx" 2> nul -@rd /s/q "%USERPROFILE%\.nuget\packages\wixtoolset.bal.wixext" 2> nul -@rd /s/q "%USERPROFILE%\.nuget\packages\wixtoolset.bootstrapperapplications.wixext" 2> nul -@rd /s/q "%USERPROFILE%\.nuget\packages\wixtoolset.wixstandardbootstrapperapplicationfunctionapi" 2> nul -@exit /b - -:end -@popd -@endlocal diff --git a/src/ext/Bal/bal_t.proj b/src/ext/Bal/bal_t.proj index a0e66e97..da83b47f 100644 --- a/src/ext/Bal/bal_t.proj +++ b/src/ext/Bal/bal_t.proj @@ -3,13 +3,6 @@ - - - - - - - @@ -17,11 +10,33 @@ - + - + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/BalExtensionFixture.cs b/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/BalExtensionFixture.cs index 2e21ef90..6e24ad72 100644 --- a/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/BalExtensionFixture.cs +++ b/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/BalExtensionFixture.cs @@ -6,13 +6,14 @@ namespace WixToolsetTest.BootstrapperApplications using System.Collections.Generic; using System.IO; using System.Linq; - using WixInternal.Core.TestPackage; - using WixInternal.TestSupport; - using Xunit; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.Core.MSTestPackage; + using WixInternal.MSTestSupport; + [TestClass] public class BalExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingDisplayInternalUICondition() { using (var fs = new DisposableFileSystem()) @@ -35,7 +36,7 @@ namespace WixToolsetTest.BootstrapperApplications }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); @@ -46,11 +47,11 @@ namespace WixToolsetTest.BootstrapperApplications "", }, balPackageInfos); - Assert.True(File.Exists(Path.Combine(baFolderPath, "thm.wxl"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "thm.wxl"))); } } - [Fact] + [TestMethod] public void CanBuildUsingBootstrapperApplicationId() { using (var fs = new DisposableFileSystem()) @@ -73,7 +74,7 @@ namespace WixToolsetTest.BootstrapperApplications }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); @@ -91,7 +92,7 @@ namespace WixToolsetTest.BootstrapperApplications } } - [Fact] + [TestMethod] public void CanBuildUsingOverridable() { using (var fs = new DisposableFileSystem()) @@ -113,7 +114,7 @@ namespace WixToolsetTest.BootstrapperApplications }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); @@ -132,7 +133,7 @@ namespace WixToolsetTest.BootstrapperApplications } } - [Fact] + [TestMethod] public void CanBuildUsingWixStdBa() { using (var fs = new DisposableFileSystem()) @@ -152,11 +153,11 @@ namespace WixToolsetTest.BootstrapperApplications }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); } } - //[Fact] + // [TestMethod] //public void CanBuildUsingMBAWithAlwaysInstallPrereqs() //{ // using (var fs = new DisposableFileSystem()) @@ -179,7 +180,7 @@ namespace WixToolsetTest.BootstrapperApplications // compileResult.AssertSuccess(); - // Assert.True(File.Exists(bundleFile)); + // Assert.IsTrue(File.Exists(bundleFile)); // var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath); // extractResult.AssertSuccess(); @@ -198,7 +199,7 @@ namespace WixToolsetTest.BootstrapperApplications // } //} - [Fact] + [TestMethod] public void CannotBuildUsingMBAWithNoPrereqs() { using (var fs = new DisposableFileSystem()) @@ -223,14 +224,14 @@ namespace WixToolsetTest.BootstrapperApplications { "The WixManagedBootstrapperApplicationHost element has been deprecated.", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(1130, compileResult.ExitCode); + Assert.AreEqual(1130, compileResult.ExitCode); - Assert.False(File.Exists(bundleFile)); - Assert.False(File.Exists(Path.Combine(intermediateFolder, "test.exe"))); + Assert.IsFalse(File.Exists(bundleFile)); + Assert.IsFalse(File.Exists(Path.Combine(intermediateFolder, "test.exe"))); } } - [Fact] + [TestMethod] public void CannotBuildUsingDncbaMissingBAFactoryPayload() { using (var fs = new DisposableFileSystem()) @@ -254,14 +255,14 @@ namespace WixToolsetTest.BootstrapperApplications "The WixDotNetCoreBootstrapperApplicationHost element has been deprecated.", "The BootstrapperApplication element's Name or SourceFile attribute was not found; one of these is required." }, compileResult.Messages.Select(x => x.ToString()).ToArray()); - Assert.Equal(44, compileResult.ExitCode); + Assert.AreEqual(44, compileResult.ExitCode); - Assert.False(File.Exists(bundleFile)); - Assert.False(File.Exists(Path.Combine(intermediateFolder, "test.exe"))); + Assert.IsFalse(File.Exists(bundleFile)); + Assert.IsFalse(File.Exists(Path.Combine(intermediateFolder, "test.exe"))); } } - [Fact] + [TestMethod] public void CannotBuildUsingOverridableWrongCase() { using (var fs = new DisposableFileSystem()) @@ -284,7 +285,7 @@ namespace WixToolsetTest.BootstrapperApplications "-o", bundleFile, }); - Assert.InRange(result.ExitCode, 2, Int32.MaxValue); + Assert.IsTrue(result.ExitCode >= 2 && result.ExitCode <= Int32.MaxValue); var messages = result.Messages.Select(m => m.ToString()).ToList(); messages.Sort(); diff --git a/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/InternalUIBAFixture.cs b/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/InternalUIBAFixture.cs index 58d5d551..72e31540 100644 --- a/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/InternalUIBAFixture.cs +++ b/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/InternalUIBAFixture.cs @@ -5,13 +5,14 @@ namespace WixToolsetTest.BootstrapperApplications using System.IO; using System.Linq; using System.Xml; - using WixInternal.Core.TestPackage; - using WixInternal.TestSupport; - using Xunit; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.Core.MSTestPackage; + using WixInternal.MSTestSupport; + [TestClass] public class InternalUIBAFixture { - [Fact] + [TestMethod] public void CanBuildUsingWixIuiBa() { using (var fs = new DisposableFileSystem()) @@ -34,7 +35,7 @@ namespace WixToolsetTest.BootstrapperApplications }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); @@ -45,12 +46,12 @@ namespace WixToolsetTest.BootstrapperApplications "", }, balPackageInfos); - Assert.True(File.Exists(Path.Combine(baFolderPath, "wixpreq.thm"))); - Assert.True(File.Exists(Path.Combine(baFolderPath, "wixpreq.wxl"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "wixpreq.thm"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "wixpreq.wxl"))); } } - [Fact] + [TestMethod] public void CanBuildUsingWixIuiBaWithUrlPrereqPackage() { using (var fs = new DisposableFileSystem()) @@ -73,7 +74,7 @@ namespace WixToolsetTest.BootstrapperApplications }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); @@ -90,12 +91,12 @@ namespace WixToolsetTest.BootstrapperApplications "", }, mbaPrereqInfos); - Assert.True(File.Exists(Path.Combine(baFolderPath, "wixpreq.thm"))); - Assert.True(File.Exists(Path.Combine(baFolderPath, "wixpreq.wxl"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "wixpreq.thm"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "wixpreq.wxl"))); } } - [Fact] + [TestMethod] public void CanBuildUsingWixIuiBaWithImplicitPrimaryPackage() { using (var fs = new DisposableFileSystem()) @@ -118,7 +119,7 @@ namespace WixToolsetTest.BootstrapperApplications }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); @@ -135,12 +136,12 @@ namespace WixToolsetTest.BootstrapperApplications "", }, mbaPrereqInfos); - Assert.True(File.Exists(Path.Combine(baFolderPath, "wixpreq.thm"))); - Assert.True(File.Exists(Path.Combine(baFolderPath, "wixpreq.wxl"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "wixpreq.thm"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "wixpreq.wxl"))); } } - [Fact] + [TestMethod] public void CanBuildUsingWixIuiBaWithWarnings() { using (var fs = new DisposableFileSystem()) @@ -172,7 +173,7 @@ namespace WixToolsetTest.BootstrapperApplications compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); @@ -189,12 +190,12 @@ namespace WixToolsetTest.BootstrapperApplications "", }, mbaPrereqInfos); - Assert.True(File.Exists(Path.Combine(baFolderPath, "wixpreq.thm"))); - Assert.True(File.Exists(Path.Combine(baFolderPath, "wixpreq.wxl"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "wixpreq.thm"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "wixpreq.wxl"))); } } - [Fact] + [TestMethod] public void CanBuildUsingWixIuiBaAndForcedCachePrimaryPackage() { using (var fs = new DisposableFileSystem()) @@ -218,7 +219,7 @@ namespace WixToolsetTest.BootstrapperApplications compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); @@ -239,8 +240,8 @@ namespace WixToolsetTest.BootstrapperApplications "", }, mbaPrereqInfos); - Assert.True(File.Exists(Path.Combine(baFolderPath, "wixpreq.thm"))); - Assert.True(File.Exists(Path.Combine(baFolderPath, "wixpreq.wxl"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "wixpreq.thm"))); + Assert.IsTrue(File.Exists(Path.Combine(baFolderPath, "wixpreq.wxl"))); } static void AssertCacheType(XmlNode node) @@ -251,16 +252,16 @@ namespace WixToolsetTest.BootstrapperApplications if (package == "test.msi") { - Assert.Equal("force", cache); + Assert.AreEqual("force", cache); } else if (package == "wixnative.exe") { - Assert.Equal("keep", cache); + Assert.AreEqual("keep", cache); } } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithAllPrereqPackages() { using (var fs = new DisposableFileSystem()) @@ -285,11 +286,11 @@ namespace WixToolsetTest.BootstrapperApplications "When using WixInternalUIBootstrapperApplication, there must be one package with bal:PrimaryPackageType=\"default\".", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(6808, compileResult.ExitCode); + Assert.AreEqual(6808, compileResult.ExitCode); } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithImplicitNonMsiPrimaryPackage() { using (var fs = new DisposableFileSystem()) @@ -314,11 +315,11 @@ namespace WixToolsetTest.BootstrapperApplications "When using WixInternalUIBootstrapperApplication, packages must either be non-permanent and have the bal:PrimaryPackageType attribute, or be permanent and have the bal:PrereqPackage attribute set to 'yes'.", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(6811, compileResult.ExitCode); + Assert.AreEqual(6811, compileResult.ExitCode); } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithImplicitPrimaryPackageEnableFeatureSelection() { using (var fs = new DisposableFileSystem()) @@ -343,11 +344,11 @@ namespace WixToolsetTest.BootstrapperApplications "When using WixInternalUIBootstrapperApplication, packages must either be non-permanent and have the bal:PrimaryPackageType attribute, or be permanent and have the bal:PrereqPackage attribute set to 'yes'.", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(6811, compileResult.ExitCode); + Assert.AreEqual(6811, compileResult.ExitCode); } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithMultipleNonPermanentNonPrimaryPackages() { using (var fs = new DisposableFileSystem()) @@ -373,11 +374,11 @@ namespace WixToolsetTest.BootstrapperApplications "When using WixInternalUIBootstrapperApplication, packages must either be non-permanent and have the bal:PrimaryPackageType attribute, or be permanent and have the bal:PrereqPackage attribute set to 'yes'.", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(6811, compileResult.ExitCode); + Assert.AreEqual(6811, compileResult.ExitCode); } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithMultiplePrimaryPackagesOfSameType() { using (var fs = new DisposableFileSystem()) @@ -403,11 +404,11 @@ namespace WixToolsetTest.BootstrapperApplications "The location of the package related to the previous error.", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(6810, compileResult.ExitCode); + Assert.AreEqual(6810, compileResult.ExitCode); } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithNoDefaultPrimaryPackage() { using (var fs = new DisposableFileSystem()) @@ -432,11 +433,11 @@ namespace WixToolsetTest.BootstrapperApplications "When using WixInternalUIBootstrapperApplication, there must be one package with bal:PrimaryPackageType=\"default\".", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(6808, compileResult.ExitCode); + Assert.AreEqual(6808, compileResult.ExitCode); } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithNonMsiPrimaryPackage() { using (var fs = new DisposableFileSystem()) @@ -461,11 +462,11 @@ namespace WixToolsetTest.BootstrapperApplications "When using WixInternalUIBootstrapperApplication, each primary package must be an MsiPackage.", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(6814, compileResult.ExitCode); + Assert.AreEqual(6814, compileResult.ExitCode); } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithNonPermanentPrereqPackage() { using (var fs = new DisposableFileSystem()) @@ -490,11 +491,11 @@ namespace WixToolsetTest.BootstrapperApplications "When using WixInternalUIBootstrapperApplication and bal:PrereqPackage is set to 'yes', the package must be permanent.", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(6812, compileResult.ExitCode); + Assert.AreEqual(6812, compileResult.ExitCode); } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithPermanentPrimaryPackage() { using (var fs = new DisposableFileSystem()) @@ -520,11 +521,11 @@ namespace WixToolsetTest.BootstrapperApplications "When using WixInternalUIBootstrapperApplication, there must be one package with bal:PrimaryPackageType=\"default\".", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(6808, compileResult.ExitCode); + Assert.AreEqual(6808, compileResult.ExitCode); } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithPrimaryPackageEnableFeatureSelection() { using (var fs = new DisposableFileSystem()) @@ -550,11 +551,11 @@ namespace WixToolsetTest.BootstrapperApplications "When using WixInternalUIBootstrapperApplication, there must be one package with bal:PrimaryPackageType=\"default\".", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(6808, compileResult.ExitCode); + Assert.AreEqual(6808, compileResult.ExitCode); } } - [Fact] + [TestMethod] public void CannotBuildUsingWixIuiBaWithPrimaryPrereqPackage() { using (var fs = new DisposableFileSystem()) @@ -578,7 +579,7 @@ namespace WixToolsetTest.BootstrapperApplications "The MsiPackage/@PrereqPackage attribute's value, 'yes', cannot be specified with attribute PrimaryPackageType present.", }, compileResult.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(193, compileResult.ExitCode); + Assert.AreEqual(193, compileResult.ExitCode); } } } diff --git a/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/WixToolsetTest.BootstrapperApplications.csproj b/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/WixToolsetTest.BootstrapperApplications.csproj index 64fc297c..6a9b5856 100644 --- a/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/WixToolsetTest.BootstrapperApplications.csproj +++ b/src/ext/Bal/test/WixToolsetTest.BootstrapperApplications/WixToolsetTest.BootstrapperApplications.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -20,6 +20,7 @@ - + + diff --git a/src/ext/ComPlus/complus.cmd b/src/ext/ComPlus/complus.cmd deleted file mode 100644 index 3b3a5772..00000000 --- a/src/ext/ComPlus/complus.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -:parse_args -@if /i "%1"=="release" set _C=Release -@if not "%1"=="" shift & goto parse_args - -@echo ComPlus.wixext build %_C% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror || exit /b - -:: Test -dotnet test -c %_C% --no-build test\WixToolsetTest.ComPlus || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror -p:NoBuild=true wixext\WixToolset.ComPlus.wixext.csproj || exit /b - -@popd -@endlocal \ No newline at end of file diff --git a/src/ext/ComPlus/complus_t.proj b/src/ext/ComPlus/complus_t.proj new file mode 100644 index 00000000..439856b6 --- /dev/null +++ b/src/ext/ComPlus/complus_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/ComPlus/test/WixToolsetTest.ComPlus/ComPlusExtensionFixture.cs b/src/ext/ComPlus/test/WixToolsetTest.ComPlus/ComPlusExtensionFixture.cs index 17c5eb0f..7b38ef54 100644 --- a/src/ext/ComPlus/test/WixToolsetTest.ComPlus/ComPlusExtensionFixture.cs +++ b/src/ext/ComPlus/test/WixToolsetTest.ComPlus/ComPlusExtensionFixture.cs @@ -3,14 +3,15 @@ namespace WixToolsetTest.ComPlus { using System.Linq; - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; using WixToolset.ComPlus; - using Xunit; + [TestClass] public class ComPlusExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingComPlusPartition() { var folder = TestData.Get(@"TestData\UsingComPlusPartition"); diff --git a/src/ext/ComPlus/test/WixToolsetTest.ComPlus/WixToolsetTest.ComPlus.csproj b/src/ext/ComPlus/test/WixToolsetTest.ComPlus/WixToolsetTest.ComPlus.csproj index a9e9dbef..d0a7081b 100644 --- a/src/ext/ComPlus/test/WixToolsetTest.ComPlus/WixToolsetTest.ComPlus.csproj +++ b/src/ext/ComPlus/test/WixToolsetTest.ComPlus/WixToolsetTest.ComPlus.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -16,6 +16,7 @@ - + + diff --git a/src/ext/Dependency/dependency.cmd b/src/ext/Dependency/dependency.cmd deleted file mode 100644 index 0ebcbfd5..00000000 --- a/src/ext/Dependency/dependency.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -:parse_args -@if /i "%1"=="release" set _C=Release -@if not "%1"=="" shift & goto parse_args - -@echo Dependency.wixext build %_C% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror || exit /b - -:: Test -dotnet test -c %_C% --no-build test\WixToolsetTest.Dependency || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror -p:NoBuild=true wixext\WixToolset.Dependency.wixext.csproj || exit /b - -@popd -@endlocal diff --git a/src/ext/Dependency/dependency_t.proj b/src/ext/Dependency/dependency_t.proj new file mode 100644 index 00000000..d05b8de9 --- /dev/null +++ b/src/ext/Dependency/dependency_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/Dependency/test/WixToolsetTest.Dependency/DependencyExtensionFixture.cs b/src/ext/Dependency/test/WixToolsetTest.Dependency/DependencyExtensionFixture.cs index 6190a4e0..ade2a12e 100644 --- a/src/ext/Dependency/test/WixToolsetTest.Dependency/DependencyExtensionFixture.cs +++ b/src/ext/Dependency/test/WixToolsetTest.Dependency/DependencyExtensionFixture.cs @@ -4,14 +4,15 @@ namespace WixToolsetTest.Dependency { using System.Linq; using System.Text.RegularExpressions; - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; using WixToolset.Dependency; - using Xunit; + [TestClass] public class DependencyExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingProvides() { var folder = TestData.Get(@"TestData\UsingProvides"); diff --git a/src/ext/Dependency/test/WixToolsetTest.Dependency/WixToolsetTest.Dependency.csproj b/src/ext/Dependency/test/WixToolsetTest.Dependency/WixToolsetTest.Dependency.csproj index 70b56f45..1fd46c63 100644 --- a/src/ext/Dependency/test/WixToolsetTest.Dependency/WixToolsetTest.Dependency.csproj +++ b/src/ext/Dependency/test/WixToolsetTest.Dependency/WixToolsetTest.Dependency.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -16,6 +16,7 @@ - + + diff --git a/src/ext/DirectX/directx.cmd b/src/ext/DirectX/directx.cmd deleted file mode 100644 index 56889513..00000000 --- a/src/ext/DirectX/directx.cmd +++ /dev/null @@ -1,24 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -:parse_args -@if /i "%1"=="release" set _C=Release -@if not "%1"=="" shift & goto parse_args - -@echo DirectX.wixext build %_C% - -:: Restore -msbuild -t:Restore -p:Configuration=%_C% -tl -nologo -warnaserror || exit /b - -:: Build -msbuild -t:Build -p:Configuration=%_C% -tl -nologo -warnaserror test\WixToolsetTest.DirectX\WixToolsetTest.DirectX.csproj || exit /b - -:: Test -dotnet test -c %_C% --no-build test\WixToolsetTest.DirectX || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror wixext\WixToolset.DirectX.wixext.csproj || exit /b - -@popd -@endlocal diff --git a/src/ext/DirectX/directx_t.proj b/src/ext/DirectX/directx_t.proj new file mode 100644 index 00000000..17b147ef --- /dev/null +++ b/src/ext/DirectX/directx_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/DirectX/test/WixToolsetTest.DirectX/DirectXExtensionFixture.cs b/src/ext/DirectX/test/WixToolsetTest.DirectX/DirectXExtensionFixture.cs index 64013ca6..dceaaec5 100644 --- a/src/ext/DirectX/test/WixToolsetTest.DirectX/DirectXExtensionFixture.cs +++ b/src/ext/DirectX/test/WixToolsetTest.DirectX/DirectXExtensionFixture.cs @@ -3,14 +3,15 @@ namespace WixToolsetTest.DirectX { using System.Linq; - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; using WixToolset.DirectX; - using Xunit; + [TestClass] public class DirectXExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingPixelShaderVersion() { var folder = TestData.Get(@"TestData\UsingPixelShaderVersion"); diff --git a/src/ext/DirectX/test/WixToolsetTest.DirectX/WixToolsetTest.DirectX.csproj b/src/ext/DirectX/test/WixToolsetTest.DirectX/WixToolsetTest.DirectX.csproj index 31a35320..c13f3300 100644 --- a/src/ext/DirectX/test/WixToolsetTest.DirectX/WixToolsetTest.DirectX.csproj +++ b/src/ext/DirectX/test/WixToolsetTest.DirectX/WixToolsetTest.DirectX.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -19,6 +19,7 @@ - + + diff --git a/src/ext/Firewall/firewall.cmd b/src/ext/Firewall/firewall.cmd deleted file mode 100644 index 92926a8c..00000000 --- a/src/ext/Firewall/firewall.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -:parse_args -@if /i "%1"=="release" set _C=Release -@if not "%1"=="" shift & goto parse_args - -@echo Firewall.wixext build %_C% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror || exit /b - -:: Test -dotnet test -c %_C% --no-build test\WixToolsetTest.Firewall || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror -p:NoBuild=true wixext\WixToolset.Firewall.wixext.csproj || exit /b - -@popd -@endlocal diff --git a/src/ext/Firewall/firewall_t.proj b/src/ext/Firewall/firewall_t.proj new file mode 100644 index 00000000..67229c39 --- /dev/null +++ b/src/ext/Firewall/firewall_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/Firewall/test/WixToolsetTest.Firewall/FirewallExtensionFixture.cs b/src/ext/Firewall/test/WixToolsetTest.Firewall/FirewallExtensionFixture.cs index 65016865..4b9aecd7 100644 --- a/src/ext/Firewall/test/WixToolsetTest.Firewall/FirewallExtensionFixture.cs +++ b/src/ext/Firewall/test/WixToolsetTest.Firewall/FirewallExtensionFixture.cs @@ -6,14 +6,15 @@ namespace WixToolsetTest.Firewall using System.IO; using System.Linq; using System.Xml.Linq; - using WixInternal.Core.TestPackage; - using WixInternal.TestSupport; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.Core.MSTestPackage; + using WixInternal.MSTestSupport; using WixToolset.Firewall; - using Xunit; + [TestClass] public class FirewallExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingFirewall() { var folder = TestData.Get(@"TestData\UsingFirewall"); @@ -52,7 +53,7 @@ namespace WixToolsetTest.Firewall }, results); } - [Fact] + [TestMethod] public void CanBuildUsingFirewallARM64() { var folder = TestData.Get(@"TestData\UsingFirewall"); @@ -91,7 +92,7 @@ namespace WixToolsetTest.Firewall }, results); } - [Fact] + [TestMethod] public void CanBuildWithProperties() { var folder = TestData.Get(@"TestData\UsingProperties"); @@ -112,7 +113,7 @@ namespace WixToolsetTest.Firewall }, results); } - [Fact] + [TestMethod] public void CanBuildWithPropertiesUsingFirewallARM64() { var folder = TestData.Get(@"TestData\UsingProperties"); @@ -133,7 +134,7 @@ namespace WixToolsetTest.Firewall }, results); } - [Fact] + [TestMethod] public void CanRoundtripFirewallExceptions() { var folder = TestData.Get(@"TestData", "UsingFirewall"); @@ -181,7 +182,7 @@ namespace WixToolsetTest.Firewall }, actual.Select(a => a.Name).ToArray()); } - [Fact] + [TestMethod] public void CanRoundtripFirewallExceptionsWithProperties() { var folder = TestData.Get(@"TestData", "UsingProperties"); @@ -212,7 +213,7 @@ namespace WixToolsetTest.Firewall }, actual.Select(a => a.Name).ToArray()); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForApp() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleApp"); @@ -230,7 +231,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForPort() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExamplePort"); @@ -248,7 +249,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForDNSScope() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleDNSScope"); @@ -264,7 +265,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForDHCPScope() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleDHCPScope"); @@ -281,7 +282,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForWINSScope() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleWINSScope"); @@ -298,7 +299,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForDefaultGatewayScope() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleDefaultGatewayScope"); @@ -315,7 +316,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForINetFwRule3Values() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "INetFwRule3 values"); @@ -335,7 +336,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForINetFwRule3Properties() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "INetFwRule3 properties"); @@ -355,7 +356,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForGroupingValue() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "GroupingExample1"); @@ -370,7 +371,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForGroupingProperty() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "GroupingExample2"); @@ -386,7 +387,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForIcmpValue() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ICMPExample1"); @@ -401,7 +402,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForIcmpProperty() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ICMPExample2"); @@ -416,7 +417,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForLocalScopeValue() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "LocalScopeExample1"); @@ -431,7 +432,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForLocalScopeProperty() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "LocalScopeExample2"); @@ -446,7 +447,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForRemotePorts() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "RemotePortExample1"); @@ -462,7 +463,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectForRemotePortsProperty() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "RemotePortExample2"); @@ -478,7 +479,7 @@ namespace WixToolsetTest.Firewall }, actual.Attributes); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectWhenPropertiesAreUsed() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "[NAME]", "UsingProperties"); @@ -526,10 +527,10 @@ namespace WixToolsetTest.Firewall }); var nested = related.Select(e => e.Attributes().Single(a => a.Name.LocalName == "Name").Value); - Assert.False(nested.Any()); + Assert.IsFalse(nested.Any()); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectWhenNestedPropertiesAreUsed() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "Single Nested properties", "UsingProperties"); @@ -559,10 +560,10 @@ namespace WixToolsetTest.Firewall }); var nested = related.Select(e => e.Attributes().Single(a => a.Name.LocalName == "Name").Value); - Assert.False(nested.Any()); + Assert.IsFalse(nested.Any()); } - [Fact] + [TestMethod] public void RoundtripAttributesAreCorrectWhenMultipleNestedPropertiesAreUsed() { var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "Multiple Nested properties", "UsingProperties"); diff --git a/src/ext/Firewall/test/WixToolsetTest.Firewall/WixToolsetTest.Firewall.csproj b/src/ext/Firewall/test/WixToolsetTest.Firewall/WixToolsetTest.Firewall.csproj index e46020a6..5de88c8b 100644 --- a/src/ext/Firewall/test/WixToolsetTest.Firewall/WixToolsetTest.Firewall.csproj +++ b/src/ext/Firewall/test/WixToolsetTest.Firewall/WixToolsetTest.Firewall.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -16,6 +16,7 @@ - + + diff --git a/src/ext/Http/http.cmd b/src/ext/Http/http.cmd deleted file mode 100644 index afcffb24..00000000 --- a/src/ext/Http/http.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -:parse_args -@if /i "%1"=="release" set _C=Release -@if not "%1"=="" shift & goto parse_args - -@echo Http.wixext build %_C% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror || exit /b - -:: Test -dotnet test -c %_C% --no-build test\WixToolsetTest.Http || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror -p:NoBuild=true wixext\WixToolset.Http.wixext.csproj || exit /b - -@popd -@endlocal diff --git a/src/ext/Http/http_t.proj b/src/ext/Http/http_t.proj new file mode 100644 index 00000000..8cd9c7d4 --- /dev/null +++ b/src/ext/Http/http_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/Http/test/WixToolsetTest.Http/HttpExtensionFixture.cs b/src/ext/Http/test/WixToolsetTest.Http/HttpExtensionFixture.cs index ffd698f5..c91ce937 100644 --- a/src/ext/Http/test/WixToolsetTest.Http/HttpExtensionFixture.cs +++ b/src/ext/Http/test/WixToolsetTest.Http/HttpExtensionFixture.cs @@ -2,14 +2,15 @@ namespace WixToolsetTest.Http { - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; using WixToolset.Http; - using Xunit; + [TestClass] public class HttpExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingSsl() { var folder = TestData.Get("TestData", "Ssl"); @@ -29,7 +30,7 @@ namespace WixToolsetTest.Http }, results); } - [Fact] + [TestMethod] public void CanBuildUsingUrlReservation() { var folder = TestData.Get(@"TestData\UsingUrlReservation"); diff --git a/src/ext/Http/test/WixToolsetTest.Http/WixToolsetTest.Http.csproj b/src/ext/Http/test/WixToolsetTest.Http/WixToolsetTest.Http.csproj index b23ef481..d5e6c929 100644 --- a/src/ext/Http/test/WixToolsetTest.Http/WixToolsetTest.Http.csproj +++ b/src/ext/Http/test/WixToolsetTest.Http/WixToolsetTest.Http.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -16,6 +16,7 @@ - + + diff --git a/src/ext/Iis/iis.cmd b/src/ext/Iis/iis.cmd deleted file mode 100644 index 0ae87a77..00000000 --- a/src/ext/Iis/iis.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -:parse_args -@if /i "%1"=="release" set _C=Release -@if not "%1"=="" shift & goto parse_args - -@echo Iis.wixext build %_C% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror || exit /b - -:: Test -dotnet test test\WixToolsetTest.Iis -c %_C% --no-build --nologo || exit /b - -:: Pack -dotnet pack wixext\WixToolset.Iis.wixext.csproj -c %_C% --no-build --nologo || exit /b - -@popd -@endlocal diff --git a/src/ext/Iis/iis_t.proj b/src/ext/Iis/iis_t.proj new file mode 100644 index 00000000..84473475 --- /dev/null +++ b/src/ext/Iis/iis_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/Iis/test/WixToolsetTest.Iis/IisExtensionFixture.cs b/src/ext/Iis/test/WixToolsetTest.Iis/IisExtensionFixture.cs index ab3f35d9..01a89dc0 100644 --- a/src/ext/Iis/test/WixToolsetTest.Iis/IisExtensionFixture.cs +++ b/src/ext/Iis/test/WixToolsetTest.Iis/IisExtensionFixture.cs @@ -3,14 +3,15 @@ namespace WixToolsetTest.Iis { using System.Linq; - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; using WixToolset.Iis; - using Xunit; + [TestClass] public class IisExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingIIs() { var folder = TestData.Get(@"TestData\UsingIis"); diff --git a/src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.csproj b/src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.csproj index a39e5b0b..a0a6e043 100644 --- a/src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.csproj +++ b/src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -19,6 +19,7 @@ - + + diff --git a/src/ext/Msmq/msmq.cmd b/src/ext/Msmq/msmq.cmd deleted file mode 100644 index 3ebceab4..00000000 --- a/src/ext/Msmq/msmq.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -:parse_args -@if /i "%1"=="release" set _C=Release -@if not "%1"=="" shift & goto parse_args - -@echo Msmq.wixext build %_C% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror || exit /b - -:: Test -dotnet test test\WixToolsetTest.Msmq -c %_C% --no-build --nologo || exit /b - -:: Pack -dotnet pack wixext\WixToolset.Msmq.wixext.csproj -c %_C% --no-build --nologo || exit /b - -@popd -@endlocal diff --git a/src/ext/Msmq/msmq_t.proj b/src/ext/Msmq/msmq_t.proj new file mode 100644 index 00000000..73424370 --- /dev/null +++ b/src/ext/Msmq/msmq_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/Msmq/test/WixToolsetTest.Msmq/MsmqExtensionFixture.cs b/src/ext/Msmq/test/WixToolsetTest.Msmq/MsmqExtensionFixture.cs index 970bc2e9..60335b8a 100644 --- a/src/ext/Msmq/test/WixToolsetTest.Msmq/MsmqExtensionFixture.cs +++ b/src/ext/Msmq/test/WixToolsetTest.Msmq/MsmqExtensionFixture.cs @@ -6,14 +6,15 @@ namespace WixToolsetTest.Msmq using System.IO; using System.Linq; using System.Xml.Linq; - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; using WixToolset.Msmq; - using Xunit; + [TestClass] public class MsmqExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingMessageQueue() { var folder = TestData.Get(@"TestData\UsingMessageQueue"); @@ -36,7 +37,8 @@ namespace WixToolsetTest.Msmq }, results); } - [Fact(Skip = "Util:Wix4Group and Util:Wix6Group decompilation issues prevent this usage currently")] + [TestMethod] + [Ignore("Util:Wix4Group and Util:Wix6Group decompilation issues prevent this usage currently")] public void CanRoundtripMessageQueue() { var folder = TestData.Get(@"TestData\UsingMessageQueue"); diff --git a/src/ext/Msmq/test/WixToolsetTest.Msmq/WixToolsetTest.Msmq.csproj b/src/ext/Msmq/test/WixToolsetTest.Msmq/WixToolsetTest.Msmq.csproj index e7b6f21e..a8991c2e 100644 --- a/src/ext/Msmq/test/WixToolsetTest.Msmq/WixToolsetTest.Msmq.csproj +++ b/src/ext/Msmq/test/WixToolsetTest.Msmq/WixToolsetTest.Msmq.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -19,6 +19,7 @@ - + + diff --git a/src/ext/NetFx/netfx.cmd b/src/ext/NetFx/netfx.cmd deleted file mode 100644 index d81959cc..00000000 --- a/src/ext/NetFx/netfx.cmd +++ /dev/null @@ -1,48 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -@set _L=%~dp0..\..\..\build\logs - -:parse_args -@if /i "%1"=="release" set _C=Release -@if /i "%1"=="inc" set _INC=1 -@if /i "%1"=="clean" set _CLEAN=1 -@if not "%1"=="" shift & goto parse_args - -@set _B=%~dp0..\..\..\build\NetFx.wixext\%_C% - -:: Clean - -@if "%_INC%"=="" call :clean -@if NOT "%_CLEAN%"=="" goto :end - -@echo NetFx.wixext build %_C% - -:: Restore -nuget restore netcoresearch\packages.config || exit /b - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror -bl:%_L%\ext_netfx_build.binlog || exit /b - -:: Test -dotnet test ^ - %_B%\net6.0\WixToolsetTest.NetFx.dll ^ - --nologo -l "trx;LogFileName=%_L%\TestResults\netfx.wixext.trx" || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror -p:NoBuild=true wixext\WixToolset.Netfx.wixext.csproj || exit /b - -@goto :end - -:clean -@rd /s/q "..\..\build\NetFx.wixext" 2> nul -@del "..\..\build\artifacts\WixToolset.NetFx.wixext.*.nupkg" 2> nul -@del "%_L%\ext_netfx_build.binlog" 2> nul -@del "%_L%\TestResults\netfx.wixext.trx" 2> nul -@rd /s/q "%USERPROFILE%\.nuget\packages\wixtoolset.netfx.wixext" 2> nul -@exit /b - -:end -@popd -@endlocal diff --git a/src/ext/NetFx/netfx_t.proj b/src/ext/NetFx/netfx_t.proj new file mode 100644 index 00000000..3301dc8a --- /dev/null +++ b/src/ext/NetFx/netfx_t.proj @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/NetFx/test/WixToolsetTest.Netfx/NetfxExtensionFixture.cs b/src/ext/NetFx/test/WixToolsetTest.Netfx/NetfxExtensionFixture.cs index a78a5617..37f715bf 100644 --- a/src/ext/NetFx/test/WixToolsetTest.Netfx/NetfxExtensionFixture.cs +++ b/src/ext/NetFx/test/WixToolsetTest.Netfx/NetfxExtensionFixture.cs @@ -4,14 +4,15 @@ namespace WixToolsetTest.Netfx { using System.IO; using System.Linq; - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; using WixToolset.Netfx; - using Xunit; + [TestClass] public class NetfxExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingLatestDotNetCorePackages() { using (var fs = new DisposableFileSystem()) @@ -21,30 +22,24 @@ namespace WixToolsetTest.Netfx var bundleSourceFolder = TestData.Get(@"TestData\UsingDotNetCorePackages"); var intermediateFolder = Path.Combine(baseFolder, "obj"); - var extensionResult = WixRunner.Execute(new[] - { - "extension", "add", - "WixToolset.BootstrapperApplications.wixext" - }); - var compileResult = WixRunner.Execute(new[] { "build", Path.Combine(bundleSourceFolder, "BundleLatest.wxs"), Path.Combine(bundleSourceFolder, "NetCore3.1.12_x86.wxs"), Path.Combine(bundleSourceFolder, "NetCore3.1.12_x64.wxs"), - "-ext", "WixToolset.BootstrapperApplications.wixext", + "-ext", TestData.Get(@"WixToolset.BootstrapperApplications.wixext.dll").Replace("NetFx.wixext", "Bal.wixext"), "-ext", TestData.Get(@"WixToolset.Netfx.wixext.dll"), "-intermediateFolder", intermediateFolder, "-o", bundleFile, }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); } } - [Fact] + [TestMethod] public void CanBuildUsingLatestDotNetCorePackages_X64() { using (var fs = new DisposableFileSystem()) @@ -54,29 +49,23 @@ namespace WixToolsetTest.Netfx var bundleSourceFolder = TestData.Get(@"TestData\UsingDotNetCorePackages"); var intermediateFolder = Path.Combine(baseFolder, "obj"); - var extensionResult = WixRunner.Execute(new[] - { - "extension", "add", - "WixToolset.BootstrapperApplications.wixext" - }); - var compileResult = WixRunner.Execute(new[] { "build", Path.Combine(bundleSourceFolder, "BundleLatest_x64.wxs"), Path.Combine(bundleSourceFolder, "NetCore3.1.12_x64.wxs"), - "-ext", "WixToolset.BootstrapperApplications.wixext", + "-ext", TestData.Get(@"WixToolset.BootstrapperApplications.wixext.dll").Replace("NetFx.wixext", "Bal.wixext"), "-ext", TestData.Get(@"WixToolset.Netfx.wixext.dll"), "-intermediateFolder", intermediateFolder, "-o", bundleFile, }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); } } - [Fact] + [TestMethod] public void CanBuildUsingNetFx481Packages() { using (var fs = new DisposableFileSystem()) @@ -86,17 +75,11 @@ namespace WixToolsetTest.Netfx var bundleSourceFolder = TestData.Get(@"TestData\UsingNetFxPackages"); var intermediateFolder = Path.Combine(baseFolder, "obj"); - var extensionResult = WixRunner.Execute(new[] - { - "extension", "add", - "WixToolset.BootstrapperApplications.wixext" - }); - var compileResult = WixRunner.Execute(new[] { "build", Path.Combine(bundleSourceFolder, "BundleLatest.wxs"), - "-ext", "WixToolset.BootstrapperApplications.wixext", + "-ext", TestData.Get(@"WixToolset.BootstrapperApplications.wixext.dll").Replace("NetFx.wixext", "Bal.wixext"), "-ext", TestData.Get(@"WixToolset.Netfx.wixext.dll"), "-intermediateFolder", intermediateFolder, "-o", bundleFile, @@ -104,11 +87,11 @@ namespace WixToolsetTest.Netfx }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); } } - [Fact] + [TestMethod] public void CanBuildUsingNetFxSearches() { using (var fs = new DisposableFileSystem()) @@ -118,20 +101,12 @@ namespace WixToolsetTest.Netfx var bundleSourceFolder = TestData.Get(@"TestData\UsingNetFxSearches"); var intermediateFolder = Path.Combine(baseFolder, "obj"); - var extensionResult = WixRunner.Execute(warningsAsErrors: true, new[] - { - "extension", "add", - "WixToolset.BootstrapperApplications.wixext", - "extension", "add", - "WixToolset.Util.wixext", - }); - var compileResult = WixRunner.Execute(new[] { "build", Path.Combine(bundleSourceFolder, "BundleLatest.wxs"), - "-ext", "WixToolset.BootstrapperApplications.wixext", - "-ext", "WixToolset.Util.wixext", + "-ext", TestData.Get(@"WixToolset.BootstrapperApplications.wixext.dll").Replace("NetFx.wixext", "Bal.wixext"), + "-ext", TestData.Get(@"WixToolset.Util.wixext.dll").Replace("NetFx.wixext", "Util.wixext"), "-ext", TestData.Get(@"WixToolset.Netfx.wixext.dll"), "-intermediateFolder", intermediateFolder, "-o", bundleFile, @@ -139,11 +114,11 @@ namespace WixToolsetTest.Netfx }); compileResult.AssertSuccess(); - Assert.True(File.Exists(bundleFile)); + Assert.IsTrue(File.Exists(bundleFile)); } } - [Fact] + [TestMethod] public void CanBuildUsingNativeImage() { var folder = TestData.Get(@"TestData\UsingNativeImage"); @@ -162,7 +137,7 @@ namespace WixToolsetTest.Netfx }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildUsingNativeImageX64() { var folder = TestData.Get(@"TestData\UsingNativeImage"); @@ -181,7 +156,7 @@ namespace WixToolsetTest.Netfx }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildUsingNativeImageARM64() { var folder = TestData.Get(@"TestData\UsingNativeImage"); @@ -200,7 +175,7 @@ namespace WixToolsetTest.Netfx }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildUsingDotNetCompatibilityCheck() { var folder = TestData.Get(@"TestData\UsingDotNetCompatibilityCheck"); diff --git a/src/ext/NetFx/test/WixToolsetTest.Netfx/WixToolsetTest.Netfx.csproj b/src/ext/NetFx/test/WixToolsetTest.Netfx/WixToolsetTest.Netfx.csproj index 4e509cce..bdca49e6 100644 --- a/src/ext/NetFx/test/WixToolsetTest.Netfx/WixToolsetTest.Netfx.csproj +++ b/src/ext/NetFx/test/WixToolsetTest.Netfx/WixToolsetTest.Netfx.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -16,6 +16,7 @@ - + + diff --git a/src/ext/PowerShell/powershell_t.proj b/src/ext/PowerShell/powershell_t.proj new file mode 100644 index 00000000..da54d629 --- /dev/null +++ b/src/ext/PowerShell/powershell_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/PowerShell/ps.cmd b/src/ext/PowerShell/ps.cmd deleted file mode 100644 index 4a8aa61e..00000000 --- a/src/ext/PowerShell/ps.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -:parse_args -@if /i "%1"=="release" set _C=Release -@if not "%1"=="" shift & goto parse_args - -@echo PowerShell.wixext build %_C% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror || exit /b - -:: Test -dotnet test -c %_C% --no-build test\WixToolsetTest.PowerShell || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror -p:NoBuild=true wixext\WixToolset.PowerShell.wixext.csproj || exit /b - -@popd -@endlocal diff --git a/src/ext/PowerShell/test/WixToolsetTest.PowerShell/PowerShellExtensionFixture.cs b/src/ext/PowerShell/test/WixToolsetTest.PowerShell/PowerShellExtensionFixture.cs index eafda99f..a1dc3282 100644 --- a/src/ext/PowerShell/test/WixToolsetTest.PowerShell/PowerShellExtensionFixture.cs +++ b/src/ext/PowerShell/test/WixToolsetTest.PowerShell/PowerShellExtensionFixture.cs @@ -2,14 +2,15 @@ namespace WixToolsetTest.PowerShell { - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; using WixToolset.PowerShell; - using Xunit; + [TestClass] public class PowerShellExtensionFixture { - [Fact] + [TestMethod] public void CantBuildUsingTypesFileWithoutSnapIn() { var folder = TestData.Get(@"TestData\TypesFile"); @@ -19,8 +20,8 @@ namespace WixToolsetTest.PowerShell var results = build.BuildAndQuery(args => { wixRunnerResult = WixRunner.Execute(args); }); - Assert.NotNull(wixRunnerResult); - Assert.Equal((int)PSErrors.Ids.NeitherIdSpecified, wixRunnerResult.ExitCode); + Assert.IsNotNull(wixRunnerResult); + Assert.AreEqual((int)PSErrors.Ids.NeitherIdSpecified, wixRunnerResult.ExitCode); } } } diff --git a/src/ext/PowerShell/test/WixToolsetTest.PowerShell/WixToolsetTest.Powershell.csproj b/src/ext/PowerShell/test/WixToolsetTest.PowerShell/WixToolsetTest.Powershell.csproj index 347ca1ed..cff13cb7 100644 --- a/src/ext/PowerShell/test/WixToolsetTest.PowerShell/WixToolsetTest.Powershell.csproj +++ b/src/ext/PowerShell/test/WixToolsetTest.PowerShell/WixToolsetTest.Powershell.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -16,6 +16,7 @@ - + + diff --git a/src/ext/Sql/sql.cmd b/src/ext/Sql/sql.cmd deleted file mode 100644 index 41af0223..00000000 --- a/src/ext/Sql/sql.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -:parse_args -@if /i "%1"=="release" set _C=Release -@if not "%1"=="" shift & goto parse_args - -@echo Sql.wixext build %_C% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror || exit /b - -:: Test -dotnet test -c %_C% --no-build test\WixToolsetTest.Sql || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror -p:NoBuild=true wixext\WixToolset.Sql.wixext.csproj || exit /b - -@popd -@endlocal diff --git a/src/ext/Sql/sql_t.proj b/src/ext/Sql/sql_t.proj new file mode 100644 index 00000000..97b2c8fd --- /dev/null +++ b/src/ext/Sql/sql_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sql/test/WixToolsetTest.Sql/SqlExtensionFixture.cs b/src/ext/Sql/test/WixToolsetTest.Sql/SqlExtensionFixture.cs index 5576576d..14ca14c3 100644 --- a/src/ext/Sql/test/WixToolsetTest.Sql/SqlExtensionFixture.cs +++ b/src/ext/Sql/test/WixToolsetTest.Sql/SqlExtensionFixture.cs @@ -3,14 +3,15 @@ namespace WixToolsetTest.Sql { using System.Linq; - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; using WixToolset.Sql; - using Xunit; + [TestClass] public class SqlExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingSqlStuff() { var folder = TestData.Get(@"TestData\UsingSql"); diff --git a/src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.csproj b/src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.csproj index 6c848683..62345258 100644 --- a/src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.csproj +++ b/src/ext/Sql/test/WixToolsetTest.Sql/WixToolsetTest.Sql.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -16,6 +16,7 @@ - + + diff --git a/src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs b/src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs index bb20f087..e06feac7 100644 --- a/src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs +++ b/src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs @@ -4,15 +4,16 @@ namespace WixToolsetTest.UI { using System.IO; using System.Linq; - using WixInternal.Core.TestPackage; - using WixInternal.TestSupport; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.Core.MSTestPackage; + using WixInternal.MSTestSupport; using WixToolset.Data.WindowsInstaller; using WixToolset.UI; - using Xunit; + [TestClass] public class UIExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingWixUIAdvanced() { var folder = TestData.Get(@"TestData", "WixUI_Advanced"); @@ -20,7 +21,7 @@ namespace WixToolsetTest.UI var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); var results = build.BuildAndQuery(Build, "Binary", "Dialog", "CustomAction", "ControlEvent", "InstallUISequence"); - Assert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t")); WixAssert.CompareLineByLine(new[] { "Binary:WixUI_Bmp_Banner\t[Binary data]", @@ -37,7 +38,7 @@ namespace WixToolsetTest.UI "CustomAction:WixSetPerMachineFolder\t51\tAPPLICATIONFOLDER\t[WixPerMachineFolder]\t", "CustomAction:WixSetPerUserFolder\t51\tAPPLICATIONFOLDER\t[WixPerUserFolder]\t", }, results.Where(r => r.StartsWith("CustomAction:")).ToArray()); - Assert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).ToArray()); + WixAssert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).ToArray()); WixAssert.CompareLineByLine(new[] { "InstallUISequence:AdvancedWelcomeEulaDlg\tNOT Installed\t1297", @@ -45,7 +46,7 @@ namespace WixToolsetTest.UI }, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray()); } - [Fact] + [TestMethod] public void CanBuildUsingWixUIAdvancedX64() { var folder = TestData.Get(@"TestData", "WixUI_Advanced"); @@ -53,7 +54,7 @@ namespace WixToolsetTest.UI var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); var results = build.BuildAndQuery(BuildX64, "Binary", "Dialog", "CustomAction", "ControlEvent", "InstallUISequence"); - Assert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t")); WixAssert.CompareLineByLine(new[] { "Binary:WixUI_Bmp_Banner\t[Binary data]", @@ -70,10 +71,10 @@ namespace WixToolsetTest.UI "CustomAction:WixSetPerMachineFolder\t51\tAPPLICATIONFOLDER\t[WixPerMachineFolder]\t", "CustomAction:WixSetPerUserFolder\t51\tAPPLICATIONFOLDER\t[WixPerUserFolder]\t", }, results.Where(r => r.StartsWith("CustomAction:")).ToArray()); - Assert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).ToArray()); + WixAssert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).ToArray()); } - [Fact] + [TestMethod] public void CanBuildUsingWixUIAdvancedARM64() { var folder = TestData.Get(@"TestData", "WixUI_Advanced"); @@ -81,7 +82,7 @@ namespace WixToolsetTest.UI var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); var results = build.BuildAndQuery(BuildARM64, "Binary", "Dialog", "CustomAction", "ControlEvent", "InstallUISequence"); - Assert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t")); WixAssert.CompareLineByLine(new[] { "Binary:WixUI_Bmp_Banner\t[Binary data]", @@ -98,10 +99,10 @@ namespace WixToolsetTest.UI "CustomAction:WixSetPerMachineFolder\t51\tAPPLICATIONFOLDER\t[WixPerMachineFolder]\t", "CustomAction:WixSetPerUserFolder\t51\tAPPLICATIONFOLDER\t[WixPerUserFolder]\t", }, results.Where(r => r.StartsWith("CustomAction:")).ToArray()); - Assert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).ToArray()); + WixAssert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).ToArray()); } - [Fact] + [TestMethod] public void CanBuildUsingWixUIFeatureTree() { var folder = TestData.Get(@"TestData", "WixUI_FeatureTree"); @@ -109,9 +110,9 @@ namespace WixToolsetTest.UI var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); var results = build.BuildAndQuery(BuildX64, "Binary", "Dialog", "CustomAction", "ControlEvent", "InstallUISequence"); - Assert.Single(results, result => result.StartsWith("Dialog:WelcomeDlg\t")); - Assert.Single(results, result => result.StartsWith("Dialog:CustomizeDlg\t")); - Assert.Empty(results.Where(result => result.StartsWith("Dialog:SetupTypeDlg\t"))); + WixAssert.Single(results, result => result.StartsWith("Dialog:WelcomeDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:CustomizeDlg\t")); + WixAssert.Empty(results.Where(result => result.StartsWith("Dialog:SetupTypeDlg\t"))); WixAssert.CompareLineByLine(new[] { "Binary:WixUI_Bmp_Banner\t[Binary data]", @@ -125,14 +126,14 @@ namespace WixToolsetTest.UI { "CustomAction:SetWIXUI_EXITDIALOGOPTIONALTEXT\t51\tWIXUI_EXITDIALOGOPTIONALTEXT\tThank you for installing [ProductName].\t", }, results.Where(r => r.StartsWith("CustomAction:")).ToArray()); - Assert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction"))); + WixAssert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction"))); WixAssert.CompareLineByLine(new[] { "InstallUISequence:WelcomeDlg\tNOT Installed OR PATCH\t1297", }, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray()); } - [Fact] + [TestMethod] public void CanBuildWithWixUIInstallDirWithCustomizedEula() { var folder = TestData.Get(@"TestData", "WixUI_InstallDir"); @@ -140,8 +141,8 @@ namespace WixToolsetTest.UI var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); var results = build.BuildAndQuery(BuildEula, "Binary", "Dialog", "CustomAction", "Property", "ControlEvent", "InstallUISequence"); - Assert.Single(results, result => result.StartsWith("Dialog:InstallDirDlg\t")); - Assert.Single(results, result => result.StartsWith("Dialog:WelcomeDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:InstallDirDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:WelcomeDlg\t")); WixAssert.CompareLineByLine(new[] { "Binary:WixUI_Bmp_Banner\t[Binary data]", @@ -171,7 +172,7 @@ namespace WixToolsetTest.UI }, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray()); } - [Fact] + [TestMethod] public void CanBuildUsingWixUIMinimal() { var folder = TestData.Get(@"TestData", "WixUI_Minimal"); @@ -179,7 +180,7 @@ namespace WixToolsetTest.UI var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); var results = build.BuildAndQuery(Build, "Binary", "Dialog", "CustomAction", "ControlEvent", "InstallUISequence"); - Assert.Single(results, result => result.StartsWith("Dialog:WelcomeEulaDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:WelcomeEulaDlg\t")); WixAssert.CompareLineByLine(new[] { "Binary:WixUI_Bmp_Banner\t[Binary data]", @@ -189,8 +190,8 @@ namespace WixToolsetTest.UI "Binary:WixUI_Ico_Exclam\t[Binary data]", "Binary:WixUI_Ico_Info\t[Binary data]", }, results.Where(r => r.StartsWith("Binary:")).ToArray()); - Assert.Empty(results.Where(r => r.StartsWith("CustomAction:"))); - Assert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction"))); + WixAssert.Empty(results.Where(r => r.StartsWith("CustomAction:"))); + WixAssert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction"))); WixAssert.CompareLineByLine(new[] { "InstallUISequence:WelcomeDlg\tInstalled AND PATCH\t1296", @@ -198,7 +199,7 @@ namespace WixToolsetTest.UI }, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray()); } - [Fact] + [TestMethod] public void CanBuildUsingWixUIMinimalInKazakh() { var folder = TestData.Get(@"TestData", "WixUI_Minimal"); @@ -207,10 +208,10 @@ namespace WixToolsetTest.UI var results = build.BuildAndQuery(BuildInKazakh, "Dialog"); var welcomeDlg = results.Where(r => r.StartsWith("Dialog:WelcomeDlg\t")).Select(r => r.Split('\t')).Single(); - Assert.Equal("[ProductName] бағдарламасын орнату", welcomeDlg[6]); + Assert.AreEqual("[ProductName] бағдарламасын орнату", welcomeDlg[6]); } - [Fact] + [TestMethod] public void CanBuildUsingWixUIMinimalAndReadPdb() { var folder = TestData.Get(@"TestData", "WixUI_Minimal"); @@ -236,7 +237,7 @@ namespace WixToolsetTest.UI } } - [Fact] + [TestMethod] public void CanBuildUsingWixUIMondo() { var folder = TestData.Get(@"TestData", "WixUI_Mondo"); @@ -244,9 +245,9 @@ namespace WixToolsetTest.UI var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); var results = build.BuildAndQuery(Build, "Binary", "Dialog", "CustomAction", "ControlEvent", "InstallUISequence"); - Assert.Single(results, result => result.StartsWith("Dialog:WelcomeDlg\t")); - Assert.Single(results, result => result.StartsWith("Dialog:CustomizeDlg\t")); - Assert.Single(results, result => result.StartsWith("Dialog:SetupTypeDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:WelcomeDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:CustomizeDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:SetupTypeDlg\t")); WixAssert.CompareLineByLine(new[] { "Binary:WixUI_Bmp_Banner\t[Binary data]", @@ -271,7 +272,7 @@ namespace WixToolsetTest.UI }, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray()); } - [Fact] + [TestMethod] public void CanBuildUsingWixUIMondoLocalized() { var folder = TestData.Get(@"TestData", "WixUI_Mondo"); @@ -285,7 +286,7 @@ namespace WixToolsetTest.UI }, results.Where(s => s.StartsWith("Control:ErrorDlg\tY")).Select(s => s.Split('\t')[9]).ToArray()); } - [Fact] + [TestMethod] public void CanBuildWithInstallDirAndRemovedDialog() { var folder = TestData.Get(@"TestData", "InstallDir_NoLicense"); @@ -293,7 +294,7 @@ namespace WixToolsetTest.UI var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); var results = build.BuildAndQuery(Build, "Binary", "Dialog", "CustomAction", "Property", "ControlEvent", "InstallUISequence"); - Assert.Single(results, result => result.StartsWith("Dialog:InstallDirDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:InstallDirDlg\t")); WixAssert.CompareLineByLine(new[] { "Binary:WixUI_Bmp_Banner\t[Binary data]", @@ -318,7 +319,7 @@ namespace WixToolsetTest.UI "ControlEvent:InstallDirDlg\tNext\tDoAction\tWixUIValidatePath_X86\t1\t2", }, results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).OrderBy(s => s).ToArray()); - Assert.Empty(results.Where(result => result.Contains("LicenseAgreementDlg")).ToArray()); + WixAssert.Empty(results.Where(result => result.Contains("LicenseAgreementDlg")).ToArray()); WixAssert.CompareLineByLine(new[] { @@ -326,7 +327,7 @@ namespace WixToolsetTest.UI }, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray()); } - [Fact] + [TestMethod] public void CanBuildWithInstallDirAndAddedDialog() { var folder = TestData.Get(@"TestData", "InstallDir_SpecialDlg"); @@ -334,7 +335,7 @@ namespace WixToolsetTest.UI var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); var results = build.BuildAndQuery(BuildX64, "Binary", "Control", "Dialog", "CustomAction", "Property", "ControlEvent", "InstallUISequence"); - Assert.Single(results, result => result.StartsWith("Dialog:InstallDirDlg\t")); + WixAssert.Single(results, result => result.StartsWith("Dialog:InstallDirDlg\t")); WixAssert.CompareLineByLine(new[] { "Binary:WixUI_Bmp_Banner\t[Binary data]", @@ -344,23 +345,23 @@ namespace WixToolsetTest.UI "Binary:WixUI_Ico_Exclam\t[Binary data]", "Binary:WixUI_Ico_Info\t[Binary data]", }, results.Where(r => r.StartsWith("Binary:")).ToArray()); - Assert.Empty(results.Where(r => r.StartsWith("CustomAction:")).ToArray()); + WixAssert.Empty(results.Where(r => r.StartsWith("CustomAction:")).ToArray()); WixAssert.CompareLineByLine(new[] { "Property:WIXUI_INSTALLDIR\tINSTALLFOLDER", }, results.Where(r => r.StartsWith("Property:WIXUI")).ToArray()); - Assert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).OrderBy(s => s).ToArray()); + WixAssert.Empty(results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).OrderBy(s => s).ToArray()); WixAssert.CompareLineByLine(new[] { "InstallUISequence:WelcomeDlg\tNOT Installed OR PATCH\t1297", }, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray()); - Assert.Equal(10, results.Where(result => result.StartsWith("Control:") && result.Contains("SpecialDlg")).Count()); - Assert.Equal(5, results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("SpecialDlg")).Count()); - Assert.Single(results.Where(result => result.StartsWith("Dialog:") && result.Contains("SpecialDlg"))); + Assert.AreEqual(10, results.Where(result => result.StartsWith("Control:") && result.Contains("SpecialDlg")).Count()); + Assert.AreEqual(5, results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("SpecialDlg")).Count()); + WixAssert.Single(results.Where(result => result.StartsWith("Dialog:") && result.Contains("SpecialDlg"))); } - [Fact] + [TestMethod] public void CannotBuildWithV3LikeUIRef() { var folder = TestData.Get(@"TestData", "InvalidUIRef"); @@ -381,7 +382,7 @@ namespace WixToolsetTest.UI var results = WixRunner.Execute(args); var message = results.Messages.Single(); - Assert.Equal("The identifier 'WixUI:WixUI_Mondo' is inaccessible due to its protection level.", message.ToString()); + Assert.AreEqual("The identifier 'WixUI:WixUI_Mondo' is inaccessible due to its protection level.", message.ToString()); } } diff --git a/src/ext/UI/test/WixToolsetTest.UI/WixToolsetTest.UI.csproj b/src/ext/UI/test/WixToolsetTest.UI/WixToolsetTest.UI.csproj index 675f14f8..132920c5 100644 --- a/src/ext/UI/test/WixToolsetTest.UI/WixToolsetTest.UI.csproj +++ b/src/ext/UI/test/WixToolsetTest.UI/WixToolsetTest.UI.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -16,6 +16,7 @@ - + + diff --git a/src/ext/UI/ui.cmd b/src/ext/UI/ui.cmd deleted file mode 100644 index a990db91..00000000 --- a/src/ext/UI/ui.cmd +++ /dev/null @@ -1,42 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -@set _L=%~dp0..\..\..\build\logs - -:parse_args -@if /i "%1"=="release" set _C=Release -@if /i "%1"=="inc" set _INC=1 -@if /i "%1"=="clean" set _CLEAN=1 -@if not "%1"=="" shift & goto parse_args - -@set _B=%~dp0..\..\..\build\UI.wixext\%_C% - -:: Clean - -@if "%_INC%"=="" call :clean -@if NOT "%_CLEAN%"=="" goto :end - -@echo UI.wixext build %_C% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror -bl:%_L%\ext_ui_build.binlog || exit /b - -:: Test -dotnet test -c %_C% --no-build test\WixToolsetTest.UI || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror -p:NoBuild=true wixext\WixToolset.UI.wixext.csproj || exit /b - -@goto :end - -:clean -@rd /s/q "..\..\..\build\UI.wixext" 2> nul -@del "..\..\..\build\artifacts\WixToolset.UI.wixext.*.nupkg" 2> nul -@del "%_L%\ext_ui_build.binlog" 2> nul -@rd /s/q "%USERPROFILE%\.nuget\packages\wixtoolset.ui.wixext" 2> nul -@exit /b - -:end -@popd -@endlocal diff --git a/src/ext/UI/ui_t.proj b/src/ext/UI/ui_t.proj new file mode 100644 index 00000000..0a989b6f --- /dev/null +++ b/src/ext/UI/ui_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs index 13c39091..03d87e4e 100644 --- a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs +++ b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs @@ -2,19 +2,20 @@ namespace WixToolsetTest.Util { + using System; using System.IO; using System.Linq; using System.Xml; - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; - using WixToolset.Util; - using Xunit; using System.Xml.Linq; - using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; + using WixToolset.Util; + [TestClass] public class UtilExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingFileShare() { var folder = TestData.Get(@"TestData\UsingFileShare"); @@ -35,7 +36,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildUsingFileShareX64() { var folder = TestData.Get(@"TestData\UsingFileShare"); @@ -56,7 +57,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanRoundtripFileShare() { var folder = TestData.Get(@"TestData", "UsingFileShare"); @@ -79,7 +80,7 @@ namespace WixToolsetTest.Util }, utilElementNames); } - [Fact] + [TestMethod] public void CanBuildCloseApplication() { var folder = TestData.Get(@"TestData\CloseApplication"); @@ -96,7 +97,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildInternetShortcutInProduct() { var folder = TestData.Get(@"TestData\InternetShortcut"); @@ -116,7 +117,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildInternetShortcutInMergeModule() { var folder = TestData.Get(@"TestData\InternetShortcutModule"); @@ -136,7 +137,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildWithPermissionEx() { var folder = TestData.Get(@"TestData\PermissionEx"); @@ -153,7 +154,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildRemoveRegistryKeyExInMergeModule() { var folder = TestData.Get(@"TestData", "RemoveRegistryKeyEx"); @@ -168,7 +169,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildRemoveFolderExInMergeModule() { var folder = TestData.Get(@"TestData\RemoveFolderEx"); @@ -183,7 +184,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildRemoveFolderExInPackage() { var folder = TestData.Get(@"TestData\RemoveFolderExPackage"); @@ -198,7 +199,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildServiceConfig() { var folder = TestData.Get(@"TestData", "ServiceConfig"); @@ -215,7 +216,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildWithEventManifest() { var folder = TestData.Get(@"TestData\EventManifest"); @@ -240,7 +241,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildWithQueries() { var folder = TestData.Get(@"TestData\Queries"); @@ -259,7 +260,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildAndDecompiileQueries() { var folder = TestData.Get(@"TestData\Queries"); @@ -285,7 +286,7 @@ namespace WixToolsetTest.Util }, utilElementNames); } - [Fact] + [TestMethod] public void CanBuildWithXmlConfig() { var folder = TestData.Get(@"TestData", "XmlConfig"); @@ -301,7 +302,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanRoundtripXmlConfig() { var folder = TestData.Get(@"TestData", "XmlConfig"); @@ -324,7 +325,7 @@ namespace WixToolsetTest.Util }, utilElementNames); } - [Fact] + [TestMethod] public void CanBuildModuleWithXmlConfig() { var folder = TestData.Get(@"TestData", "XmlConfigModule"); @@ -338,7 +339,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanBuildBundleWithSearches() { var folder = TestData.Get(@"TestData\BundleWithSearches"); @@ -366,15 +367,15 @@ namespace WixToolsetTest.Util result.AssertSuccess(); - Assert.True(File.Exists(bundlePath)); - Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); + Assert.IsTrue(File.Exists(bundlePath)); + Assert.IsTrue(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); var bootstrapperExtensionDatas = extractResult.SelectBootstrapperExtensionDataNodes("/be:BootstrapperExtensionData/be:BootstrapperExtension[@Id='Wix4UtilBootstrapperExtension_X86']"); - Assert.Equal(1, bootstrapperExtensionDatas.Count); - Assert.Equal("" + + Assert.AreEqual(1, bootstrapperExtensionDatas.Count); + Assert.AreEqual("" + "" + "", bootstrapperExtensionDatas[0].GetTestXml()); @@ -394,7 +395,7 @@ namespace WixToolsetTest.Util } } - [Fact] + [TestMethod] public void CanCreateUserGroupWithComment() { var folder = TestData.Get(@"TestData\CreateGroup"); @@ -550,7 +551,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CanCreateUserAccountWithComment() { var folder = TestData.Get(@"TestData\CreateUser"); @@ -626,7 +627,7 @@ namespace WixToolsetTest.Util }, results.OrderBy(s => s).ToArray()); } - [Fact] + [TestMethod] public void CannotBuildBundleWithSearchesUsingBuiltinVariableNames() { var folder = TestData.Get("TestData", "BundleWithSearches"); diff --git a/src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj b/src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj index 16d0e138..4036c3ab 100644 --- a/src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj +++ b/src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -16,6 +16,7 @@ - + + diff --git a/src/ext/Util/util.cmd b/src/ext/Util/util.cmd deleted file mode 100644 index 3c66e7d8..00000000 --- a/src/ext/Util/util.cmd +++ /dev/null @@ -1,45 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -@set _L=%~dp0..\..\..\build\logs - -:parse_args -@if /i "%1"=="release" set _C=Release -@if /i "%1"=="inc" set _INC=1 -@if /i "%1"=="clean" set _CLEAN=1 -@if not "%1"=="" shift & goto parse_args - -@set _B=%~dp0..\..\..\build\Util.wixext\%_C% - -:: Clean - -@if "%_INC%"=="" call :clean -@if NOT "%_CLEAN%"=="" goto :end - -@echo Building ext\Util %_C% using %_N% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror -bl:%_L%\ext_util_build.binlog || exit /b - -:: Test -dotnet test ^ - %_B%\net6.0\WixToolsetTest.Util.dll ^ - --nologo -l "trx;LogFileName=%_L%\TestResults\util.wixext.trx" || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror -p:NoBuild=true wixext\WixToolset.Util.wixext.csproj || exit /b - -@goto :end - -:clean -@rd /s/q "..\..\build\Util.wixext" 2> nul -@del "..\..\build\artifacts\WixToolset.Util.wixext.*.nupkg" 2> nul -@del "%_L%\ext_util_build.binlog" 2> nul -@del "%_L%\TestResults\util.wixext.trx" 2> nul -@rd /s/q "%USERPROFILE%\.nuget\packages\wixtoolset.util.wixext" 2> nul -@exit /b - -:end -@popd -@endlocal diff --git a/src/ext/Util/util_t.proj b/src/ext/Util/util_t.proj new file mode 100644 index 00000000..e1da6adf --- /dev/null +++ b/src/ext/Util/util_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/VisualStudio/test/WixToolsetTest.VisualStudio/VisualStudioExtensionFixture.cs b/src/ext/VisualStudio/test/WixToolsetTest.VisualStudio/VisualStudioExtensionFixture.cs index f3e81e2d..992ac953 100644 --- a/src/ext/VisualStudio/test/WixToolsetTest.VisualStudio/VisualStudioExtensionFixture.cs +++ b/src/ext/VisualStudio/test/WixToolsetTest.VisualStudio/VisualStudioExtensionFixture.cs @@ -2,15 +2,16 @@ namespace WixToolsetTest.VisualStudio { - using WixInternal.TestSupport; - using WixInternal.Core.TestPackage; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using WixInternal.MSTestSupport; + using WixInternal.Core.MSTestPackage; using WixToolset.VisualStudio; - using Xunit; using System.Linq; + [TestClass] public class VisualStudioExtensionFixture { - [Fact] + [TestMethod] public void CanBuildUsingVsixPackage() { var folder = TestData.Get(@"TestData\UsingVsixPackage"); @@ -36,7 +37,7 @@ namespace WixToolsetTest.VisualStudio }, results); } - [Fact] + [TestMethod] public void CanBuildUsingVsixPackageOnArm64() { var folder = TestData.Get(@"TestData\UsingVsixPackage"); diff --git a/src/ext/VisualStudio/test/WixToolsetTest.VisualStudio/WixToolsetTest.VisualStudio.csproj b/src/ext/VisualStudio/test/WixToolsetTest.VisualStudio/WixToolsetTest.VisualStudio.csproj index 2b0a7c1c..9cfb6867 100644 --- a/src/ext/VisualStudio/test/WixToolsetTest.VisualStudio/WixToolsetTest.VisualStudio.csproj +++ b/src/ext/VisualStudio/test/WixToolsetTest.VisualStudio/WixToolsetTest.VisualStudio.csproj @@ -1,10 +1,10 @@ - + net6.0 - true + true @@ -16,6 +16,7 @@ - + + diff --git a/src/ext/VisualStudio/visualstudio_t.proj b/src/ext/VisualStudio/visualstudio_t.proj new file mode 100644 index 00000000..52de8019 --- /dev/null +++ b/src/ext/VisualStudio/visualstudio_t.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/ext/VisualStudio/vs.cmd b/src/ext/VisualStudio/vs.cmd deleted file mode 100644 index f0873f1d..00000000 --- a/src/ext/VisualStudio/vs.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@setlocal -@pushd %~dp0 - -@set _C=Debug -:parse_args -@if /i "%1"=="release" set _C=Release -@if not "%1"=="" shift & goto parse_args - -@echo VisualStudio.wixext build %_C% - -:: Build -msbuild -Restore -p:Configuration=%_C% -tl -nologo -warnaserror || exit /b - -:: Test -dotnet test -c %_C% --no-build test\WixToolsetTest.VisualStudio || exit /b - -:: Pack -msbuild -t:Pack -p:Configuration=%_C% -tl -nologo -warnaserror -p:NoBuild=true wixext\WixToolset.VisualStudio.wixext.csproj || exit /b - -@popd -@endlocal diff --git a/src/ext/ext.cmd b/src/ext/ext.cmd index 8575b81e..86aac47b 100644 --- a/src/ext/ext.cmd +++ b/src/ext/ext.cmd @@ -2,58 +2,15 @@ @pushd %~dp0 @set _C=Debug +@set _L=%~dp0..\..\build\logs +@set _SuppressWixClean=false + :parse_args @if /i "%1"=="release" set _C=Release +@if /i "%1"=="inc" set _SuppressWixClean=true @if not "%1"=="" shift & goto parse_args -@echo ext build %_C% - -:: These extensions must be built in this order. - -:: Util -call Util\util.cmd %_C% || exit /b - -:: Bal -call Bal\bal.cmd %_C% || exit /b - -:: NetFx -call NetFx\netfx.cmd %_C% || exit /b - - -:: The rest of the extensions are in alphabetical order. - -:: ComPlus -call ComPlus\complus.cmd %_C% || exit /b - -:: Dependency -call Dependency\dependency.cmd %_C% || exit /b - -:: DirectX -call DirectX\directx.cmd %_C% || exit /b - -:: Firewall -call Firewall\firewall.cmd %_C% || exit /b - -:: Http -call Http\http.cmd %_C% || exit /b - -:: Iis -call Iis\iis.cmd %_C% || exit /b - -:: Msmq -call Msmq\msmq.cmd %_C% || exit /b - -:: PowerShell -call PowerShell\ps.cmd %_C% || exit /b - -:: Sql -call Sql\sql.cmd %_C% || exit /b - -:: UI -call UI\ui.cmd %_C% || exit /b - -:: VisualStudio -call VisualStudio\vs.cmd %_C% || exit /b +msbuild ext_t.proj -p:Configuration=%_C% -p:SuppressWixClean=%_SuppressWixClean% -m -tl -nologo -warnaserror -bl:%_L%\ext_build.binlog || exit /b @popd @endlocal diff --git a/src/ext/ext_t.proj b/src/ext/ext_t.proj new file mode 100644 index 00000000..e3301172 --- /dev/null +++ b/src/ext/ext_t.proj @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/internal/SetBuildNumber/Directory.Packages.props.pp b/src/internal/SetBuildNumber/Directory.Packages.props.pp index 8cf271d7..18a9b5eb 100644 --- a/src/internal/SetBuildNumber/Directory.Packages.props.pp +++ b/src/internal/SetBuildNumber/Directory.Packages.props.pp @@ -17,6 +17,7 @@ + @@ -37,6 +38,7 @@ + @@ -97,6 +99,10 @@ + + + + diff --git a/src/internal/SetBuildNumber/global.json.pp b/src/internal/SetBuildNumber/global.json.pp index bad3c0bd..fe48e6cc 100644 --- a/src/internal/SetBuildNumber/global.json.pp +++ b/src/internal/SetBuildNumber/global.json.pp @@ -1,6 +1,7 @@ { "msbuild-sdks": { - "Microsoft.Build.Traversal": "3.2.0", + "MSTest.Sdk": "3.8.0", + "Microsoft.Build.Traversal": "4.1.82", "Microsoft.Build.NoTargets": "3.5.6", "WixToolset.Sdk": "{packageversion}" }, diff --git a/src/internal/WixInternal.MSTestSupport/Builder.cs b/src/internal/WixInternal.MSTestSupport/Builder.cs new file mode 100644 index 00000000..62f2891b --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/Builder.cs @@ -0,0 +1,204 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.Collections.Generic; + using System.IO; + + public class Builder + { + public Builder(string sourceFolder, Type extensionType = null, string[] bindPaths = null, string outputFile = null) + { + this.SourceFolder = sourceFolder; + if (extensionType != null) + { + this.ExtensionTypes = new Type[] { extensionType }; + } + else + { + this.ExtensionTypes = new Type[] { }; + } + this.BindPaths = bindPaths; + this.OutputFile = outputFile ?? "test.msi"; + } + + public Builder(string sourceFolder, Type[] extensionTypes, string[] bindPaths = null, string outputFile = null) + { + this.SourceFolder = sourceFolder; + this.ExtensionTypes = extensionTypes; + this.BindPaths = bindPaths; + this.OutputFile = outputFile ?? "test.msi"; + } + + public string[] BindPaths { get; set; } + + public Type[] ExtensionTypes { get; set; } + + public string OutputFile { get; set; } + + public string SourceFolder { get; } + + public string[] BuildAndQuery(Action buildFunc, params string[] tables) + { + return this.BuildAndQuery(buildFunc, validate: false, tables); + } + + public string[] BuildAndQuery(Action buildFunc, bool validate, params string[] tables) + { + var sourceFiles = Directory.GetFiles(this.SourceFolder, "*.wxs"); + var wxlFiles = Directory.GetFiles(this.SourceFolder, "*.wxl"); + + using (var fs = new DisposableFileSystem()) + { + var intermediateFolder = fs.GetFolder(); + var outputPath = Path.Combine(intermediateFolder, "bin", this.OutputFile); + + var args = new List + { + "build", + "-o", outputPath, + "-intermediateFolder", intermediateFolder, + }; + + foreach (var ext in this.ExtensionTypes) + { + args.Add("-ext"); + args.Add(Path.GetFullPath(ext.Assembly.Location)); + } + + args.AddRange(sourceFiles); + + foreach (var wxlFile in wxlFiles) + { + args.Add("-loc"); + args.Add(wxlFile); + } + + foreach (var bindPath in this.BindPaths) + { + args.Add("-bindpath"); + args.Add(bindPath); + } + + buildFunc(args.ToArray()); + + if (validate) + { + args = new List + { + "msi", + "validate", + "-intermediateFolder", intermediateFolder, + outputPath, + }; + + buildFunc(args.ToArray()); + } + + return Query.QueryDatabase(outputPath, tables); + } + } + + public void BuildAndDecompileAndBuild(Action buildFunc, Action decompileFunc, string decompilePath, bool validate = false) + { + var sourceFiles = Directory.GetFiles(this.SourceFolder, "*.wxs"); + var wxlFiles = Directory.GetFiles(this.SourceFolder, "*.wxl"); + + using (var fs = new DisposableFileSystem()) + { + var intermediateFolder = fs.GetFolder(); + var outputFolder = Path.Combine(intermediateFolder, "bin"); + var decompileExtractFolder = Path.Combine(intermediateFolder, "decompiled", "extract"); + var decompileIntermediateFolder = Path.Combine(intermediateFolder, "decompiled", "obj"); + var decompileBuildFolder = Path.Combine(intermediateFolder, "decompiled", "bin"); + var outputPath = Path.Combine(outputFolder, this.OutputFile); + var decompileBuildPath = Path.Combine(decompileBuildFolder, this.OutputFile); + + // First build. + var firstBuildArgs = new List + { + "build", + "-o", outputPath, + "-intermediateFolder", intermediateFolder, + }; + + foreach (var ext in this.ExtensionTypes) + { + firstBuildArgs.Add("-ext"); + firstBuildArgs.Add(Path.GetFullPath(ext.Assembly.Location)); + } + + firstBuildArgs.AddRange(sourceFiles); + + foreach (var wxlFile in wxlFiles) + { + firstBuildArgs.Add("-loc"); + firstBuildArgs.Add(wxlFile); + } + + foreach (var bindPath in this.BindPaths) + { + firstBuildArgs.Add("-bindpath"); + firstBuildArgs.Add(bindPath); + } + + buildFunc(firstBuildArgs.ToArray()); + + if (validate) + { + firstBuildArgs = new List + { + "msi", + "validate", + "-intermediateFolder", intermediateFolder, + outputPath, + }; + + buildFunc(firstBuildArgs.ToArray()); + } + + // Decompile built output. + var decompileArgs = new List + { + "msi", "decompile", + outputPath, + "-intermediateFolder", decompileIntermediateFolder, + "-x", decompileExtractFolder, + "-o", decompilePath + }; + + foreach (var ext in this.ExtensionTypes) + { + decompileArgs.Add("-ext"); + decompileArgs.Add(Path.GetFullPath(ext.Assembly.Location)); + } + + decompileFunc(decompileArgs.ToArray()); + + // Build decompiled output. + var secondBuildArgs = new List + { + "build", + decompilePath, + "-o", decompileBuildPath, + "-intermediateFolder", decompileIntermediateFolder + }; + + foreach (var ext in this.ExtensionTypes) + { + secondBuildArgs.Add("-ext"); + secondBuildArgs.Add(Path.GetFullPath(ext.Assembly.Location)); + } + + secondBuildArgs.Add("-bindpath"); + secondBuildArgs.Add(outputFolder); + + secondBuildArgs.Add("-bindpath"); + secondBuildArgs.Add(decompileExtractFolder); + + buildFunc(secondBuildArgs.ToArray()); + } + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/DisposableFileSystem.cs b/src/internal/WixInternal.MSTestSupport/DisposableFileSystem.cs new file mode 100644 index 00000000..5e4bb23f --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/DisposableFileSystem.cs @@ -0,0 +1,94 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.Collections.Generic; + using System.IO; + + public class DisposableFileSystem : IDisposable + { + protected bool Disposed { get; private set; } + + private List CleanupPaths { get; } = new List(); + + public bool Keep { get; } + + public DisposableFileSystem(bool keep = false) + { + this.Keep = keep; + } + + protected string GetFile(bool create = false) + { + var path = Path.GetTempFileName(); + + if (!create) + { + File.Delete(path); + } + + this.CleanupPaths.Add(path); + + return path; + } + + public string GetFolder(bool create = false) + { + // Always return a path with a space in it. + var path = Path.Combine(Path.GetTempPath(), ".WIXTEST " + Path.GetRandomFileName()); + + if (create) + { + Directory.CreateDirectory(path); + } + + this.CleanupPaths.Add(path); + + return path; + } + + + #region // IDisposable + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (this.Disposed) + { + return; + } + + if (disposing && !this.Keep) + { + foreach (var path in this.CleanupPaths) + { + try + { + if (File.Exists(path)) + { + File.Delete(path); + } + else if (Directory.Exists(path)) + { + Directory.Delete(path, true); + } + } + catch + { + // Best effort delete, so ignore any failures. + } + } + } + + this.Disposed = true; + } + + #endregion + } +} diff --git a/src/internal/WixInternal.MSTestSupport/DotnetRunner.cs b/src/internal/WixInternal.MSTestSupport/DotnetRunner.cs new file mode 100644 index 00000000..8fa3a739 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/DotnetRunner.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.Collections.Generic; + using System.IO; + + public class DotnetRunner : ExternalExecutable + { + private static readonly object InitLock = new object(); + private static bool Initialized; + private static DotnetRunner Instance; + + public static ExternalExecutableResult Execute(string command, string[] arguments = null) => + InitAndExecute(command, arguments); + + private static ExternalExecutableResult InitAndExecute(string command, string[] arguments) + { + lock (InitLock) + { + if (!Initialized) + { + Initialized = true; + var dotnetPath = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH"); + if (String.IsNullOrEmpty(dotnetPath) || !File.Exists(dotnetPath)) + { + dotnetPath = "dotnet"; + } + + Instance = new DotnetRunner(dotnetPath); + } + } + + return Instance.ExecuteCore(command, arguments); + } + + private DotnetRunner(string exePath) : base(exePath) { } + + private ExternalExecutableResult ExecuteCore(string command, string[] arguments) + { + var total = new List + { + command, + }; + + if (arguments != null) + { + total.AddRange(arguments); + } + + var args = CombineArguments(total); + var mergeErrorIntoOutput = true; + return this.Run(args, mergeErrorIntoOutput); + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/ExternalExecutable.cs b/src/internal/WixInternal.MSTestSupport/ExternalExecutable.cs new file mode 100644 index 00000000..927240ec --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/ExternalExecutable.cs @@ -0,0 +1,374 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics; + using System.IO; + using System.Runtime.InteropServices; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Win32.SafeHandles; + + public abstract class ExternalExecutable + { + private readonly string exePath; + + protected ExternalExecutable(string exePath) + { + this.exePath = exePath; + } + + protected ExternalExecutableResult Run(string args, bool mergeErrorIntoOutput = false, string workingDirectory = null) + { + // https://github.com/dotnet/runtime/issues/58492 + // Process.Start doesn't currently support starting a process with a long path, + // but the way to support long paths doesn't support searching for the executable if it was a relative path. + // Avoid the managed way of doing this even if the target isn't a long path to help verify that the native way works. + if (!Path.IsPathRooted(this.exePath)) + { + return this.RunManaged(args, mergeErrorIntoOutput, workingDirectory); + } + + // https://web.archive.org/web/20150331190801/https://support.microsoft.com/en-us/kb/190351 + var commandLine = $"\"{this.exePath}\" {args}"; + var currentDirectory = workingDirectory ?? Path.GetDirectoryName(this.exePath); + if (String.IsNullOrEmpty(currentDirectory)) + { + currentDirectory = null; + } + var processInfo = new PROCESS_INFORMATION(); + var startInfo = new STARTUPINFOW + { + cb = Marshal.SizeOf(typeof(STARTUPINFOW)), + dwFlags = StartupInfoFlags.STARTF_FORCEOFFFEEDBACK | StartupInfoFlags.STARTF_USESTDHANDLES, + hStdInput = GetStdHandle(StdHandleType.STD_INPUT_HANDLE), + }; + SafeFileHandle hStdOutputParent = null; + SafeFileHandle hStdErrorParent = null; + + try + { + CreatePipeForProcess(out hStdOutputParent, out startInfo.hStdOutput); + + if (!mergeErrorIntoOutput) + { + CreatePipeForProcess(out hStdErrorParent, out startInfo.hStdError); + } + else + { + if (!DuplicateHandle(GetCurrentProcess(), startInfo.hStdOutput, GetCurrentProcess(), out startInfo.hStdError, 0, true, DuplicateHandleOptions.DUPLICATE_SAME_ACCESS)) + { + throw new Win32Exception(); + } + } + + if (!CreateProcessW(this.exePath, commandLine, IntPtr.Zero, IntPtr.Zero, true, CreateProcessFlags.CREATE_NO_WINDOW, IntPtr.Zero, + currentDirectory, ref startInfo, ref processInfo)) + { + throw new Win32Exception(); + } + + startInfo.Dispose(); + + return GetResultFromNative(mergeErrorIntoOutput, hStdOutputParent, hStdErrorParent, processInfo.hProcess, this.exePath, args); + } + finally + { + hStdErrorParent?.Dispose(); + hStdOutputParent?.Dispose(); + + startInfo.Dispose(); + processInfo.Dispose(); + } + } + + private static ExternalExecutableResult GetResultFromNative(bool mergeErrorIntoOutput, SafeFileHandle hStdOutputParent, SafeFileHandle hStdErrorParent, IntPtr hProcess, string fileName, string args) + { + using (var outputStream = new StreamReader(new FileStream(hStdOutputParent, FileAccess.Read))) + using (var errorStream = mergeErrorIntoOutput ? null : new StreamReader(new FileStream(hStdErrorParent, FileAccess.Read))) + { + var outputTask = Task.Run(() => ReadProcessStreamLines(outputStream)); + var errorTask = Task.Run(() => ReadProcessStreamLines(errorStream)); + + while (!outputTask.Wait(100) || !errorTask.Wait(100)) { Task.Yield(); } + var standardOutput = outputTask.Result; + var standardError = errorTask.Result; + + if (WaitForSingleObject(hProcess, -1) != 0) + { + throw new Win32Exception(); + } + + if (!GetExitCodeProcess(hProcess, out var exitCode)) + { + throw new Win32Exception(); + } + + return new ExternalExecutableResult + { + ExitCode = exitCode, + StandardError = standardError, + StandardOutput = standardOutput, + FileName = fileName, + Arguments = args, + }; + } + } + + private static string[] ReadProcessStreamLines(StreamReader streamReader) + { + if (streamReader == null) + { + return null; + } + + var lines = new List(); + while (true) + { + var line = streamReader.ReadLine(); + if (line == null) + { + break; + } + + lines.Add(line); + } + + return lines.ToArray(); + } + + protected ExternalExecutableResult RunManaged(string args, bool mergeErrorIntoOutput = false, string workingDirectory = null) + { + var startInfo = new ProcessStartInfo(this.exePath, args) + { + CreateNoWindow = true, + RedirectStandardError = true, + RedirectStandardOutput = true, + UseShellExecute = false, + WorkingDirectory = workingDirectory ?? Path.GetDirectoryName(this.exePath), + }; + + using (var process = Process.Start(startInfo)) + { + // This implementation of merging the streams does not guarantee that lines are retrieved in the same order that they were written. + // If the process is simultaneously writing to both streams, this is impossible to do anyway. + var standardOutput = new ConcurrentQueue(); + var standardError = mergeErrorIntoOutput ? standardOutput : new ConcurrentQueue(); + + process.ErrorDataReceived += (s, e) => { if (e.Data != null) { standardError.Enqueue(e.Data); } }; + process.OutputDataReceived += (s, e) => { if (e.Data != null) { standardOutput.Enqueue(e.Data); } }; + + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + + process.WaitForExit(); + + return new ExternalExecutableResult + { + ExitCode = process.ExitCode, + StandardError = mergeErrorIntoOutput ? null : standardError.ToArray(), + StandardOutput = standardOutput.ToArray(), + FileName = this.exePath, + Arguments = args, + }; + } + } + + // This is internal because it assumes backslashes aren't used as escape characters and there aren't any double quotes. + internal static string CombineArguments(IEnumerable arguments) + { + if (arguments == null) + { + return null; + } + + var sb = new StringBuilder(); + + foreach (var arg in arguments) + { + if (sb.Length > 0) + { + sb.Append(' '); + } + + if (arg.IndexOf(' ') > -1 && !arg.EndsWith("\"")) + { + sb.Append("\""); + sb.Append(arg); + sb.Append("\""); + } + else + { + sb.Append(arg); + } + } + + return sb.ToString(); + } + + private static void CreatePipeForProcess(out SafeFileHandle hReadPipe, out IntPtr hWritePipe) + { + var securityAttributes = new SECURITY_ATTRIBUTES + { + nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES)), + bInheritHandle = true, + }; + + if (!CreatePipe(out var hReadTemp, out hWritePipe, ref securityAttributes, 0)) + { + throw new Win32Exception(); + } + + // Only the handle passed to the process should be inheritable, so have to duplicate the other handle to get an uninheritable one. + if (!DuplicateHandle(GetCurrentProcess(), hReadTemp, GetCurrentProcess(), out var hReadPipePtr, 0, false, DuplicateHandleOptions.DUPLICATE_CLOSE_SOURCE | DuplicateHandleOptions.DUPLICATE_SAME_ACCESS)) + { + throw new Win32Exception(); + } + + hReadPipe = new SafeFileHandle(hReadPipePtr, true); + } + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + private extern static IntPtr GetStdHandle(StdHandleType nStdHandle); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private extern static bool CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe, ref SECURITY_ATTRIBUTES lpPipeAttributes, int nSize); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private extern static bool CreateProcessW( + string lpApplicationName, + string lpCommandLine, + IntPtr lpProcessAttributes, + IntPtr lpThreadAttributes, + [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles, + CreateProcessFlags dwCreationFlags, + IntPtr lpEnvironment, + string lpCurrentDirectory, + ref STARTUPINFOW lpStartupInfo, + ref PROCESS_INFORMATION lpProcessInformation); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] + private extern static IntPtr GetCurrentProcess(); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private extern static bool GetExitCodeProcess(IntPtr hHandle, out int lpExitCode); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + private extern static int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private extern static bool CloseHandle(IntPtr hObject); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private extern static bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, DuplicateHandleOptions dwOptions); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct SECURITY_ATTRIBUTES + { + public int nLength; + public IntPtr lpSecurityDescriptor; + [MarshalAs(UnmanagedType.Bool)] + public bool bInheritHandle; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct STARTUPINFOW + { + public int cb; + public string lpReserved; + public string lpDesktop; + public string lpTitle; + public int dwX; + public int dwY; + public int dwXSize; + public int dwYSize; + public int dwXCountChars; + public int dwYCountChars; + public int dwFillAttribute; + public StartupInfoFlags dwFlags; + public short wShowWindow; + public short cbReserved2; + public IntPtr lpReserved2; + public IntPtr hStdInput; + public IntPtr hStdOutput; + public IntPtr hStdError; + + public void Dispose() + { + // This makes assumptions based on how it's used above. + if (this.hStdError != IntPtr.Zero) + { + CloseHandle(this.hStdError); + this.hStdError = IntPtr.Zero; + } + + if (this.hStdOutput != IntPtr.Zero) + { + CloseHandle(this.hStdOutput); + this.hStdOutput = IntPtr.Zero; + } + } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct PROCESS_INFORMATION + { + public IntPtr hProcess; + public IntPtr hThread; + public int dwProcessId; + public int dwThreadId; + + public void Dispose() + { + if (this.hProcess != IntPtr.Zero) + { + CloseHandle(this.hProcess); + this.hProcess = IntPtr.Zero; + } + + if (this.hThread != IntPtr.Zero) + { + CloseHandle(this.hThread); + this.hThread = IntPtr.Zero; + } + } + } + + private enum StdHandleType + { + STD_INPUT_HANDLE = -10, + STD_OUTPUT_HANDLE = -11, + STD_ERROR_HANDLE = -12, + } + + [Flags] + private enum CreateProcessFlags + { + None = 0x0, + CREATE_NO_WINDOW = 0x08000000, + } + + [Flags] + private enum StartupInfoFlags + { + None = 0x0, + STARTF_FORCEOFFFEEDBACK = 0x80, + STARTF_USESTDHANDLES = 0x100, + } + + private enum DuplicateHandleOptions + { + DUPLICATE_CLOSE_SOURCE = 1, + DUPLICATE_SAME_ACCESS = 2, + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/ExternalExecutableResult.cs b/src/internal/WixInternal.MSTestSupport/ExternalExecutableResult.cs new file mode 100644 index 00000000..57bf0d11 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/ExternalExecutableResult.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System.Diagnostics; + + public class ExternalExecutableResult + { + public int ExitCode { get; set; } + + public string[] StandardError { get; set; } + + public string[] StandardOutput { get; set; } + + public string FileName { get; set; } + + public string Arguments { get; set; } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/FakeBuildEngine.cs b/src/internal/WixInternal.MSTestSupport/FakeBuildEngine.cs new file mode 100644 index 00000000..951d1bc8 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/FakeBuildEngine.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System.Collections; + using System.Text; + using Microsoft.Build.Framework; + + public class FakeBuildEngine : IBuildEngine + { + private readonly StringBuilder output = new StringBuilder(); + + public int ColumnNumberOfTaskNode => 0; + + public bool ContinueOnError => false; + + public int LineNumberOfTaskNode => 0; + + public string ProjectFileOfTaskNode => "fake_wix.targets"; + + public string Output => this.output.ToString(); + + public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs) => throw new System.NotImplementedException(); + + public void LogCustomEvent(CustomBuildEventArgs e) => this.output.AppendLine(e.Message); + + public void LogErrorEvent(BuildErrorEventArgs e) => this.output.AppendLine(e.Message); + + public void LogMessageEvent(BuildMessageEventArgs e) => this.output.AppendLine(e.Message); + + public void LogWarningEvent(BuildWarningEventArgs e) => this.output.AppendLine(e.Message); + } +} diff --git a/src/internal/WixInternal.MSTestSupport/MsbuildRunner.cs b/src/internal/WixInternal.MSTestSupport/MsbuildRunner.cs new file mode 100644 index 00000000..69fc7292 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/MsbuildRunner.cs @@ -0,0 +1,112 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.Collections.Generic; + using System.IO; + + public class MsbuildRunner : ExternalExecutable + { + private static readonly string VswhereFindArguments = "-property installationPath -version [17.0,18.0)"; + private static readonly string MsbuildCurrentRelativePath = @"MSBuild\Current\Bin\MSBuild.exe"; + private static readonly string MsbuildCurrentRelativePath64 = @"MSBuild\Current\Bin\amd64\MSBuild.exe"; + + private static readonly object InitLock = new object(); + + private static bool Initialized; + private static MsbuildRunner MsbuildCurrentRunner; + private static MsbuildRunner MsbuildCurrentRunner64; + + public static MsbuildRunnerResult Execute(string projectPath, string[] arguments = null, bool x64 = false) => + InitAndExecute(String.Empty, projectPath, arguments, x64); + + public static MsbuildRunnerResult ExecuteWithMsbuildCurrent(string projectPath, string[] arguments = null, bool x64 = false) => + InitAndExecute("Current", projectPath, arguments, x64); + + private static MsbuildRunnerResult InitAndExecute(string msbuildVersion, string projectPath, string[] arguments, bool x64) + { + lock (InitLock) + { + if (!Initialized) + { + Initialized = true; + var vswhereResult = VswhereRunner.Execute(VswhereFindArguments, true); + if (vswhereResult.ExitCode != 0) + { + throw new InvalidOperationException($"Failed to execute vswhere.exe, exit code: {vswhereResult.ExitCode}. Output:\r\n{String.Join("\r\n", vswhereResult.StandardOutput)}"); + } + + string msbuildCurrentPath = null; + string msbuildCurrentPath64 = null; + + foreach (var installPath in vswhereResult.StandardOutput) + { + if (msbuildCurrentPath == null) + { + var path = Path.Combine(installPath, MsbuildCurrentRelativePath); + if (File.Exists(path)) + { + msbuildCurrentPath = path; + } + } + + if (msbuildCurrentPath64 == null) + { + var path = Path.Combine(installPath, MsbuildCurrentRelativePath64); + if (File.Exists(path)) + { + msbuildCurrentPath64 = path; + } + } + } + + if (msbuildCurrentPath != null) + { + MsbuildCurrentRunner = new MsbuildRunner(msbuildCurrentPath); + } + + if (msbuildCurrentPath64 != null) + { + MsbuildCurrentRunner64 = new MsbuildRunner(msbuildCurrentPath64); + } + } + } + + MsbuildRunner runner = x64 ? MsbuildCurrentRunner64 : MsbuildCurrentRunner; + + if (runner == null) + { + throw new InvalidOperationException($"Failed to find an installed{(x64 ? " 64-bit" : String.Empty)} MSBuild{msbuildVersion}"); + } + + return runner.ExecuteCore(projectPath, arguments); + } + + private MsbuildRunner(string exePath) : base(exePath) { } + + private MsbuildRunnerResult ExecuteCore(string projectPath, string[] arguments) + { + var total = new List + { + projectPath, + }; + + if (arguments != null) + { + total.AddRange(arguments); + } + + var args = CombineArguments(total); + var mergeErrorIntoOutput = true; + var workingFolder = Path.GetDirectoryName(projectPath); + var result = this.Run(args, mergeErrorIntoOutput, workingFolder); + + return new MsbuildRunnerResult + { + ExitCode = result.ExitCode, + Output = result.StandardOutput, + }; + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/MsbuildRunnerResult.cs b/src/internal/WixInternal.MSTestSupport/MsbuildRunnerResult.cs new file mode 100644 index 00000000..02e25ebb --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/MsbuildRunnerResult.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public class MsbuildRunnerResult + { + public int ExitCode { get; set; } + + public string[] Output { get; set; } + + public void AssertSuccess() + { + Assert.IsTrue(0 == this.ExitCode, $"MSBuild failed unexpectedly. Output:{Environment.NewLine}{String.Join(Environment.NewLine, this.Output)}"); + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/MsbuildUtilities.cs b/src/internal/WixInternal.MSTestSupport/MsbuildUtilities.cs new file mode 100644 index 00000000..4776e6f1 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/MsbuildUtilities.cs @@ -0,0 +1,99 @@ +// Copyright(c) .NET Foundation and contributors.All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + + public enum BuildSystem + { + DotNetCoreSdk, + MSBuild, + MSBuild64, + } + + public static class MsbuildUtilities + { + public static MsbuildRunnerResult BuildProject(BuildSystem buildSystem, string projectPath, string[] arguments = null, string configuration = "Release", string verbosityLevel = "normal", bool suppressValidation = true) + { + var allArgs = new List + { + $"-verbosity:{verbosityLevel}", + $"-p:Configuration={configuration}", + $"-p:SuppressValidation={suppressValidation}", + // Node reuse means that child msbuild processes can stay around after the build completes. + // Under that scenario, the root msbuild does not reliably close its streams which causes us to hang. + "-nr:false", + MsbuildUtilities.GetQuotedSwitch(buildSystem, "bl", Path.ChangeExtension(projectPath, ".binlog")) + }; + + if (arguments != null) + { + allArgs.AddRange(arguments); + } + + switch (buildSystem) + { + case BuildSystem.DotNetCoreSdk: + { + allArgs.Add(projectPath); + var result = DotnetRunner.Execute("msbuild", allArgs.ToArray()); + return new MsbuildRunnerResult + { + ExitCode = result.ExitCode, + Output = result.StandardOutput, + }; + } + case BuildSystem.MSBuild: + case BuildSystem.MSBuild64: + { + return MsbuildRunner.Execute(projectPath, allArgs.ToArray(), buildSystem == BuildSystem.MSBuild64); + } + default: + { + throw new NotImplementedException(); + } + } + } + + public static string GetQuotedSwitch(BuildSystem _, string switchName, string switchValue) + { + // If the value ends with a backslash, escape it. + if (switchValue?.EndsWith("\\") == true) + { + switchValue += @"\"; + } + + return $"-{switchName}:\"{switchValue}\""; + } + + public static string GetQuotedPropertySwitch(BuildSystem buildSystem, string propertyName, string propertyValue) + { + // If the value ends with a backslash, escape it. + if (propertyValue?.EndsWith("\\") == true) + { + propertyValue += @"\"; + } + + var quotedValue = "\"" + propertyValue + "\""; + + // If the value contains a semicolon then escape-quote it (wrap with the characters: \") to wrap the value + // instead of just quoting the value, otherwise dotnet.exe will not pass the value to MSBuild correctly. + if (buildSystem == BuildSystem.DotNetCoreSdk && propertyValue?.IndexOf(';') > -1) + { + quotedValue = "\\\"" + propertyValue + "\\\""; + } + + return $"-p:{propertyName}={quotedValue}"; + } + + public static IEnumerable GetToolCommandLines(MsbuildRunnerResult result, string toolName, string operation, BuildSystem buildSystem) + { + var expectedToolExe = buildSystem == BuildSystem.DotNetCoreSdk ? $"{toolName}.dll\"" : $"{toolName}.exe"; + var expectedToolCommand = $"{expectedToolExe} {operation}"; + return result.Output.Where(line => line.Contains(expectedToolCommand)); + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/Pushd.cs b/src/internal/WixInternal.MSTestSupport/Pushd.cs new file mode 100644 index 00000000..7086ffd0 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/Pushd.cs @@ -0,0 +1,46 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.IO; + + public class Pushd : IDisposable + { + protected bool Disposed { get; private set; } + + public Pushd(string path) + { + this.PreviousDirectory = Directory.GetCurrentDirectory(); + + Directory.SetCurrentDirectory(path); + } + + public string PreviousDirectory { get; } + + #region // IDisposable + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (this.Disposed) + { + return; + } + + if (disposing) + { + Directory.SetCurrentDirectory(this.PreviousDirectory); + } + + this.Disposed = true; + } + + #endregion + } +} diff --git a/src/internal/WixInternal.MSTestSupport/Query.cs b/src/internal/WixInternal.MSTestSupport/Query.cs new file mode 100644 index 00000000..5a8868b3 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/Query.cs @@ -0,0 +1,207 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Text; + using WixToolset.Dtf.Compression.Cab; + using WixToolset.Dtf.WindowsInstaller; + + public class Query + { + public static string[] QueryDatabase(string path, string[] tables) + { + var results = new List(); + var resultsByTable = QueryDatabaseByTable(path, tables); + var sortedTables = tables.ToList(); + sortedTables.Sort(); + foreach (var tableName in sortedTables) + { + var rows = resultsByTable[tableName]; + rows?.ForEach(r => results.Add($"{tableName}:{r}")); + } + return results.ToArray(); + } + + public static string[] QueryDatabase(Database db, string[] tables) + { + var results = new List(); + var resultsByTable = QueryDatabaseByTable(db, tables); + var sortedTables = tables.ToList(); + sortedTables.Sort(); + foreach (var tableName in sortedTables) + { + var rows = resultsByTable[tableName]; + rows?.ForEach(r => results.Add($"{tableName}:{r}")); + } + return results.ToArray(); + } + + /// + /// Returns rows from requested tables formatted to facilitate testing. + /// If the table did not exist in the database, its list will be null. + /// + /// + /// + /// + public static Dictionary> QueryDatabaseByTable(string path, string[] tables) + { + var results = new Dictionary>(); + + if (tables?.Length > 0) + { + using (var db = new Database(path)) + { + results = QueryDatabaseByTable(db, tables); + } + } + + return results; + } + + /// + /// Returns rows from requested tables formatted to facilitate testing. + /// If the table did not exist in the database, its list will be null. + /// + /// + /// + /// + public static Dictionary> QueryDatabaseByTable(Database db, string[] tables) + { + var results = new Dictionary>(); + + if (tables?.Length > 0) + { + var sb = new StringBuilder(); + + foreach (var table in tables) + { + if (table == "_SummaryInformation") + { + var entries = new List(); + results.Add(table, entries); + + entries.Add($"Title\t{db.SummaryInfo.Title}"); + entries.Add($"Subject\t{db.SummaryInfo.Subject}"); + entries.Add($"Author\t{db.SummaryInfo.Author}"); + entries.Add($"Keywords\t{db.SummaryInfo.Keywords}"); + entries.Add($"Comments\t{db.SummaryInfo.Comments}"); + entries.Add($"Template\t{db.SummaryInfo.Template}"); + entries.Add($"CodePage\t{db.SummaryInfo.CodePage}"); + entries.Add($"PageCount\t{db.SummaryInfo.PageCount}"); + entries.Add($"WordCount\t{db.SummaryInfo.WordCount}"); + entries.Add($"CharacterCount\t{db.SummaryInfo.CharacterCount}"); + entries.Add($"Security\t{db.SummaryInfo.Security}"); + + continue; + } + + if (!db.IsTablePersistent(table)) + { + results.Add(table, null); + continue; + } + + var rows = new List(); + results.Add(table, rows); + + using (var view = db.OpenView("SELECT * FROM `{0}`", table)) + { + view.Execute(); + + Record record; + while ((record = view.Fetch()) != null) + { + sb.Clear(); + + using (record) + { + for (var i = 0; i < record.FieldCount; ++i) + { + if (i > 0) + { + sb.Append("\t"); + } + + sb.Append(record[i + 1]?.ToString()); + } + } + + rows.Add(sb.ToString()); + } + } + + rows.Sort(); + } + } + + return results; + } + + public static CabFileInfo[] GetCabinetFiles(string path) + { + var cab = new CabInfo(path); + + var result = cab.GetFiles(); + + return result.Select(c => c).ToArray(); + } + + public static void ExtractStream(string path, string streamName, string outputPath) + { + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); + + using (var db = new Database(path)) + using (var view = db.OpenView("SELECT `Data` FROM `_Streams` WHERE `Name` = '{0}'", streamName)) + { + view.Execute(); + + using (var record = view.Fetch()) + { + record.GetStream(1, outputPath); + } + } + } + + public static void ExtractSubStorage(string path, string subStorageName, string outputPath) + { + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); + + using (var db = new Database(path)) + using (var view = db.OpenView("SELECT `Name`, `Data` FROM `_Storages` WHERE `Name` = '{0}'", subStorageName)) + { + view.Execute(); + + using (var record = view.Fetch()) + { + var name = record.GetString(1); + record.GetStream(2, outputPath); + } + } + } + + public static string[] GetSubStorageNames(string path) + { + var result = new List(); + + using (var db = new Database(path)) + using (var view = db.OpenView("SELECT `Name` FROM `_Storages`")) + { + view.Execute(); + + Record record; + while ((record = view.Fetch()) != null) + { + var name = record.GetString(1); + result.Add(name); + } + } + + result.Sort(); + return result.ToArray(); + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/RobocopyRunner.cs b/src/internal/WixInternal.MSTestSupport/RobocopyRunner.cs new file mode 100644 index 00000000..7ad8f6fe --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/RobocopyRunner.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + public class RobocopyRunner : ExternalExecutable + { + private static readonly RobocopyRunner Instance = new RobocopyRunner(); + + private RobocopyRunner() : base("robocopy") { } + + public static ExternalExecutableResult Execute(string args) + { + return Instance.Run(args); + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/TestData.cs b/src/internal/WixInternal.MSTestSupport/TestData.cs new file mode 100644 index 00000000..5f167a87 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/TestData.cs @@ -0,0 +1,78 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.IO; + using System.Reflection; + using System.Runtime.CompilerServices; + + public class TestData + { + public static void CreateFile(string path, long size, bool fill = false) + { + // Ensure the directory exists. + path = Path.GetFullPath(path); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + + using (var file = File.OpenWrite(path)) + { + if (fill) + { + var random = new Random(); + var bytes = new byte[4096]; + var generated = 0L; + + // Put fill bytes in the file so it doesn't compress trivially. + while (generated < size) + { + var generate = (int)Math.Min(size - generated, bytes.Length); + + random.NextBytes(bytes); + + file.Write(bytes, 0, generate); + + generated += generate; + } + } + else + { + file.SetLength(size); + } + } + } + + public static string Get(params string[] paths) + { + var localPath = AppDomain.CurrentDomain.BaseDirectory; + return Path.Combine(localPath, Path.Combine(paths)); + } + + public static string GetUnitTestLogsFolder([CallerFilePath] string path = "", [CallerMemberName] string method = "") + { + var startingPath = AppDomain.CurrentDomain.BaseDirectory; + var buildPath = startingPath; + + while (!String.IsNullOrEmpty(buildPath)) + { + var folderName = Path.GetFileName(buildPath); + if (String.Equals("build", folderName, StringComparison.OrdinalIgnoreCase)) + { + break; + } + + buildPath = Path.GetDirectoryName(buildPath); + } + + if (String.IsNullOrEmpty(buildPath)) + { + throw new InvalidOperationException($"Could not find the 'build' folder in the test path: {startingPath}. Cannot get test logs folder without being able to find the build folder."); + } + + var testLogsFolder = Path.Combine(buildPath, "logs", "UnitTests", $"{Path.GetFileNameWithoutExtension(path)}_{method}"); + Directory.CreateDirectory(testLogsFolder); + + return testLogsFolder; + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/TestDataFolderFileSystem.cs b/src/internal/WixInternal.MSTestSupport/TestDataFolderFileSystem.cs new file mode 100644 index 00000000..1fea9665 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/TestDataFolderFileSystem.cs @@ -0,0 +1,42 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + + /// + /// This class builds on top of DisposableFileSystem + /// to make it easy to write a test that needs a whole folder of test data copied to a temp location + /// that will automatically be cleaned up at the end of the test. + /// + public class TestDataFolderFileSystem : IDisposable + { + private DisposableFileSystem fileSystem; + + public string BaseFolder { get; private set; } + + public void Dispose() + { + this.fileSystem?.Dispose(); + } + + public void Initialize(string sourceDirectoryPath) + { + if (this.fileSystem != null) + { + throw new InvalidOperationException(); + } + this.fileSystem = new DisposableFileSystem(); + + this.BaseFolder = this.fileSystem.GetFolder(); + + RobocopyFolder(sourceDirectoryPath, this.BaseFolder); + } + + public static ExternalExecutableResult RobocopyFolder(string sourceFolderPath, string destinationFolderPath) + { + var args = $"\"{sourceFolderPath}\" \"{destinationFolderPath}\" /E /R:1 /W:1"; + return RobocopyRunner.Execute(args); + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/VswhereRunner.cs b/src/internal/WixInternal.MSTestSupport/VswhereRunner.cs new file mode 100644 index 00000000..f6ff2116 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/VswhereRunner.cs @@ -0,0 +1,41 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.IO; + + public class VswhereRunner : ExternalExecutable + { + private static readonly string VswhereRelativePath = @"Microsoft Visual Studio\Installer\vswhere.exe"; + + private static readonly object InitLock = new object(); + private static bool Initialized; + private static VswhereRunner Instance; + + public static ExternalExecutableResult Execute(string args, bool mergeErrorIntoOutput = false) => + InitAndExecute(args, mergeErrorIntoOutput); + + private static ExternalExecutableResult InitAndExecute(string args, bool mergeErrorIntoOutput) + { + lock (InitLock) + { + if (!Initialized) + { + Initialized = true; + var vswherePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), VswhereRelativePath); + if (!File.Exists(vswherePath)) + { + throw new InvalidOperationException($"Failed to find vswhere at: {vswherePath}"); + } + + Instance = new VswhereRunner(vswherePath); + } + } + + return Instance.Run(args, mergeErrorIntoOutput); + } + + private VswhereRunner(string exePath) : base(exePath) { } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/WixAssert.cs b/src/internal/WixInternal.MSTestSupport/WixAssert.cs new file mode 100644 index 00000000..927ebee6 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/WixAssert.cs @@ -0,0 +1,164 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Xml.Linq; + + public class WixAssert + { + public static void CompareLineByLine(string[] expectedLines, string[] actualLines) + { + var lineNumber = 0; + + for (; lineNumber < expectedLines.Length && lineNumber < actualLines.Length; ++lineNumber) + { + StringEqual($"{lineNumber}: {expectedLines[lineNumber]}", $"{lineNumber}: {actualLines[lineNumber]}"); + } + + var additionalExpectedLines = expectedLines.Length > lineNumber ? String.Join(Environment.NewLine, expectedLines.Skip(lineNumber).Select((s, i) => $"{lineNumber + i}: {s}")) : $"Missing {actualLines.Length - lineNumber} lines"; + var additionalActualLines = actualLines.Length > lineNumber ? String.Join(Environment.NewLine, actualLines.Skip(lineNumber).Select((s, i) => $"{lineNumber + i}: {s}")) : $"Missing {expectedLines.Length - lineNumber} lines"; + + Assert.AreEqual(additionalExpectedLines, additionalActualLines, StringObjectEqualityComparer.InvariantCulture); + } + + public static void CompareXml(XContainer xExpected, XContainer xActual) + { + var expecteds = ComparableElements(xExpected); + var actuals = ComparableElements(xActual); + + CompareLineByLine(expecteds.OrderBy(s => s).ToArray(), actuals.OrderBy(s => s).ToArray()); + } + + public static void CompareXml(string expectedPath, string actualPath) + { + var expectedDoc = XDocument.Load(expectedPath, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + var actualDoc = XDocument.Load(actualPath, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + + CompareXml(expectedDoc, actualDoc); + } + + private static IEnumerable ComparableElements(XContainer container) + { + return container.Descendants().Select(x => $"{x.Name.LocalName}:{String.Join(",", x.Attributes().OrderBy(a => a.Name.LocalName).Select(a => $"{a.Name.LocalName}={ComparableAttribute(a)}"))}"); + } + + private static string ComparableAttribute(XAttribute attribute) + { + switch (attribute.Name.LocalName) + { + case "SourceFile": + return ""; + default: + return attribute.Value; + } + } + + public static void StringCollectionEmpty(IList collection) + { + if (collection.Count > 0) + { + Assert.Fail($"The collection was expected to be empty, but instead was [{Environment.NewLine}\"{String.Join($"\", {Environment.NewLine}\"", collection)}\"{Environment.NewLine}]"); + } + } + + public static void StringEqual(string expected, string actual, bool ignoreCase = false) + { + WixStringEqualException.ThrowIfNotEqual(expected, actual, ignoreCase); + } + + public static void NotStringEqual(string expected, string actual, bool ignoreCase = false) + { + var comparer = ignoreCase ? StringObjectEqualityComparer.InvariantCultureIgnoreCase : StringObjectEqualityComparer.InvariantCulture; + Assert.AreNotEqual(expected, actual, comparer); + } + + public static void Single(IEnumerable collection) + { + Assert.AreEqual(1, collection.Count()); + } + + public static void Single(IEnumerable collection, Func predicate) + { + var results = collection.Where(predicate); + Assert.AreEqual(1, results.Count()); + } + + public static void Empty(IEnumerable collection) + { + Assert.AreEqual(0, collection.Count()); + } + + public static void Empty(IEnumerable collection, Func predicate) + { + var results = collection.Where(predicate); + Assert.AreEqual(0, results.Count()); + } + } + + internal class StringObjectEqualityComparer : IEqualityComparer + { + public static readonly StringObjectEqualityComparer InvariantCultureIgnoreCase = new StringObjectEqualityComparer(true); + public static readonly StringObjectEqualityComparer InvariantCulture = new StringObjectEqualityComparer(false); + + private readonly StringComparer stringComparer; + + public StringObjectEqualityComparer(bool ignoreCase) + { + this.stringComparer = ignoreCase ? StringComparer.InvariantCultureIgnoreCase : StringComparer.InvariantCulture; + } + + public new bool Equals(object x, object y) + { + return this.stringComparer.Equals((string)x, (string)y); + } + + public int GetHashCode(object obj) + { + return this.stringComparer.GetHashCode((string)obj); + } + } + + public class WixStringEqualException : AssertFailedException + { + public WixStringEqualException(string userMessage) : base(userMessage) { } + + public static void ThrowIfNotEqual(string expected, string actual, bool ignoreCase) + { + var comparer = ignoreCase ? StringObjectEqualityComparer.InvariantCultureIgnoreCase : StringObjectEqualityComparer.InvariantCulture; + if (comparer.Equals(expected, actual)) + { + return; + } + + var sbMessage = new StringBuilder(); + + try + { + Assert.AreEqual(expected, actual, ignoreCase); + } + catch (AssertFailedException xe) + { + // If either string is not completely in the message, then make sure it gets in there. + if (!xe.Message.Contains(expected) || !xe.Message.Contains(actual)) + { + sbMessage.AppendLine(xe.Message); + sbMessage.AppendLine(); + sbMessage.AppendFormat("Expected: {0}", expected); + sbMessage.AppendLine(); + sbMessage.AppendFormat("Actual: {0}", actual); + } + else + { + throw; + } + } + + throw new WixStringEqualException(sbMessage.ToString()); + } + } +} diff --git a/src/internal/WixInternal.MSTestSupport/WixInternal.MSTestSupport.csproj b/src/internal/WixInternal.MSTestSupport/WixInternal.MSTestSupport.csproj new file mode 100644 index 00000000..b48aacd4 --- /dev/null +++ b/src/internal/WixInternal.MSTestSupport/WixInternal.MSTestSupport.csproj @@ -0,0 +1,27 @@ + + + + + + + net6.0;net472 + true + embedded + true + true + $(NoWarn);CS1591 + false + true + + + + + + + + + + + + + diff --git a/src/internal/WixInternal.TestSupport/WixAssert.cs b/src/internal/WixInternal.TestSupport/WixAssert.cs new file mode 100644 index 00000000..40355131 --- /dev/null +++ b/src/internal/WixInternal.TestSupport/WixAssert.cs @@ -0,0 +1,143 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.MSTestSupport +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Xml.Linq; + using Xunit; + using Xunit.Sdk; + + public class WixAssert + { + public static void CompareLineByLine(string[] expectedLines, string[] actualLines) + { + var lineNumber = 0; + + for (; lineNumber < expectedLines.Length && lineNumber < actualLines.Length; ++lineNumber) + { + StringEqual($"{lineNumber}: {expectedLines[lineNumber]}", $"{lineNumber}: {actualLines[lineNumber]}"); + } + + var additionalExpectedLines = expectedLines.Length > lineNumber ? String.Join(Environment.NewLine, expectedLines.Skip(lineNumber).Select((s, i) => $"{lineNumber + i}: {s}")) : $"Missing {actualLines.Length - lineNumber} lines"; + var additionalActualLines = actualLines.Length > lineNumber ? String.Join(Environment.NewLine, actualLines.Skip(lineNumber).Select((s, i) => $"{lineNumber + i}: {s}")) : $"Missing {expectedLines.Length - lineNumber} lines"; + + Assert.Equal(additionalExpectedLines, additionalActualLines, StringObjectEqualityComparer.InvariantCulture); + } + + public static void CompareXml(XContainer xExpected, XContainer xActual) + { + var expecteds = ComparableElements(xExpected); + var actuals = ComparableElements(xActual); + + CompareLineByLine(expecteds.OrderBy(s => s).ToArray(), actuals.OrderBy(s => s).ToArray()); + } + + public static void CompareXml(string expectedPath, string actualPath) + { + var expectedDoc = XDocument.Load(expectedPath, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + var actualDoc = XDocument.Load(actualPath, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + + CompareXml(expectedDoc, actualDoc); + } + + private static IEnumerable ComparableElements(XContainer container) + { + return container.Descendants().Select(x => $"{x.Name.LocalName}:{String.Join(",", x.Attributes().OrderBy(a => a.Name.LocalName).Select(a => $"{a.Name.LocalName}={ComparableAttribute(a)}"))}"); + } + + private static string ComparableAttribute(XAttribute attribute) + { + switch (attribute.Name.LocalName) + { + case "SourceFile": + return ""; + default: + return attribute.Value; + } + } + + public static void StringCollectionEmpty(IList collection) + { + if (collection.Count > 0) + { + Assert.Fail($"The collection was expected to be empty, but instead was [{Environment.NewLine}\"{String.Join($"\", {Environment.NewLine}\"", collection)}\"{Environment.NewLine}]"); + } + } + + public static void StringEqual(string expected, string actual, bool ignoreCase = false) + { + WixStringEqualException.ThrowIfNotEqual(expected, actual, ignoreCase); + } + + public static void NotStringEqual(string expected, string actual, bool ignoreCase = false) + { + var comparer = ignoreCase ? StringObjectEqualityComparer.InvariantCultureIgnoreCase : StringObjectEqualityComparer.InvariantCulture; + Assert.NotEqual(expected, actual, comparer); + } + } + + internal class StringObjectEqualityComparer : IEqualityComparer + { + public static readonly StringObjectEqualityComparer InvariantCultureIgnoreCase = new StringObjectEqualityComparer(true); + public static readonly StringObjectEqualityComparer InvariantCulture = new StringObjectEqualityComparer(false); + + private readonly StringComparer stringComparer; + + public StringObjectEqualityComparer(bool ignoreCase) + { + this.stringComparer = ignoreCase ? StringComparer.InvariantCultureIgnoreCase : StringComparer.InvariantCulture; + } + + public new bool Equals(object x, object y) + { + return this.stringComparer.Equals((string)x, (string)y); + } + + public int GetHashCode(object obj) + { + return this.stringComparer.GetHashCode((string)obj); + } + } + + public class WixStringEqualException : XunitException + { + public WixStringEqualException(string userMessage) : base(userMessage) { } + + public static void ThrowIfNotEqual(string expected, string actual, bool ignoreCase) + { + var comparer = ignoreCase ? StringObjectEqualityComparer.InvariantCultureIgnoreCase : StringObjectEqualityComparer.InvariantCulture; + if (comparer.Equals(expected, actual)) + { + return; + } + + var sbMessage = new StringBuilder(); + + try + { + Assert.Equal(expected, actual, ignoreCase); + } + catch (XunitException xe) + { + // If either string is not completely in the message, then make sure it gets in there. + if (!xe.Message.Contains(expected) || !xe.Message.Contains(actual)) + { + sbMessage.AppendLine(xe.Message); + sbMessage.AppendLine(); + sbMessage.AppendFormat("Expected: {0}", expected); + sbMessage.AppendLine(); + sbMessage.AppendFormat("Actual: {0}", actual); + } + else + { + throw; + } + } + + throw new WixStringEqualException(sbMessage.ToString()); + } + } +} diff --git a/src/internal/WixInternal.TestSupport/XunitExtensions/WixAssert.cs b/src/internal/WixInternal.TestSupport/XunitExtensions/WixAssert.cs index 5ac28de1..131d4e83 100644 --- a/src/internal/WixInternal.TestSupport/XunitExtensions/WixAssert.cs +++ b/src/internal/WixInternal.TestSupport/XunitExtensions/WixAssert.cs @@ -105,6 +105,32 @@ namespace WixInternal.TestSupport Assert.NotEqual(expected, actual, comparer); } + public static void Single(IEnumerable collection) + { + Assert.Single(collection); + // TODO: MSTEST: Assert.Equal(1, collection.Count()); + } + + public static void Single(IEnumerable collection, Func predicate) + { + var results = collection.Where(predicate); + Assert.Single(results); + // TODO: MSTEST: Assert.Equal(1, results.Count()); + } + + public static void Empty(IEnumerable collection) + { + Assert.Empty(collection); + // TODO: MSTEST: Assert.Equal(0, collection.Count()); + } + + public static void Empty(IEnumerable collection, Func predicate) + { + var results = collection.Where(predicate); + Assert.Empty(results); + // TODO: MSTEST: Assert.Equal(0, results.Count()); + } + // There appears to have been a bug in VC++, which might or might not have been partially // or completely corrected. It was unable to disambiguate a call to: // Xunit::Assert::Throws(System::Type^, System::Action^) diff --git a/src/internal/internal.sln b/src/internal/internal.sln index e8d8db17..5514e543 100644 --- a/src/internal/internal.sln +++ b/src/internal/internal.sln @@ -9,6 +9,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WixInternal.TestSupport.Nat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixInternal.BaseBuildTasks.Sources", "WixInternal.BaseBuildTasks.Sources\WixInternal.BaseBuildTasks.Sources.csproj", "{6B654490-AB0D-4F94-B564-DAA80044D5A3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WixInternal.XunitTestSupport", "WixInternal.XunitTestSupport\WixInternal.XunitTestSupport.csproj", "{AF7C4730-583B-46F8-9BB6-16D1F0330932}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WixInternal.MSTestSupport", "WixInternal.MSTestSupport\WixInternal.MSTestSupport.csproj", "{E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -65,6 +69,38 @@ Global {6B654490-AB0D-4F94-B564-DAA80044D5A3}.Release|x64.Build.0 = Release|Any CPU {6B654490-AB0D-4F94-B564-DAA80044D5A3}.Release|x86.ActiveCfg = Release|Any CPU {6B654490-AB0D-4F94-B564-DAA80044D5A3}.Release|x86.Build.0 = Release|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Debug|ARM64.Build.0 = Debug|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Debug|x64.ActiveCfg = Debug|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Debug|x64.Build.0 = Debug|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Debug|x86.ActiveCfg = Debug|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Debug|x86.Build.0 = Debug|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Release|Any CPU.Build.0 = Release|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Release|ARM64.ActiveCfg = Release|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Release|ARM64.Build.0 = Release|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Release|x64.ActiveCfg = Release|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Release|x64.Build.0 = Release|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Release|x86.ActiveCfg = Release|Any CPU + {AF7C4730-583B-46F8-9BB6-16D1F0330932}.Release|x86.Build.0 = Release|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Debug|ARM64.Build.0 = Debug|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Debug|x64.ActiveCfg = Debug|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Debug|x64.Build.0 = Debug|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Debug|x86.ActiveCfg = Debug|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Debug|x86.Build.0 = Debug|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Release|Any CPU.Build.0 = Release|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Release|ARM64.ActiveCfg = Release|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Release|ARM64.Build.0 = Release|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Release|x64.ActiveCfg = Release|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Release|x64.Build.0 = Release|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Release|x86.ActiveCfg = Release|Any CPU + {E70898F2-8D08-4FCE-9CFF-EF1792FCA2E2}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/internal/internal_t.proj b/src/internal/internal_t.proj index 7dd52354..ab96b6c8 100644 --- a/src/internal/internal_t.proj +++ b/src/internal/internal_t.proj @@ -2,6 +2,7 @@ + diff --git a/src/wix.runsettings b/src/wix.runsettings new file mode 100644 index 00000000..97e4acda --- /dev/null +++ b/src/wix.runsettings @@ -0,0 +1,7 @@ + + + + MethodLevel + + + diff --git a/src/wix/WixInternal.Core.MSTestPackage/BundleExtractor.cs b/src/wix/WixInternal.Core.MSTestPackage/BundleExtractor.cs new file mode 100644 index 00000000..c491ad56 --- /dev/null +++ b/src/wix/WixInternal.Core.MSTestPackage/BundleExtractor.cs @@ -0,0 +1,156 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.Core.MSTestPackage +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Xml; + using WixToolset.Data.Burn; + using WixToolset.Extensibility.Services; + + /// + /// Class to extract bundle contents for testing. + /// + public class BundleExtractor + { + private const string BurnNamespace = "http://wixtoolset.org/schemas/v4/2008/Burn"; + private const string BADataFileName = "BootstrapperApplicationData.xml"; + private const string BootstrapperExtensionDataFileName = "BootstrapperExtensionData.xml"; + + /// + /// Extracts the BA container. + /// + /// + /// Path to the bundle. + /// Path to extract to. + /// Temp path for extraction. + /// + public static ExtractBAContainerResult ExtractBAContainer(IMessaging messaging, string bundleFilePath, string destinationFolderPath, string tempFolderPath) + { + return ExtractAllContainers(messaging, bundleFilePath, destinationFolderPath, null, tempFolderPath); + } + + /// + /// Extracts the BA container. + /// + /// + /// Path to the bundle. + /// Path to extract BA to. + /// Optional path to extract other attached containers to. + /// Temp path for extraction. + /// + public static ExtractBAContainerResult ExtractAllContainers(IMessaging messaging, string bundleFilePath, string baFolderPath, string otherContainersFolderPath, string tempFolderPath) + { + Directory.CreateDirectory(tempFolderPath); + + var args = new List + { + "burn", "extract", + "-intermediatefolder", tempFolderPath, + bundleFilePath, + "-oba", baFolderPath + }; + + if (!String.IsNullOrEmpty(otherContainersFolderPath)) + { + args.Add("-o"); + args.Add(otherContainersFolderPath); + } + + var runnerResult = WixRunner.Execute(args.ToArray()); + + var result = new ExtractBAContainerResult(); + + if (runnerResult.ExitCode == 0) + { + result.Success = true; + result.ManifestDocument = LoadBurnManifest(baFolderPath); + result.ManifestNamespaceManager = GetBurnNamespaceManager(result.ManifestDocument, "burn"); + + result.BADataDocument = LoadBAData(baFolderPath); + result.BADataNamespaceManager = GetBADataNamespaceManager(result.BADataDocument, "ba"); + + result.BootstrapperExtensionDataDocument = LoadBootstrapperExtensionData(baFolderPath); + result.BootstrapperExtensionDataNamespaceManager = GetBootstrapperExtensionDataNamespaceManager(result.BootstrapperExtensionDataDocument, "be"); + } + + return result; + } + + /// + /// Gets an for BootstrapperApplicationData.xml with the given prefix assigned to the root namespace. + /// + /// + /// + /// + public static XmlNamespaceManager GetBADataNamespaceManager(XmlDocument document, string prefix) + { + var namespaceManager = new XmlNamespaceManager(document.NameTable); + namespaceManager.AddNamespace(prefix, BurnConstants.BootstrapperApplicationDataNamespace); + return namespaceManager; + } + + /// + /// Gets an for BootstrapperExtensionData.xml with the given prefix assigned to the root namespace. + /// + /// + /// + /// + public static XmlNamespaceManager GetBootstrapperExtensionDataNamespaceManager(XmlDocument document, string prefix) + { + var namespaceManager = new XmlNamespaceManager(document.NameTable); + namespaceManager.AddNamespace(prefix, BurnConstants.BootstrapperExtensionDataNamespace); + return namespaceManager; + } + + /// + /// Gets an for the Burn manifest.xml with the given prefix assigned to the root namespace. + /// + /// + /// + /// + public static XmlNamespaceManager GetBurnNamespaceManager(XmlDocument document, string prefix) + { + var namespaceManager = new XmlNamespaceManager(document.NameTable); + namespaceManager.AddNamespace(prefix, BurnNamespace); + return namespaceManager; + } + + /// + /// Loads an XmlDocument with the BootstrapperApplicationData.xml from the given folder that contains the contents of the BA container. + /// + /// + /// + public static XmlDocument LoadBAData(string baFolderPath) + { + var document = new XmlDocument(); + document.Load(Path.Combine(baFolderPath, BADataFileName)); + return document; + } + + /// + /// Loads an XmlDocument with the BootstrapperApplicationData.xml from the given folder that contains the contents of the BA container. + /// + /// + /// + public static XmlDocument LoadBootstrapperExtensionData(string baFolderPath) + { + var document = new XmlDocument(); + document.Load(Path.Combine(baFolderPath, BootstrapperExtensionDataFileName)); + return document; + } + + /// + /// Loads an XmlDocument with the BootstrapperApplicationData.xml from the given folder that contains the contents of the BA container. + /// + /// + /// + public static XmlDocument LoadBurnManifest(string baFolderPath) + { + var document = new XmlDocument(); + document.Load(Path.Combine(baFolderPath, "manifest.xml")); + return document; + } + } +} diff --git a/src/wix/WixInternal.Core.MSTestPackage/ExtractBAContainerResult.cs b/src/wix/WixInternal.Core.MSTestPackage/ExtractBAContainerResult.cs new file mode 100644 index 00000000..47759188 --- /dev/null +++ b/src/wix/WixInternal.Core.MSTestPackage/ExtractBAContainerResult.cs @@ -0,0 +1,156 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.Core.MSTestPackage +{ + using System.Collections.Generic; + using System.IO; + using System.Xml; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + /// + /// The result of extracting the BA container. + /// + public class ExtractBAContainerResult + { + /// + /// for BootstrapperExtensionData.xml. + /// + public XmlDocument BootstrapperExtensionDataDocument { get; set; } + + /// + /// for BootstrapperExtensionData.xml. + /// + public XmlNamespaceManager BootstrapperExtensionDataNamespaceManager { get; set; } + + /// + /// for BootstrapperApplicationData.xml. + /// + public XmlDocument BADataDocument { get; set; } + + /// + /// for BootstrapperApplicationData.xml. + /// + public XmlNamespaceManager BADataNamespaceManager { get; set; } + + /// + /// for the Burn manifest.xml. + /// + public XmlDocument ManifestDocument { get; set; } + + /// + /// for the Burn manifest.xml. + /// + public XmlNamespaceManager ManifestNamespaceManager { get; set; } + + /// + /// Whether extraction succeeded. + /// + public bool Success { get; set; } + + /// + /// Whether attached containers extraction succeeded. + /// + public bool? AttachedContainersSuccess { get; set; } + + /// + /// + /// + /// + public ExtractBAContainerResult AssertSuccess() + { + Assert.IsTrue(this.Success); + Assert.IsTrue(!this.AttachedContainersSuccess.HasValue || this.AttachedContainersSuccess.Value); + return this; + } + + /// + /// Returns the relative path of the BA entry point dll in the given folder. + /// + /// + /// + public string GetBAFilePath(string extractedBAContainerFolderPath) + { + var uxPayloads = this.SelectManifestNodes("/burn:BurnManifest/burn:UX/burn:Payload"); + var baPayload = uxPayloads[0]; + var relativeBAPath = baPayload.Attributes["FilePath"].Value; + return Path.Combine(extractedBAContainerFolderPath, relativeBAPath); + } + + /// + /// Returns the relative path of the BootstrapperExtension entry point dll in the given folder. + /// + /// + /// + /// + public string GetBootstrapperExtensionFilePath(string extractedBAContainerFolderPath, string extensionId) + { + var uxPayloads = this.SelectManifestNodes($"/burn:BurnManifest/burn:UX/burn:Payload[@Id='{extensionId}']"); + var bextPayload = uxPayloads[0]; + var relativeBextPath = bextPayload.Attributes["FilePath"].Value; + return Path.Combine(extractedBAContainerFolderPath, relativeBextPath); + } + + /// + /// + /// + /// elements must have the 'ba' prefix + /// + public XmlNodeList SelectBADataNodes(string xpath) + { + return this.BADataDocument.SelectNodes(xpath, this.BADataNamespaceManager); + } + + /// + /// + /// + /// elements must have the 'ba' prefix + /// Attributes for which the value should be set to '*'. + /// + public string[] GetBADataTestXmlLines(string xpath, Dictionary> ignoredAttributesByElementName = null) + { + return this.SelectBADataNodes(xpath).GetTestXmlLines(ignoredAttributesByElementName); + } + + /// + /// + /// + /// elements must have the 'be' prefix + /// + public XmlNodeList SelectBootstrapperExtensionDataNodes(string xpath) + { + return this.BootstrapperExtensionDataDocument.SelectNodes(xpath, this.BootstrapperExtensionDataNamespaceManager); + } + + /// + /// + /// + /// elements must have the 'be' prefix + /// Attributes for which the value should be set to '*'. + /// + public string[] GetBootstrapperExtensionTestXmlLines(string xpath, Dictionary> ignoredAttributesByElementName = null) + { + return this.SelectBootstrapperExtensionDataNodes(xpath).GetTestXmlLines(ignoredAttributesByElementName); + } + + /// + /// + /// + /// elements must have the 'burn' prefix + /// + public XmlNodeList SelectManifestNodes(string xpath) + { + return this.ManifestDocument.SelectNodes(xpath, this.ManifestNamespaceManager); + } + + /// + /// + /// + /// elements must have the 'burn' prefix + /// Attributes for which the value should be set to '*'. + /// + public string[] GetManifestTestXmlLines(string xpath, Dictionary> ignoredAttributesByElementName = null) + { + return this.SelectManifestNodes(xpath).GetTestXmlLines(ignoredAttributesByElementName); + } + } +} diff --git a/src/wix/WixInternal.Core.MSTestPackage/TestMessageListener.cs b/src/wix/WixInternal.Core.MSTestPackage/TestMessageListener.cs new file mode 100644 index 00000000..d8bde43f --- /dev/null +++ b/src/wix/WixInternal.Core.MSTestPackage/TestMessageListener.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.Core.MSTestPackage +{ + using System.Collections.Generic; + using WixToolset.Data; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Services; + + /// + /// An that simply stores all the messages. + /// + public sealed class TestMessageListener : IMessageListener + { + /// + /// All messages that have been received. + /// + public List Messages { get; } = new List(); + + /// + /// + /// + public string ShortAppName => "TEST"; + + /// + /// + /// + public string LongAppName => "Test"; + + /// + /// Stores the message in . + /// + /// + public void Write(Message message) + { + this.Messages.Add(message); + } + + /// + /// Stores the message in . + /// + /// + public void Write(string message) + { + this.Messages.Add(new Message(null, MessageLevel.Information, 0, message)); + } + + /// + /// Always returns defaultMessageLevel. + /// + /// + /// + /// + /// + public MessageLevel CalculateMessageLevel(IMessaging messaging, Message message, MessageLevel defaultMessageLevel) => defaultMessageLevel; + } +} diff --git a/src/wix/WixInternal.Core.MSTestPackage/WixInternal.Core.MSTestPackage.csproj b/src/wix/WixInternal.Core.MSTestPackage/WixInternal.Core.MSTestPackage.csproj new file mode 100644 index 00000000..6b4bbefe --- /dev/null +++ b/src/wix/WixInternal.Core.MSTestPackage/WixInternal.Core.MSTestPackage.csproj @@ -0,0 +1,35 @@ + + + + + + net6.0;net472 + Internal WiX Toolset MSTest Package + embedded + true + true + false + true + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/WixInternal.Core.MSTestPackage/WixMessageFormatter.cs b/src/wix/WixInternal.Core.MSTestPackage/WixMessageFormatter.cs new file mode 100644 index 00000000..c103f5d2 --- /dev/null +++ b/src/wix/WixInternal.Core.MSTestPackage/WixMessageFormatter.cs @@ -0,0 +1,40 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.Core.MSTestPackage +{ + using System; + using WixToolset.Data; + + /// + /// Utility class to help format messages. + /// + public static class WixMessageFormatter + { + /// + /// Formats a message into a standard string with the level, id, and message. + /// + /// Message to format + /// Standard message formatting with the level, id, and message. + public static string FormatMessage(Message message) + { + return $"{message.Level} {message.Id}: {message}"; + } + + /// + /// Formats a message into a standard string with the level, id, and message. + /// + /// Message to format + /// Match for the replacement + /// Value to replace + /// Standard message formatting with the level, id, and message. + public static string FormatMessage(Message message, string replacementMatch, string replacement) + { + if (replacement is null) + { + throw new ArgumentNullException(nameof(replacement)); + } + + return $"{message.Level} {message.Id}: {message}".Replace(replacementMatch, replacement); + } + } +} diff --git a/src/wix/WixInternal.Core.MSTestPackage/WixRunner.cs b/src/wix/WixInternal.Core.MSTestPackage/WixRunner.cs new file mode 100644 index 00000000..d83ba93e --- /dev/null +++ b/src/wix/WixInternal.Core.MSTestPackage/WixRunner.cs @@ -0,0 +1,90 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.Core.MSTestPackage +{ + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using WixToolset.Core; + using WixToolset.Core.Burn; + using WixToolset.Core.ExtensionCache; + using WixToolset.Core.WindowsInstaller; + using WixToolset.Data; + using WixToolset.Extensibility.Services; + + /// + /// Utility class to emulate wix.exe with standard backends. + /// + public static class WixRunner + { + /// + /// Emulates calling wix.exe with standard backends. + /// + /// + /// + /// + /// + public static int Execute(string[] args, out List messages, bool warningsAsErrors = true) + { + var serviceProvider = WixToolsetServiceProviderFactory.CreateServiceProvider(); + var task = Execute(args, serviceProvider, out messages, warningsAsErrors: warningsAsErrors); + return task.Result; + } + + /// + /// Emulates calling wix.exe with standard backends. + /// This overload always treats warnings as errors. + /// + /// + /// + public static WixRunnerResult Execute(params string[] args) + { + return Execute(true, args); + } + + /// + /// Emulates calling wix.exe with standard backends. + /// + /// + /// + /// + public static WixRunnerResult Execute(bool warningsAsErrors, params string[] args) + { + var serviceProvider = WixToolsetServiceProviderFactory.CreateServiceProvider(); + var exitCode = Execute(args, serviceProvider, out var messages, warningsAsErrors: warningsAsErrors); + return new WixRunnerResult { ExitCode = exitCode.Result, Messages = messages.ToArray() }; + } + + /// + /// Emulates calling wix.exe with standard backends. + /// + /// + /// + /// + /// + /// + public static Task Execute(string[] args, IWixToolsetCoreServiceProvider coreProvider, out List messages, bool warningsAsErrors = true) + { + coreProvider.AddWindowsInstallerBackend() + .AddBundleBackend() + .AddExtensionCacheManager(); + + var listener = new TestMessageListener(); + + messages = listener.Messages; + + var messaging = coreProvider.GetService(); + messaging.SetListener(listener); + + var arguments = new List(args); + if (warningsAsErrors) + { + arguments.Add("-wx"); + } + + var commandLine = coreProvider.GetService(); + var command = commandLine.CreateCommand(arguments.ToArray()); + return command?.ExecuteAsync(CancellationToken.None) ?? Task.FromResult(1); + } + } +} diff --git a/src/wix/WixInternal.Core.MSTestPackage/WixRunnerResult.cs b/src/wix/WixInternal.Core.MSTestPackage/WixRunnerResult.cs new file mode 100644 index 00000000..4a8c784d --- /dev/null +++ b/src/wix/WixInternal.Core.MSTestPackage/WixRunnerResult.cs @@ -0,0 +1,62 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.Core.MSTestPackage +{ + using System; + using System.Collections.Generic; + using WixToolset.Data; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + /// + /// The result of an Execute method of . + /// + public class WixRunnerResult + { + /// + /// ExitCode for the operation. + /// + public int ExitCode { get; set; } + + /// + /// Messages from the operation. + /// + public Message[] Messages { get; set; } + + /// + /// + /// + /// + public WixRunnerResult AssertSuccess() + { + AssertSuccess(this.ExitCode, this.Messages); + return this; + } + + /// + /// + /// + /// + /// + public static void AssertSuccess(int exitCode, IEnumerable messages) + { + Assert.IsTrue(0 == exitCode, $"\r\n\r\nWixRunner failed with exit code: {exitCode}\r\n Output: {String.Join("\r\n ", FormatMessages(messages))}\r\n"); + } + + private static IEnumerable FormatMessages(IEnumerable messages) + { + foreach (var message in messages) + { + var filename = message.SourceLineNumbers?.FileName ?? "TEST"; + var line = message.SourceLineNumbers?.LineNumber ?? -1; + var type = message.Level.ToString().ToLowerInvariant(); + + if (line > 0) + { + filename = String.Concat(filename, "(", line, ")"); + } + + yield return String.Format("{0} : {1} {2}{3:0000}: {4}", filename, type, "TEST", message.Id, message.ToString()); + } + } + } +} diff --git a/src/wix/WixInternal.Core.MSTestPackage/XmlNodeExtensions.cs b/src/wix/WixInternal.Core.MSTestPackage/XmlNodeExtensions.cs new file mode 100644 index 00000000..11a7b209 --- /dev/null +++ b/src/wix/WixInternal.Core.MSTestPackage/XmlNodeExtensions.cs @@ -0,0 +1,115 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixInternal.Core.MSTestPackage +{ + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Text.RegularExpressions; + using System.Xml; + + /// + /// Utility class to help compare XML in tests using string comparisons by using single quotes and stripping all namespaces. + /// + public static class XmlNodeExtensions + { + /// + /// Adds root element around XML then returns it using single quotes and stripping all namespaces. + /// + /// + /// Attributes for which the value should be set to '*'. + /// + public static string GetFragmentTestXml(this string xmlFragment, Dictionary> ignoredAttributesByElementName = null) + { + return $"{xmlFragment}".GetTestXml(ignoredAttributesByElementName); + } + + /// + /// Returns the node's outer XML using single quotes and stripping all namespaces. + /// + /// + /// Attributes for which the value should be set to '*'. + /// + public static string GetTestXml(this XmlNode node, Dictionary> ignoredAttributesByElementName = null) + { + return node.OuterXml.GetTestXml(ignoredAttributesByElementName); + } + + /// + /// Returns the XML using single quotes and stripping all namespaces. + /// + /// + /// Attributes for which the value should be set to '*'. + /// + public static string GetTestXml(this string xml, Dictionary> ignoredAttributesByElementName = null) + { + string formattedXml; + using (var sw = new StringWriter()) + using (var writer = new TestXmlWriter(sw)) + { + var doc = new XmlDocument(); + doc.LoadXml(xml); + + if (ignoredAttributesByElementName != null) + { + HandleIgnoredAttributes(doc, ignoredAttributesByElementName); + } + + doc.Save(writer); + formattedXml = sw.ToString(); + } + + return Regex.Replace(formattedXml, " xmlns(:[^=]+)?='[^']*'", ""); + } + + /// + /// Returns the XML for each node using single quotes and stripping all namespaces. + /// + /// + /// Attributes for which the value should be set to '*'. + /// + public static string[] GetTestXmlLines(this XmlNodeList nodeList, Dictionary> ignoredAttributesByElementName = null) + { + return nodeList.Cast() + .Select(x => x.GetTestXml(ignoredAttributesByElementName)) + .ToArray(); + } + + private static void HandleIgnoredAttributes(XmlNode node, Dictionary> ignoredAttributesByElementName) + { + if (node.Attributes != null && ignoredAttributesByElementName.TryGetValue(node.LocalName, out var ignoredAttributes)) + { + foreach (var ignoredAttribute in ignoredAttributes) + { + var attribute = node.Attributes[ignoredAttribute]; + if (attribute != null) + { + attribute.Value = "*"; + } + } + } + + if (node.ChildNodes != null) + { + foreach (XmlNode childNode in node.ChildNodes) + { + HandleIgnoredAttributes(childNode, ignoredAttributesByElementName); + } + } + } + + private class TestXmlWriter : XmlTextWriter + { + public TestXmlWriter(TextWriter w) + : base(w) + { + this.QuoteChar = '\''; + } + + public override void WriteStartDocument() + { + //OmitXmlDeclaration + } + } + } +} diff --git a/src/wix/pack_t.proj b/src/wix/pack_t.proj index cd2cf634..7090f19b 100644 --- a/src/wix/pack_t.proj +++ b/src/wix/pack_t.proj @@ -8,6 +8,7 @@ + diff --git a/src/wix/wix.sln b/src/wix/wix.sln index f64b22c0..7eec8e8a 100644 --- a/src/wix/wix.sln +++ b/src/wix/wix.sln @@ -48,6 +48,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "pack-wix", "pack-wix\pack-w EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Core", "test\WixToolsetTest.Core\WixToolsetTest.Core.csproj", "{392817AE-4493-4BED-A7FD-2399379E1B1C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WixInternal.Core.MSTestPackage", "WixInternal.Core.MSTestPackage\WixInternal.Core.MSTestPackage.csproj", "{61003299-4D78-4291-862C-73806C62C3BD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -412,6 +414,22 @@ Global {392817AE-4493-4BED-A7FD-2399379E1B1C}.Release|x64.Build.0 = Release|Any CPU {392817AE-4493-4BED-A7FD-2399379E1B1C}.Release|x86.ActiveCfg = Release|Any CPU {392817AE-4493-4BED-A7FD-2399379E1B1C}.Release|x86.Build.0 = Release|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Debug|ARM64.Build.0 = Debug|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Debug|x64.ActiveCfg = Debug|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Debug|x64.Build.0 = Debug|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Debug|x86.ActiveCfg = Debug|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Debug|x86.Build.0 = Debug|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Release|Any CPU.Build.0 = Release|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Release|ARM64.ActiveCfg = Release|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Release|ARM64.Build.0 = Release|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Release|x64.ActiveCfg = Release|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Release|x64.Build.0 = Release|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Release|x86.ActiveCfg = Release|Any CPU + {61003299-4D78-4291-862C-73806C62C3BD}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE -- cgit v1.2.3-55-g6feb