aboutsummaryrefslogtreecommitdiff
path: root/src/burn/test/BurnUnitTest
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 17:06:54 -0700
committerRob Mensching <rob@firegiant.com>2021-04-29 16:36:06 -0700
commitaf10c45d7b3a44af0b461a557847fe03263dcc10 (patch)
tree6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/test/BurnUnitTest
parent9c2aed97299fb96aeee3f1471ce40225437aaecf (diff)
downloadwix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.gz
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.bz2
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.zip
Move burn into burn
Diffstat (limited to 'src/burn/test/BurnUnitTest')
-rw-r--r--src/burn/test/BurnUnitTest/AssemblyInfo.cpp12
-rw-r--r--src/burn/test/BurnUnitTest/BurnTestException.h93
-rw-r--r--src/burn/test/BurnUnitTest/BurnTestFixture.h75
-rw-r--r--src/burn/test/BurnUnitTest/BurnUnitTest.h48
-rw-r--r--src/burn/test/BurnUnitTest/BurnUnitTest.rc6
-rw-r--r--src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj109
-rw-r--r--src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters80
-rw-r--r--src/burn/test/BurnUnitTest/CacheTest.cpp119
-rw-r--r--src/burn/test/BurnUnitTest/ElevationTest.cpp221
-rw-r--r--src/burn/test/BurnUnitTest/ManifestHelpers.cpp41
-rw-r--r--src/burn/test/BurnUnitTest/ManifestHelpers.h24
-rw-r--r--src/burn/test/BurnUnitTest/ManifestTest.cpp62
-rw-r--r--src/burn/test/BurnUnitTest/PlanTest.cpp1473
-rw-r--r--src/burn/test/BurnUnitTest/RegistrationTest.cpp772
-rw-r--r--src/burn/test/BurnUnitTest/SearchTest.cpp815
-rw-r--r--src/burn/test/BurnUnitTest/TestData/CacheTest/CacheSignatureTest.File1
-rw-r--r--src/burn/test/BurnUnitTest/TestData/PlanTest/BasicFunctionality_BundleA_manifest.xml1
-rw-r--r--src/burn/test/BurnUnitTest/TestData/PlanTest/MsiTransaction_BundleAv1_manifest.xml1
-rw-r--r--src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml1
-rw-r--r--src/burn/test/BurnUnitTest/VariableHelpers.cpp217
-rw-r--r--src/burn/test/BurnUnitTest/VariableHelpers.h36
-rw-r--r--src/burn/test/BurnUnitTest/VariableTest.cpp532
-rw-r--r--src/burn/test/BurnUnitTest/VariantTest.cpp221
-rw-r--r--src/burn/test/BurnUnitTest/packages.config15
-rw-r--r--src/burn/test/BurnUnitTest/precomp.cpp3
-rw-r--r--src/burn/test/BurnUnitTest/precomp.h79
26 files changed, 5057 insertions, 0 deletions
diff --git a/src/burn/test/BurnUnitTest/AssemblyInfo.cpp b/src/burn/test/BurnUnitTest/AssemblyInfo.cpp
new file mode 100644
index 00000000..0282b1b7
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/AssemblyInfo.cpp
@@ -0,0 +1,12 @@
1// 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.
2
3#include "precomp.h"
4
5using namespace System::Reflection;
6using namespace System::Runtime::CompilerServices;
7using namespace System::Runtime::InteropServices;
8
9[assembly: AssemblyTitleAttribute("Windows Installer XML Burn unit tests")];
10[assembly: AssemblyDescriptionAttribute("Burn unit tests")];
11[assembly: AssemblyCultureAttribute("")];
12[assembly: ComVisible(false)];
diff --git a/src/burn/test/BurnUnitTest/BurnTestException.h b/src/burn/test/BurnUnitTest/BurnTestException.h
new file mode 100644
index 00000000..bd94b4fc
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/BurnTestException.h
@@ -0,0 +1,93 @@
1#pragma once
2// 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.
3
4
5namespace Microsoft
6{
7namespace Tools
8{
9namespace WindowsInstallerXml
10{
11namespace Test
12{
13namespace Bootstrapper
14{
15 using namespace System;
16
17 public ref struct BurnTestException : public System::Exception
18 {
19 public:
20 BurnTestException(HRESULT error)
21 {
22 this->HResult = error;
23 }
24
25 BurnTestException(HRESULT error, String^ message)
26 : Exception(message)
27 {
28 this->HResult = error;
29 }
30
31 property Int32 ErrorCode
32 {
33 Int32 get()
34 {
35 return this->HResult;
36 }
37 }
38
39 };
40}
41}
42}
43}
44}
45
46// this class is used by __TestThrowOnFailure_Format() below to deallocate
47// the string created after the function call has returned
48class __TestThrowOnFailure_StringFree
49{
50 LPWSTR m_scz;
51
52public:
53 __TestThrowOnFailure_StringFree(LPWSTR scz)
54 {
55 m_scz = scz;
56 }
57
58 ~__TestThrowOnFailure_StringFree()
59 {
60 ReleaseStr(m_scz);
61 }
62
63 operator LPCWSTR()
64 {
65 return m_scz;
66 }
67};
68
69// used by the TestThrowOnFailure macros to format the error string and
70// return an LPCWSTR that can be used to initialize a System::String
71#pragma warning (push)
72#pragma warning (disable : 4793)
73inline __TestThrowOnFailure_StringFree __TestThrowOnFailure_Format(LPCWSTR wzFormat, ...)
74{
75 Assert(wzFormat && *wzFormat);
76
77 HRESULT hr = S_OK;
78 LPWSTR scz = NULL;
79 va_list args;
80
81 va_start(args, wzFormat);
82 hr = StrAllocFormattedArgs(&scz, wzFormat, args);
83 va_end(args);
84 ExitOnFailure(hr, "Failed to format message string.");
85
86LExit:
87 return scz;
88}
89#pragma warning (pop)
90
91#define TestThrowOnFailure(hr, s) if (FAILED(hr)) { throw gcnew Microsoft::Tools::WindowsInstallerXml::Test::Bootstrapper::BurnTestException(hr, gcnew System::String(s)); }
92#define TestThrowOnFailure1(hr, s, p) if (FAILED(hr)) { throw gcnew Microsoft::Tools::WindowsInstallerXml::Test::Bootstrapper::BurnTestException(hr, gcnew System::String(__TestThrowOnFailure_Format(s, p))); }
93#define TestThrowOnFailure2(hr, s, p1, p2) if (FAILED(hr)) { throw gcnew Microsoft::Tools::WindowsInstallerXml::Test::Bootstrapper::BurnTestException(hr, gcnew System::String(__TestThrowOnFailure_Format(s, p1, p2))); }
diff --git a/src/burn/test/BurnUnitTest/BurnTestFixture.h b/src/burn/test/BurnUnitTest/BurnTestFixture.h
new file mode 100644
index 00000000..103972ef
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/BurnTestFixture.h
@@ -0,0 +1,75 @@
1#pragma once
2// 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.
3
4
5namespace Microsoft
6{
7namespace Tools
8{
9namespace WindowsInstallerXml
10{
11namespace Test
12{
13namespace Bootstrapper
14{
15 using namespace System;
16 using namespace WixBuildTools::TestSupport;
17
18 public ref class BurnTestFixture : IDisposable
19 {
20 public:
21 BurnTestFixture()
22 {
23 HRESULT hr = XmlInitialize();
24 TestThrowOnFailure(hr, L"Failed to initialize XML support.");
25
26 hr = RegInitialize();
27 TestThrowOnFailure(hr, L"Failed to initialize Regutil.");
28
29 hr = CrypInitialize();
30 TestThrowOnFailure(hr, L"Failed to initialize Cryputil.");
31
32 PlatformInitialize();
33
34 this->testDirectory = WixBuildTools::TestSupport::TestData::Get();
35
36 LogInitialize(::GetModuleHandleW(NULL));
37
38 LogSetLevel(REPORT_DEBUG, FALSE);
39
40 hr = LogOpen(NULL, L"BurnUnitTest", NULL, L"txt", FALSE, FALSE, NULL);
41 TestThrowOnFailure(hr, L"Failed to open log.");
42 }
43
44 ~BurnTestFixture()
45 {
46 CrypUninitialize();
47 XmlUninitialize();
48 RegUninitialize();
49 LogUninitialize(FALSE);
50 }
51
52 property String^ DataDirectory
53 {
54 String^ get()
55 {
56 return this->testDirectory;
57 }
58 }
59
60 property String^ TestDirectory
61 {
62 String^ get()
63 {
64 return this->testDirectory;
65 }
66 }
67
68 private:
69 String^ testDirectory;
70 };
71}
72}
73}
74}
75}
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.h b/src/burn/test/BurnUnitTest/BurnUnitTest.h
new file mode 100644
index 00000000..ed1d2956
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/BurnUnitTest.h
@@ -0,0 +1,48 @@
1#pragma once
2// 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.
3
4
5namespace Microsoft
6{
7namespace Tools
8{
9namespace WindowsInstallerXml
10{
11namespace Test
12{
13namespace Bootstrapper
14{
15 using namespace System;
16 using namespace Xunit;
17
18 [CollectionDefinition("Burn")]
19 public ref class BurnCollectionDefinition : ICollectionFixture<BurnTestFixture^>
20 {
21
22 };
23
24 [Collection("Burn")]
25 public ref class BurnUnitTest
26 {
27 public:
28 BurnUnitTest(BurnTestFixture^ fixture)
29 {
30 this->testContext = fixture;
31 }
32
33 property BurnTestFixture^ TestContext
34 {
35 BurnTestFixture^ get()
36 {
37 return this->testContext;
38 }
39 }
40
41 private:
42 BurnTestFixture^ testContext;
43 };
44}
45}
46}
47}
48}
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.rc b/src/burn/test/BurnUnitTest/BurnUnitTest.rc
new file mode 100644
index 00000000..3a815db2
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/BurnUnitTest.rc
@@ -0,0 +1,6 @@
1// 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.
2
3#define VER_APP
4#define VER_ORIGINAL_FILENAME "BurnUnitTest.dll"
5#define VER_INTERNAL_NAME "setup"
6#define VER_FILE_DESCRIPTION "WiX Toolset Bootstrapper unit tests"
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
new file mode 100644
index 00000000..33c8ed6c
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
@@ -0,0 +1,109 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <Import Project="..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.57\build\WixToolset.BootstrapperCore.Native.props" Condition="Exists('..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.57\build\WixToolset.BootstrapperCore.Native.props')" />
6 <Import Project="..\..\..\packages\WixToolset.DUtil.4.0.70\build\WixToolset.DUtil.props" Condition="Exists('..\..\..\packages\WixToolset.DUtil.4.0.70\build\WixToolset.DUtil.props')" />
7 <Import Project="..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.47\build\WixBuildTools.TestSupport.Native.props" Condition="Exists('..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.47\build\WixBuildTools.TestSupport.Native.props')" />
8 <ItemGroup Label="ProjectConfigurations">
9 <ProjectConfiguration Include="Debug|ARM64">
10 <Configuration>Debug</Configuration>
11 <Platform>ARM64</Platform>
12 </ProjectConfiguration>
13 <ProjectConfiguration Include="Debug|Win32">
14 <Configuration>Debug</Configuration>
15 <Platform>Win32</Platform>
16 </ProjectConfiguration>
17 <ProjectConfiguration Include="Release|ARM64">
18 <Configuration>Release</Configuration>
19 <Platform>ARM64</Platform>
20 </ProjectConfiguration>
21 <ProjectConfiguration Include="Release|Win32">
22 <Configuration>Release</Configuration>
23 <Platform>Win32</Platform>
24 </ProjectConfiguration>
25 </ItemGroup>
26
27 <PropertyGroup Label="Globals">
28 <ProjectTypes>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}</ProjectTypes>
29 <ProjectGuid>{9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}</ProjectGuid>
30 <RootNamespace>UnitTest</RootNamespace>
31 <Keyword>ManagedCProj</Keyword>
32 <ConfigurationType>DynamicLibrary</ConfigurationType>
33 <CharacterSet>Unicode</CharacterSet>
34 <CLRSupport>true</CLRSupport>
35 <SignOutput>false</SignOutput>
36 </PropertyGroup>
37
38 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
39 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
40
41 <PropertyGroup>
42 <ProjectAdditionalIncludeDirectories Condition=" '$(DirectReference)'=='true' ">$(ProjectDir)..\..\..\..\balutil\src\WixToolset.BootstrapperCore.Native\inc</ProjectAdditionalIncludeDirectories>
43 <ProjectAdditionalIncludeDirectories>$(ProjectAdditionalIncludeDirectories);..\..\engine</ProjectAdditionalIncludeDirectories>
44 <ProjectAdditionalLinkLibraries>cabinet.lib;crypt32.lib;msi.lib;rpcrt4.lib;shlwapi.lib;wininet.lib</ProjectAdditionalLinkLibraries>
45 </PropertyGroup>
46
47 <ItemGroup>
48 <ClCompile Include="AssemblyInfo.cpp" />
49 <ClCompile Include="CacheTest.cpp" />
50 <ClCompile Include="ElevationTest.cpp" />
51 <ClCompile Include="ManifestHelpers.cpp" />
52 <ClCompile Include="ManifestTest.cpp" />
53 <ClCompile Include="PlanTest.cpp" />
54 <ClCompile Include="precomp.cpp">
55 <PrecompiledHeader>Create</PrecompiledHeader>
56 <!-- Warnings from referencing netstandard dlls -->
57 <DisableSpecificWarnings>4564;4691</DisableSpecificWarnings>
58 </ClCompile>
59 <ClCompile Include="RegistrationTest.cpp" />
60 <ClCompile Include="SearchTest.cpp" />
61 <ClCompile Include="VariableHelpers.cpp" />
62 <ClCompile Include="VariableTest.cpp" />
63 <ClCompile Include="VariantTest.cpp" />
64 </ItemGroup>
65 <ItemGroup>
66 <ClInclude Include="BurnTestException.h" />
67 <ClInclude Include="BurnTestFixture.h" />
68 <ClInclude Include="BurnUnitTest.h" />
69 <ClInclude Include="ManifestHelpers.h" />
70 <ClInclude Include="precomp.h" />
71 <ClInclude Include="VariableHelpers.h" />
72 </ItemGroup>
73 <ItemGroup>
74 <None Include="packages.config" />
75 <ResourceCompile Include="BurnUnitTest.rc" />
76 </ItemGroup>
77 <ItemGroup>
78 <None Include="TestData\CacheTest\CacheSignatureTest.File" CopyToOutputDirectory="PreserveNewest" />
79 <None Include="TestData\PlanTest\BasicFunctionality_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" />
80 <None Include="TestData\PlanTest\MsiTransaction_BundleAv1_manifest.xml" CopyToOutputDirectory="PreserveNewest" />
81 <None Include="TestData\PlanTest\Slipstream_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" />
82 </ItemGroup>
83 <ItemGroup>
84 <Reference Include="System" />
85 <Reference Include="System.Core" />
86 <Reference Include="WixBuildTools.TestSupport">
87 <HintPath>..\..\..\packages\WixBuildTools.TestSupport.4.0.50\lib\net472\WixBuildTools.TestSupport.dll</HintPath>
88 </Reference>
89 <Reference Include="WixBuildTools.TestSupport.Native">
90 <HintPath>..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.50\lib\net472\WixBuildTools.TestSupport.Native.dll</HintPath>
91 </Reference>
92 </ItemGroup>
93 <ItemGroup>
94 <ProjectReference Include="..\..\engine\engine.vcxproj">
95 <Project>{8119537D-E1D9-6591-D51A-49770A2F9C37}</Project>
96 </ProjectReference>
97 </ItemGroup>
98 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
99 <Import Project="..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.50\build\WixBuildTools.TestSupport.Native.targets" Condition="Exists('..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.50\build\WixBuildTools.TestSupport.Native.targets')" />
100 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
101 <PropertyGroup>
102 <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
103 </PropertyGroup>
104 <Error Condition="!Exists('..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.47\build\WixBuildTools.TestSupport.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.47\build\WixBuildTools.TestSupport.Native.props'))" />
105 <Error Condition="!Exists('..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.47\build\WixBuildTools.TestSupport.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.47\build\WixBuildTools.TestSupport.Native.targets'))" />
106 <Error Condition="!Exists('..\..\..\packages\WixToolset.DUtil.4.0.70\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixToolset.DUtil.4.0.70\build\WixToolset.DUtil.props'))" />
107 <Error Condition="!Exists('..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.57\build\WixToolset.BootstrapperCore.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.57\build\WixToolset.BootstrapperCore.Native.props'))" />
108 </Target>
109</Project>
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters
new file mode 100644
index 00000000..f9461f53
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters
@@ -0,0 +1,80 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemGroup>
4 <Filter Include="Source Files">
5 <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
6 <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
7 </Filter>
8 <Filter Include="Header Files">
9 <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
10 <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
11 </Filter>
12 <Filter Include="Resource Files">
13 <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
14 <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
15 </Filter>
16 </ItemGroup>
17 <ItemGroup>
18 <ClCompile Include="AssemblyInfo.cpp">
19 <Filter>Source Files</Filter>
20 </ClCompile>
21 <ClCompile Include="CacheTest.cpp">
22 <Filter>Source Files</Filter>
23 </ClCompile>
24 <ClCompile Include="ElevationTest.cpp">
25 <Filter>Source Files</Filter>
26 </ClCompile>
27 <ClCompile Include="ManifestHelpers.cpp">
28 <Filter>Source Files</Filter>
29 </ClCompile>
30 <ClCompile Include="ManifestTest.cpp">
31 <Filter>Source Files</Filter>
32 </ClCompile>
33 <ClCompile Include="PlanTest.cpp">
34 <Filter>Source Files</Filter>
35 </ClCompile>
36 <ClCompile Include="precomp.cpp">
37 <Filter>Source Files</Filter>
38 </ClCompile>
39 <ClCompile Include="RegistrationTest.cpp">
40 <Filter>Source Files</Filter>
41 </ClCompile>
42 <ClCompile Include="SearchTest.cpp">
43 <Filter>Source Files</Filter>
44 </ClCompile>
45 <ClCompile Include="VariableHelpers.cpp">
46 <Filter>Source Files</Filter>
47 </ClCompile>
48 <ClCompile Include="VariableTest.cpp">
49 <Filter>Source Files</Filter>
50 </ClCompile>
51 <ClCompile Include="VariantTest.cpp">
52 <Filter>Source Files</Filter>
53 </ClCompile>
54 </ItemGroup>
55 <ItemGroup>
56 <ClInclude Include="BurnTestException.h">
57 <Filter>Header Files</Filter>
58 </ClInclude>
59 <ClInclude Include="ManifestHelpers.h">
60 <Filter>Header Files</Filter>
61 </ClInclude>
62 <ClInclude Include="precomp.h">
63 <Filter>Header Files</Filter>
64 </ClInclude>
65 <ClInclude Include="VariableHelpers.h">
66 <Filter>Header Files</Filter>
67 </ClInclude>
68 <ClInclude Include="BurnUnitTest.h">
69 <Filter>Header Files</Filter>
70 </ClInclude>
71 <ClInclude Include="BurnTestFixture.h">
72 <Filter>Header Files</Filter>
73 </ClInclude>
74 </ItemGroup>
75 <ItemGroup>
76 <ResourceCompile Include="BurnUnitTest.rc">
77 <Filter>Resource Files</Filter>
78 </ResourceCompile>
79 </ItemGroup>
80</Project> \ No newline at end of file
diff --git a/src/burn/test/BurnUnitTest/CacheTest.cpp b/src/burn/test/BurnUnitTest/CacheTest.cpp
new file mode 100644
index 00000000..d0cc237f
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/CacheTest.cpp
@@ -0,0 +1,119 @@
1// 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.
2
3#include "precomp.h"
4
5static HRESULT CALLBACK CacheTestEventRoutine(
6 __in BURN_CACHE_MESSAGE* pMessage,
7 __in LPVOID pvContext
8 );
9
10static DWORD CALLBACK CacheTestProgressRoutine(
11 __in LARGE_INTEGER TotalFileSize,
12 __in LARGE_INTEGER TotalBytesTransferred,
13 __in LARGE_INTEGER StreamSize,
14 __in LARGE_INTEGER StreamBytesTransferred,
15 __in DWORD dwStreamNumber,
16 __in DWORD dwCallbackReason,
17 __in HANDLE hSourceFile,
18 __in HANDLE hDestinationFile,
19 __in_opt LPVOID lpData
20 );
21
22typedef struct _CACHE_TEST_CONTEXT
23{
24} CACHE_TEST_CONTEXT;
25
26namespace Microsoft
27{
28namespace Tools
29{
30namespace WindowsInstallerXml
31{
32namespace Test
33{
34namespace Bootstrapper
35{
36 using namespace System;
37 using namespace System::IO;
38 using namespace Xunit;
39
40 public ref class CacheTest : BurnUnitTest
41 {
42 public:
43 CacheTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
44 {
45 }
46
47 [Fact]
48 void CacheSignatureTest()
49 {
50 HRESULT hr = S_OK;
51 BURN_PACKAGE package = { };
52 BURN_PAYLOAD payload = { };
53 LPWSTR sczPayloadPath = NULL;
54 BYTE* pb = NULL;
55 DWORD cb = NULL;
56 CACHE_TEST_CONTEXT context = { };
57
58 try
59 {
60 pin_ptr<const wchar_t> dataDirectory = PtrToStringChars(this->TestContext->TestDirectory);
61 hr = PathConcat(dataDirectory, L"TestData\\CacheTest\\CacheSignatureTest.File", &sczPayloadPath);
62 Assert::True(S_OK == hr, "Failed to get path to test file.");
63 Assert::True(FileExistsEx(sczPayloadPath, NULL), "Test file does not exist.");
64
65 hr = StrAllocHexDecode(L"25e61cd83485062b70713aebddd3fe4992826cb121466fddc8de3eacb1e42f39d4bdd8455d95eec8c9529ced4c0296ab861931fe2c86df2f2b4e8d259a6d9223", &pb, &cb);
66 Assert::Equal(S_OK, hr);
67
68 package.fPerMachine = FALSE;
69 package.sczCacheId = L"Bootstrapper.CacheTest.CacheSignatureTest";
70 payload.sczKey = L"CacheSignatureTest.PayloadKey";
71 payload.sczFilePath = L"CacheSignatureTest.File";
72 payload.pbHash = pb;
73 payload.cbHash = cb;
74
75 hr = CacheCompletePayload(package.fPerMachine, &payload, package.sczCacheId, sczPayloadPath, FALSE, CacheTestEventRoutine, CacheTestProgressRoutine, &context);
76 Assert::Equal(S_OK, hr);
77 }
78 finally
79 {
80 ReleaseMem(pb);
81 ReleaseStr(sczPayloadPath);
82
83 String^ filePath = Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), "Package Cache\\Bootstrapper.CacheTest.CacheSignatureTest\\CacheSignatureTest.File");
84 if (File::Exists(filePath))
85 {
86 File::SetAttributes(filePath, FileAttributes::Normal);
87 File::Delete(filePath);
88 }
89 }
90 }
91 };
92}
93}
94}
95}
96}
97
98static HRESULT CALLBACK CacheTestEventRoutine(
99 __in BURN_CACHE_MESSAGE* /*pMessage*/,
100 __in LPVOID /*pvContext*/
101 )
102{
103 return S_OK;
104}
105
106static DWORD CALLBACK CacheTestProgressRoutine(
107 __in LARGE_INTEGER /*TotalFileSize*/,
108 __in LARGE_INTEGER /*TotalBytesTransferred*/,
109 __in LARGE_INTEGER /*StreamSize*/,
110 __in LARGE_INTEGER /*StreamBytesTransferred*/,
111 __in DWORD /*dwStreamNumber*/,
112 __in DWORD /*dwCallbackReason*/,
113 __in HANDLE /*hSourceFile*/,
114 __in HANDLE /*hDestinationFile*/,
115 __in_opt LPVOID /*lpData*/
116 )
117{
118 return PROGRESS_QUIET;
119}
diff --git a/src/burn/test/BurnUnitTest/ElevationTest.cpp b/src/burn/test/BurnUnitTest/ElevationTest.cpp
new file mode 100644
index 00000000..3d144128
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/ElevationTest.cpp
@@ -0,0 +1,221 @@
1// 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.
2
3#include "precomp.h"
4
5
6const DWORD TEST_CHILD_SENT_MESSAGE_ID = 0xFFFE;
7const DWORD TEST_PARENT_SENT_MESSAGE_ID = 0xFFFF;
8const HRESULT S_TEST_SUCCEEDED = 0x3133;
9const char TEST_MESSAGE_DATA[] = "{94949868-7EAE-4ac5-BEAC-AFCA2821DE01}";
10
11
12static BOOL STDAPICALLTYPE ElevateTest_ShellExecuteExW(
13 __inout LPSHELLEXECUTEINFOW lpExecInfo
14 );
15static DWORD CALLBACK ElevateTest_ThreadProc(
16 __in LPVOID lpThreadParameter
17 );
18static HRESULT ProcessParentMessages(
19 __in BURN_PIPE_MESSAGE* pMsg,
20 __in_opt LPVOID pvContext,
21 __out DWORD* pdwResult
22 );
23static HRESULT ProcessChildMessages(
24 __in BURN_PIPE_MESSAGE* pMsg,
25 __in_opt LPVOID pvContext,
26 __out DWORD* pdwResult
27 );
28
29namespace Microsoft
30{
31namespace Tools
32{
33namespace WindowsInstallerXml
34{
35namespace Test
36{
37namespace Bootstrapper
38{
39 using namespace System;
40 using namespace System::IO;
41 using namespace System::Threading;
42 using namespace Xunit;
43
44 public ref class ElevationTest : BurnUnitTest
45 {
46 public:
47 ElevationTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
48 {
49 }
50
51 [Fact]
52 void ElevateTest()
53 {
54 HRESULT hr = S_OK;
55 BURN_PIPE_CONNECTION connection = { };
56 HANDLE hEvent = NULL;
57 DWORD dwResult = S_OK;
58 try
59 {
60 ShelFunctionOverride(ElevateTest_ShellExecuteExW);
61
62 PipeConnectionInitialize(&connection);
63
64 //
65 // per-user side setup
66 //
67 hr = PipeCreateNameAndSecret(&connection.sczName, &connection.sczSecret);
68 TestThrowOnFailure(hr, L"Failed to create connection name and secret.");
69
70 hr = PipeCreatePipes(&connection, TRUE, &hEvent);
71 TestThrowOnFailure(hr, L"Failed to create pipes.");
72
73 hr = PipeLaunchChildProcess(L"tests\\ignore\\this\\path\\to\\burn.exe", &connection, TRUE, NULL);
74 TestThrowOnFailure(hr, L"Failed to create elevated process.");
75
76 hr = PipeWaitForChildConnect(&connection);
77 TestThrowOnFailure(hr, L"Failed to wait for child process to connect.");
78
79 // post execute message
80 hr = PipeSendMessage(connection.hPipe, TEST_PARENT_SENT_MESSAGE_ID, NULL, 0, ProcessParentMessages, NULL, &dwResult);
81 TestThrowOnFailure(hr, "Failed to post execute message to per-machine process.");
82
83 //
84 // initiate termination
85 //
86 hr = PipeTerminateChildProcess(&connection, 666, FALSE);
87 TestThrowOnFailure(hr, L"Failed to terminate elevated process.");
88
89 // check flags
90 Assert::Equal(S_TEST_SUCCEEDED, (HRESULT)dwResult);
91 }
92 finally
93 {
94 PipeConnectionUninitialize(&connection);
95 ReleaseHandle(hEvent);
96 }
97 }
98 };
99}
100}
101}
102}
103}
104
105
106static BOOL STDAPICALLTYPE ElevateTest_ShellExecuteExW(
107 __inout LPSHELLEXECUTEINFOW lpExecInfo
108 )
109{
110 HRESULT hr = S_OK;
111 LPWSTR scz = NULL;
112
113 hr = StrAllocString(&scz, lpExecInfo->lpParameters, 0);
114 ExitOnFailure(hr, "Failed to copy arguments.");
115
116 // Pretend this thread is the elevated process.
117 lpExecInfo->hProcess = ::CreateThread(NULL, 0, ElevateTest_ThreadProc, scz, 0, NULL);
118 ExitOnNullWithLastError(lpExecInfo->hProcess, hr, "Failed to create thread.");
119 scz = NULL;
120
121LExit:
122 ReleaseStr(scz);
123
124 return SUCCEEDED(hr);
125}
126
127static DWORD CALLBACK ElevateTest_ThreadProc(
128 __in LPVOID lpThreadParameter
129 )
130{
131 HRESULT hr = S_OK;
132 LPWSTR sczArguments = (LPWSTR)lpThreadParameter;
133 BURN_PIPE_CONNECTION connection = { };
134 BURN_PIPE_RESULT result = { };
135
136 PipeConnectionInitialize(&connection);
137
138 StrAlloc(&connection.sczName, MAX_PATH);
139 StrAlloc(&connection.sczSecret, MAX_PATH);
140
141 // parse command line arguments
142 if (3 != swscanf_s(sczArguments, L"-q -burn.elevated %s %s %u", connection.sczName, MAX_PATH, connection.sczSecret, MAX_PATH, &connection.dwProcessId))
143 {
144 hr = E_INVALIDARG;
145 ExitOnFailure(hr, "Failed to parse argument string.");
146 }
147
148 // set up connection with per-user process
149 hr = PipeChildConnect(&connection, TRUE);
150 ExitOnFailure(hr, "Failed to connect to per-user process.");
151
152 // pump messages
153 hr = PipePumpMessages(connection.hPipe, ProcessChildMessages, static_cast<LPVOID>(connection.hPipe), &result);
154 ExitOnFailure(hr, "Failed while pumping messages in child 'process'.");
155
156LExit:
157 PipeConnectionUninitialize(&connection);
158 ReleaseStr(sczArguments);
159
160 return FAILED(hr) ? (DWORD)hr : result.dwResult;
161}
162
163static HRESULT ProcessParentMessages(
164 __in BURN_PIPE_MESSAGE* pMsg,
165 __in_opt LPVOID /*pvContext*/,
166 __out DWORD* pdwResult
167 )
168{
169 HRESULT hr = S_OK;
170 HRESULT hrResult = E_INVALIDDATA;
171
172 // Process the message.
173 switch (pMsg->dwMessage)
174 {
175 case TEST_CHILD_SENT_MESSAGE_ID:
176 if (sizeof(TEST_MESSAGE_DATA) == pMsg->cbData && 0 == memcmp(TEST_MESSAGE_DATA, pMsg->pvData, sizeof(TEST_MESSAGE_DATA)))
177 {
178 hrResult = S_TEST_SUCCEEDED;
179 }
180 break;
181
182 default:
183 hr = E_INVALIDARG;
184 ExitOnRootFailure(hr, "Unexpected elevated message sent to parent process, msg: %u", pMsg->dwMessage);
185 }
186
187 *pdwResult = static_cast<DWORD>(hrResult);
188
189LExit:
190 return hr;
191}
192
193static HRESULT ProcessChildMessages(
194 __in BURN_PIPE_MESSAGE* pMsg,
195 __in_opt LPVOID pvContext,
196 __out DWORD* pdwResult
197 )
198{
199 HRESULT hr = S_OK;
200 HANDLE hPipe = static_cast<HANDLE>(pvContext);
201 DWORD dwResult = 0;
202
203 // Process the message.
204 switch (pMsg->dwMessage)
205 {
206 case TEST_PARENT_SENT_MESSAGE_ID:
207 // send test message
208 hr = PipeSendMessage(hPipe, TEST_CHILD_SENT_MESSAGE_ID, (LPVOID)TEST_MESSAGE_DATA, sizeof(TEST_MESSAGE_DATA), NULL, NULL, &dwResult);
209 ExitOnFailure(hr, "Failed to send message to per-machine process.");
210 break;
211
212 default:
213 hr = E_INVALIDARG;
214 ExitOnRootFailure(hr, "Unexpected elevated message sent to child process, msg: %u", pMsg->dwMessage);
215 }
216
217 *pdwResult = dwResult;
218
219LExit:
220 return hr;
221}
diff --git a/src/burn/test/BurnUnitTest/ManifestHelpers.cpp b/src/burn/test/BurnUnitTest/ManifestHelpers.cpp
new file mode 100644
index 00000000..96d5fab4
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/ManifestHelpers.cpp
@@ -0,0 +1,41 @@
1// 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.
2
3#include "precomp.h"
4
5
6using namespace System;
7using namespace Xunit;
8
9
10namespace Microsoft
11{
12namespace Tools
13{
14namespace WindowsInstallerXml
15{
16namespace Test
17{
18namespace Bootstrapper
19{
20 void LoadBundleXmlHelper(LPCWSTR wzDocument, IXMLDOMElement** ppixeBundle)
21 {
22 HRESULT hr = S_OK;
23 IXMLDOMDocument* pixdDocument = NULL;
24 try
25 {
26 hr = XmlLoadDocument(wzDocument, &pixdDocument);
27 TestThrowOnFailure(hr, L"Failed to load XML document.");
28
29 hr = pixdDocument->get_documentElement(ppixeBundle);
30 TestThrowOnFailure(hr, L"Failed to get bundle element.");
31 }
32 finally
33 {
34 ReleaseObject(pixdDocument);
35 }
36 }
37}
38}
39}
40}
41}
diff --git a/src/burn/test/BurnUnitTest/ManifestHelpers.h b/src/burn/test/BurnUnitTest/ManifestHelpers.h
new file mode 100644
index 00000000..e3e57555
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/ManifestHelpers.h
@@ -0,0 +1,24 @@
1#pragma once
2// 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.
3
4
5namespace Microsoft
6{
7namespace Tools
8{
9namespace WindowsInstallerXml
10{
11namespace Test
12{
13namespace Bootstrapper
14{
15
16
17void LoadBundleXmlHelper(LPCWSTR wzDocument, IXMLDOMElement** ppixeBundle);
18
19
20}
21}
22}
23}
24}
diff --git a/src/burn/test/BurnUnitTest/ManifestTest.cpp b/src/burn/test/BurnUnitTest/ManifestTest.cpp
new file mode 100644
index 00000000..963be156
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/ManifestTest.cpp
@@ -0,0 +1,62 @@
1// 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.
2
3#include "precomp.h"
4
5namespace Microsoft
6{
7namespace Tools
8{
9namespace WindowsInstallerXml
10{
11namespace Test
12{
13namespace Bootstrapper
14{
15 using namespace System;
16 using namespace Xunit;
17
18 public ref class ManifestTest : BurnUnitTest
19 {
20 public:
21 ManifestTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
22 {
23 }
24
25 [Fact]
26 void ManifestLoadXmlTest()
27 {
28 HRESULT hr = S_OK;
29 BURN_ENGINE_STATE engineState = { };
30 try
31 {
32 LPCSTR szDocument =
33 "<Bundle>"
34 " <UX UxDllPayloadId='ux.dll'>"
35 " <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
36 " </UX>"
37 " <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no' />"
38 " <Variable Id='Variable1' Type='numeric' Value='1' Hidden='no' Persisted='no' />"
39 " <RegistrySearch Id='Search1' Type='exists' Root='HKLM' Key='SOFTWARE\\Microsoft' Variable='Variable1' Condition='0' />"
40 "</Bundle>";
41
42 hr = VariableInitialize(&engineState.variables);
43 TestThrowOnFailure(hr, L"Failed to initialize variables.");
44
45 // load manifest from XML
46 hr = ManifestLoadXmlFromBuffer((BYTE*)szDocument, lstrlenA(szDocument), &engineState);
47 TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
48
49 // check variable values
50 Assert::True(VariableExistsHelper(&engineState.variables, L"Variable1"));
51 }
52 finally
53 {
54 //CoreUninitialize(&engineState);
55 }
56 }
57 };
58}
59}
60}
61}
62}
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp
new file mode 100644
index 00000000..a7c1d83c
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/PlanTest.cpp
@@ -0,0 +1,1473 @@
1// 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.
2
3#include "precomp.h"
4
5static HRESULT WINAPI PlanTestBAProc(
6 __in BOOTSTRAPPER_APPLICATION_MESSAGE message,
7 __in const LPVOID pvArgs,
8 __inout LPVOID pvResults,
9 __in_opt LPVOID pvContext
10 );
11
12static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml";
13static LPCWSTR wzSingleMsiManifestFileName = L"BasicFunctionality_BundleA_manifest.xml";
14static LPCWSTR wzSlipstreamManifestFileName = L"Slipstream_BundleA_manifest.xml";
15
16namespace Microsoft
17{
18namespace Tools
19{
20namespace WindowsInstallerXml
21{
22namespace Test
23{
24namespace Bootstrapper
25{
26 using namespace System;
27 using namespace Xunit;
28
29 public ref class PlanTest : BurnUnitTest
30 {
31 public:
32 PlanTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
33 {
34 }
35
36 [Fact]
37 void MsiTransactionInstallTest()
38 {
39 HRESULT hr = S_OK;
40 BURN_ENGINE_STATE engineState = { };
41 BURN_ENGINE_STATE* pEngineState = &engineState;
42 BURN_PLAN* pPlan = &engineState.plan;
43
44 InitializeEngineStateForCorePlan(wzMsiTransactionManifestFileName, pEngineState);
45 DetectPackagesAsAbsent(pEngineState);
46 DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"1.0.0.0");
47
48 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL);
49 NativeAssert::Succeeded(hr, "CorePlan failed");
50
51 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action);
52 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
53 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
54
55 BOOL fRollback = FALSE;
56 DWORD dwIndex = 0;
57 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
58 ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
59 ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
60 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 9);
61 ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB");
62 ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
63 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 14);
64 ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageC");
65 ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
66 Assert::Equal(dwIndex, pPlan->cCacheActions);
67
68 fRollback = TRUE;
69 dwIndex = 0;
70 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
71 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
72
73 Assert::Equal(107082ull, pPlan->qwEstimatedSize);
74 Assert::Equal(506145ull, pPlan->qwCacheSizeTotal);
75
76 fRollback = FALSE;
77 dwIndex = 0;
78 DWORD dwExecuteCheckpointId = 2;
79 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
80 ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[2].syncpoint.hEvent);
81 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
82 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
83 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER);
84 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
85 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
86 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
87 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_REGISTER);
88 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
89 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
90 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE);
91 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
92 ValidateExecuteBeginMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ");
93 ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[5].syncpoint.hEvent);
94 dwExecuteCheckpointId += 1; // cache checkpoints
95 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
96 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
97 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_REGISTER);
98 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
99 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
100 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_REGISTER);
101 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
102 ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[8].syncpoint.hEvent);
103 dwExecuteCheckpointId += 1; // cache checkpoints
104 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
105 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
106 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_REGISTER);
107 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
108 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
109 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_REGISTER);
110 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
111 ValidateExecuteCommitMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ");
112 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
113 ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL);
114 Assert::Equal(dwIndex, pPlan->cExecuteActions);
115
116 fRollback = TRUE;
117 dwIndex = 0;
118 dwExecuteCheckpointId = 2;
119 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
120 ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
121 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
122 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
123 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
124 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
125 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
126 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_UNREGISTER);
127 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
128 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
129 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
130 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE);
131 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
132 ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageB");
133 dwExecuteCheckpointId += 1; // cache checkpoints
134 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
135 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_UNREGISTER);
136 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
137 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_UNREGISTER);
138 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
139 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
140 ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageC");
141 dwExecuteCheckpointId += 1; // cache checkpoints
142 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
143 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_UNREGISTER);
144 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
145 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_UNREGISTER);
146 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
147 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
148 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
149 ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL);
150 Assert::Equal(dwIndex, pPlan->cRollbackActions);
151
152 Assert::Equal(4ul, pPlan->cExecutePackagesTotal);
153 Assert::Equal(7ul, pPlan->cOverallProgressTicksTotal);
154
155 dwIndex = 0;
156 Assert::Equal(dwIndex, pPlan->cCleanActions);
157
158 UINT uIndex = 0;
159 ValidatePlannedProvider(pPlan, uIndex++, L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", NULL);
160 Assert::Equal(uIndex, pPlan->cPlannedProviders);
161
162 Assert::Equal(3ul, pEngineState->packages.cPackages);
163 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
164 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageB", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
165 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PackageC", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
166 }
167
168 [Fact]
169 void MsiTransactionUninstallTest()
170 {
171 HRESULT hr = S_OK;
172 BURN_ENGINE_STATE engineState = { };
173 BURN_ENGINE_STATE* pEngineState = &engineState;
174 BURN_PLAN* pPlan = &engineState.plan;
175
176 InitializeEngineStateForCorePlan(wzMsiTransactionManifestFileName, pEngineState);
177 DetectPackagesAsPresentAndCached(pEngineState);
178
179 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL);
180 NativeAssert::Succeeded(hr, "CorePlan failed");
181
182 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action);
183 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
184 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
185
186 BOOL fRollback = FALSE;
187 DWORD dwIndex = 0;
188 Assert::Equal(dwIndex, pPlan->cCacheActions);
189
190 fRollback = TRUE;
191 dwIndex = 0;
192 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
193
194 Assert::Equal(0ull, pPlan->qwEstimatedSize);
195 Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
196
197 fRollback = FALSE;
198 dwIndex = 0;
199 DWORD dwExecuteCheckpointId = 1;
200 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE);
201 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
202 ValidateExecuteBeginMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ");
203 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
204 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_UNREGISTER);
205 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
206 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_UNREGISTER);
207 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
208 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
209 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
210 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_UNREGISTER);
211 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
212 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_UNREGISTER);
213 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
214 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
215 ValidateExecuteCommitMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ");
216 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
217 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
218 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
219 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_UNREGISTER);
220 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
221 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
222 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
223 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
224 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
225 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
226 Assert::Equal(dwIndex, pPlan->cExecuteActions);
227
228 fRollback = TRUE;
229 dwIndex = 0;
230 dwExecuteCheckpointId = 1;
231 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE);
232 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
233 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_REGISTER);
234 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
235 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_REGISTER);
236 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
237 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
238 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_REGISTER);
239 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
240 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_REGISTER);
241 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
242 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
243 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
244 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
245 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", BURN_DEPENDENCY_ACTION_REGISTER);
246 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
247 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER);
248 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
249 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
250 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
251 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
252 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
253 Assert::Equal(dwIndex, pPlan->cRollbackActions);
254
255 Assert::Equal(3ul, pPlan->cExecutePackagesTotal);
256 Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal);
257
258 dwIndex = 0;
259 ValidateCleanAction(pPlan, dwIndex++, L"PackageC");
260 ValidateCleanAction(pPlan, dwIndex++, L"PackageB");
261 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
262 Assert::Equal(dwIndex, pPlan->cCleanActions);
263
264 UINT uIndex = 0;
265 ValidatePlannedProvider(pPlan, uIndex++, L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", NULL);
266 ValidatePlannedProvider(pPlan, uIndex++, L"{A497C5E5-C78B-4F0B-BF72-B33E1DB1C4B8}", NULL);
267 ValidatePlannedProvider(pPlan, uIndex++, L"{D1D01094-23CE-4AF0-84B6-4A1A133F21D3}", NULL);
268 ValidatePlannedProvider(pPlan, uIndex++, L"{01E6B748-7B95-4BA9-976D-B6F35076CEF4}", NULL);
269 Assert::Equal(uIndex, pPlan->cPlannedProviders);
270
271 Assert::Equal(3ul, pEngineState->packages.cPackages);
272 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
273 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageB", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
274 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PackageC", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
275 }
276
277 [Fact]
278 void RelatedBundleMissingFromCacheTest()
279 {
280 HRESULT hr = S_OK;
281 BURN_ENGINE_STATE engineState = { };
282 BURN_ENGINE_STATE* pEngineState = &engineState;
283 BURN_PLAN* pPlan = &engineState.plan;
284
285 InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
286 DetectAttachedContainerAsAttached(pEngineState);
287 DetectPackagesAsAbsent(pEngineState);
288 BURN_RELATED_BUNDLE* pRelatedBundle = DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0");
289 pRelatedBundle->fPlannable = FALSE;
290
291 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL);
292 NativeAssert::Succeeded(hr, "CorePlan failed");
293
294 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action);
295 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
296 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
297
298 BOOL fRollback = FALSE;
299 DWORD dwIndex = 0;
300 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
301 ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
302 ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
303 Assert::Equal(dwIndex, pPlan->cCacheActions);
304
305 fRollback = TRUE;
306 dwIndex = 0;
307 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
308 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
309
310 Assert::Equal(35694ull, pPlan->qwEstimatedSize);
311 Assert::Equal(168715ull, pPlan->qwCacheSizeTotal);
312
313 fRollback = FALSE;
314 dwIndex = 0;
315 DWORD dwExecuteCheckpointId = 2;
316 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
317 ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[2].syncpoint.hEvent);
318 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
319 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
320 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER);
321 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
322 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
323 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
324 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_REGISTER);
325 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
326 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
327 Assert::Equal(dwIndex, pPlan->cExecuteActions);
328
329 fRollback = TRUE;
330 dwIndex = 0;
331 dwExecuteCheckpointId = 2;
332 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
333 ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
334 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
335 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
336 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
337 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
338 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
339 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_UNREGISTER);
340 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
341 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
342 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
343 Assert::Equal(dwIndex, pPlan->cRollbackActions);
344
345 Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
346 Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
347
348 dwIndex = 0;
349 Assert::Equal(dwIndex, pPlan->cCleanActions);
350
351 UINT uIndex = 0;
352 ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
353 Assert::Equal(uIndex, pPlan->cPlannedProviders);
354
355 Assert::Equal(1ul, pEngineState->packages.cPackages);
356 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
357 }
358
359 [Fact]
360 void SingleMsiCacheTest()
361 {
362 HRESULT hr = S_OK;
363 BURN_ENGINE_STATE engineState = { };
364 BURN_ENGINE_STATE* pEngineState = &engineState;
365 BURN_PLAN* pPlan = &engineState.plan;
366
367 InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
368 DetectAttachedContainerAsAttached(pEngineState);
369 DetectPackagesAsAbsent(pEngineState);
370 DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0");
371
372 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_CACHE);
373 NativeAssert::Succeeded(hr, "CorePlan failed");
374
375 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_CACHE, pPlan->action);
376 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
377 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
378
379 BOOL fRollback = FALSE;
380 DWORD dwIndex = 0;
381 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
382 ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
383 ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
384 Assert::Equal(dwIndex, pPlan->cCacheActions);
385
386 fRollback = TRUE;
387 dwIndex = 0;
388 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
389
390 Assert::Equal(33743ull, pPlan->qwEstimatedSize);
391 Assert::Equal(168715ull, pPlan->qwCacheSizeTotal);
392
393 fRollback = FALSE;
394 dwIndex = 0;
395 DWORD dwExecuteCheckpointId = 2;
396 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
397 ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[2].syncpoint.hEvent);
398 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
399 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
400 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
401 Assert::Equal(dwIndex, pPlan->cExecuteActions);
402
403 fRollback = TRUE;
404 dwIndex = 0;
405 dwExecuteCheckpointId = 2;
406 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
407 ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
408 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
409 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
410 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
411 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
412 Assert::Equal(dwIndex, pPlan->cRollbackActions);
413
414 Assert::Equal(0ul, pPlan->cExecutePackagesTotal);
415 Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
416
417 dwIndex = 0;
418 Assert::Equal(dwIndex, pPlan->cCleanActions);
419
420 UINT uIndex = 0;
421 ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
422 Assert::Equal(uIndex, pPlan->cPlannedProviders);
423
424 Assert::Equal(1ul, pEngineState->packages.cPackages);
425 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
426 }
427
428 [Fact]
429 void SingleMsiInstallTest()
430 {
431 HRESULT hr = S_OK;
432 BURN_ENGINE_STATE engineState = { };
433 BURN_ENGINE_STATE* pEngineState = &engineState;
434 BURN_PLAN* pPlan = &engineState.plan;
435
436 InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
437 DetectAttachedContainerAsAttached(pEngineState);
438 DetectPackagesAsAbsent(pEngineState);
439 DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0");
440
441 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL);
442 NativeAssert::Succeeded(hr, "CorePlan failed");
443
444 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action);
445 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
446 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
447
448 BOOL fRollback = FALSE;
449 DWORD dwIndex = 0;
450 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
451 ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
452 ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
453 Assert::Equal(dwIndex, pPlan->cCacheActions);
454
455 fRollback = TRUE;
456 dwIndex = 0;
457 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
458 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
459
460 Assert::Equal(35694ull, pPlan->qwEstimatedSize);
461 Assert::Equal(168715ull, pPlan->qwCacheSizeTotal);
462
463 fRollback = FALSE;
464 dwIndex = 0;
465 DWORD dwExecuteCheckpointId = 2;
466 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
467 ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[2].syncpoint.hEvent);
468 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
469 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
470 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER);
471 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
472 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
473 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
474 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_REGISTER);
475 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
476 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
477 ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL);
478 Assert::Equal(dwIndex, pPlan->cExecuteActions);
479
480 fRollback = TRUE;
481 dwIndex = 0;
482 dwExecuteCheckpointId = 2;
483 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
484 ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
485 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
486 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
487 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
488 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
489 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
490 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_UNREGISTER);
491 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
492 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
493 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
494 ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL);
495 Assert::Equal(dwIndex, pPlan->cRollbackActions);
496
497 Assert::Equal(2ul, pPlan->cExecutePackagesTotal);
498 Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal);
499
500 dwIndex = 0;
501 Assert::Equal(dwIndex, pPlan->cCleanActions);
502
503 UINT uIndex = 0;
504 ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
505 Assert::Equal(uIndex, pPlan->cPlannedProviders);
506
507 Assert::Equal(1ul, pEngineState->packages.cPackages);
508 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
509 }
510
511 [Fact]
512 void SingleMsiInstalledWithNoInstalledPackagesModifyTest()
513 {
514 HRESULT hr = S_OK;
515 BURN_ENGINE_STATE engineState = { };
516 BURN_ENGINE_STATE* pEngineState = &engineState;
517 BURN_PLAN* pPlan = &engineState.plan;
518
519 InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
520 DetectPackagesAsAbsent(pEngineState);
521
522 pEngineState->registration.fInstalled = TRUE;
523
524 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_MODIFY);
525 NativeAssert::Succeeded(hr, "CorePlan failed");
526
527 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_MODIFY, pPlan->action);
528 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
529 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
530
531 BOOL fRollback = FALSE;
532 DWORD dwIndex = 0;
533 Assert::Equal(dwIndex, pPlan->cCacheActions);
534
535 fRollback = TRUE;
536 dwIndex = 0;
537 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
538
539 Assert::Equal(0ull, pPlan->qwEstimatedSize);
540 Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
541
542 fRollback = FALSE;
543 dwIndex = 0;
544 DWORD dwExecuteCheckpointId = 1;
545 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
546 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
547 Assert::Equal(dwIndex, pPlan->cExecuteActions);
548
549 fRollback = TRUE;
550 dwIndex = 0;
551 dwExecuteCheckpointId = 1;
552 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
553 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
554 Assert::Equal(dwIndex, pPlan->cRollbackActions);
555
556 Assert::Equal(0ul, pPlan->cExecutePackagesTotal);
557 Assert::Equal(0ul, pPlan->cOverallProgressTicksTotal);
558
559 dwIndex = 0;
560 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
561 Assert::Equal(dwIndex, pPlan->cCleanActions);
562
563 UINT uIndex = 0;
564 ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
565 Assert::Equal(uIndex, pPlan->cPlannedProviders);
566
567 Assert::Equal(1ul, pEngineState->packages.cPackages);
568 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
569 }
570
571 [Fact]
572 void SingleMsiUninstallTest()
573 {
574 HRESULT hr = S_OK;
575 BURN_ENGINE_STATE engineState = { };
576 BURN_ENGINE_STATE* pEngineState = &engineState;
577 BURN_PLAN* pPlan = &engineState.plan;
578
579 InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
580 DetectPackagesAsPresentAndCached(pEngineState);
581
582 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL);
583 NativeAssert::Succeeded(hr, "CorePlan failed");
584
585 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action);
586 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
587 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
588
589 BOOL fRollback = FALSE;
590 DWORD dwIndex = 0;
591 Assert::Equal(dwIndex, pPlan->cCacheActions);
592
593 fRollback = TRUE;
594 dwIndex = 0;
595 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
596
597 Assert::Equal(0ull, pPlan->qwEstimatedSize);
598 Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
599
600 fRollback = FALSE;
601 dwIndex = 0;
602 DWORD dwExecuteCheckpointId = 1;
603 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
604 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
605 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_UNREGISTER);
606 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
607 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
608 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
609 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
610 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
611 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
612 Assert::Equal(dwIndex, pPlan->cExecuteActions);
613
614 fRollback = TRUE;
615 dwIndex = 0;
616 dwExecuteCheckpointId = 1;
617 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
618 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_REGISTER);
619 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
620 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER);
621 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
622 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
623 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
624 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
625 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
626 Assert::Equal(dwIndex, pPlan->cRollbackActions);
627
628 Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
629 Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
630
631 dwIndex = 0;
632 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
633 Assert::Equal(dwIndex, pPlan->cCleanActions);
634
635 UINT uIndex = 0;
636 ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
637 ValidatePlannedProvider(pPlan, uIndex++, L"{64633047-D172-4BBB-B202-64337D15C952}", NULL);
638 Assert::Equal(uIndex, pPlan->cPlannedProviders);
639
640 Assert::Equal(1ul, pEngineState->packages.cPackages);
641 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
642 }
643
644 [Fact]
645 void SingleMsiUninstallTestFromUpgradeBundleWithSameExactPackage()
646 {
647 HRESULT hr = S_OK;
648 BURN_ENGINE_STATE engineState = { };
649 BURN_ENGINE_STATE* pEngineState = &engineState;
650 BURN_PLAN* pPlan = &engineState.plan;
651
652 InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
653 DetectAsRelatedUpgradeBundle(&engineState, L"{02940F3E-C83E-452D-BFCF-C943777ACEAE}", L"2.0.0.0");
654
655 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL);
656 NativeAssert::Succeeded(hr, "CorePlan failed");
657
658 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action);
659 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
660 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
661
662 BOOL fRollback = FALSE;
663 DWORD dwIndex = 0;
664 Assert::Equal(dwIndex, pPlan->cCacheActions);
665
666 fRollback = TRUE;
667 dwIndex = 0;
668 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
669
670 Assert::Equal(0ull, pPlan->qwEstimatedSize);
671 Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
672
673 fRollback = FALSE;
674 dwIndex = 0;
675 DWORD dwExecuteCheckpointId = 1;
676 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
677 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
678 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_UNREGISTER);
679 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
680 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
681 Assert::Equal(dwIndex, pPlan->cExecuteActions);
682
683 fRollback = TRUE;
684 dwIndex = 0;
685 dwExecuteCheckpointId = 1;
686 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
687 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_REGISTER);
688 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
689 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
690 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
691 Assert::Equal(dwIndex, pPlan->cRollbackActions);
692
693 Assert::Equal(0ul, pPlan->cExecutePackagesTotal);
694 Assert::Equal(0ul, pPlan->cOverallProgressTicksTotal);
695
696 dwIndex = 0;
697 Assert::Equal(dwIndex, pPlan->cCleanActions);
698
699 UINT uIndex = 0;
700 ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
701 Assert::Equal(uIndex, pPlan->cPlannedProviders);
702
703 Assert::Equal(1ul, pEngineState->packages.cPackages);
704 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_IGNORED, BURN_PACKAGE_REGISTRATION_STATE_IGNORED);
705 }
706
707 [Fact]
708 void SlipstreamInstallTest()
709 {
710 HRESULT hr = S_OK;
711 BURN_ENGINE_STATE engineState = { };
712 BURN_ENGINE_STATE* pEngineState = &engineState;
713 BURN_PLAN* pPlan = &engineState.plan;
714
715 InitializeEngineStateForCorePlan(wzSlipstreamManifestFileName, pEngineState);
716 DetectPermanentPackagesAsPresentAndCached(pEngineState);
717 PlanTestDetectPatchInitialize(pEngineState);
718
719 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL);
720 NativeAssert::Succeeded(hr, "CorePlan failed");
721
722 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action);
723 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
724 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
725
726 BOOL fRollback = FALSE;
727 DWORD dwIndex = 0;
728 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
729 ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PatchA");
730 ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
731 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 2);
732 ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
733 ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
734 Assert::Equal(dwIndex, pPlan->cCacheActions);
735
736 fRollback = TRUE;
737 dwIndex = 0;
738 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 2);
739 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
740
741 Assert::Equal(3055111ull, pPlan->qwEstimatedSize);
742 Assert::Equal(212992ull, pPlan->qwCacheSizeTotal);
743
744 fRollback = FALSE;
745 dwIndex = 0;
746 DWORD dwExecuteCheckpointId = 3;
747 BURN_EXECUTE_ACTION* pExecuteAction = NULL;
748 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
749 ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[5].syncpoint.hEvent);
750 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
751 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
752 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER);
753 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
754 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
755 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
756 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_REGISTER);
757 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
758 ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[2].syncpoint.hEvent);
759 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
760 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
761 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", BURN_DEPENDENCY_ACTION_REGISTER);
762 pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_INSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, TRUE);
763 ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA");
764 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
765 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_REGISTER);
766 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
767 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
768 Assert::Equal(dwIndex, pPlan->cExecuteActions);
769
770 fRollback = TRUE;
771 dwIndex = 0;
772 dwExecuteCheckpointId = 3;
773 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
774 ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
775 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
776 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
777 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
778 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
779 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
780 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_UNREGISTER);
781 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
782 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
783 ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PatchA");
784 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
785 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", BURN_DEPENDENCY_ACTION_UNREGISTER);
786 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
787 pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, TRUE);
788 ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA");
789 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_UNREGISTER);
790 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
791 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
792 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
793 Assert::Equal(dwIndex, pPlan->cRollbackActions);
794
795 Assert::Equal(2ul, pPlan->cExecutePackagesTotal);
796 Assert::Equal(4ul, pPlan->cOverallProgressTicksTotal);
797
798 dwIndex = 0;
799 Assert::Equal(dwIndex, pPlan->cCleanActions);
800
801 UINT uIndex = 0;
802 ValidatePlannedProvider(pPlan, uIndex++, L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", NULL);
803 Assert::Equal(uIndex, pPlan->cPlannedProviders);
804
805 Assert::Equal(3ul, pEngineState->packages.cPackages);
806 ValidatePermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"NetFx48Web");
807 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
808 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PatchA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
809 }
810
811 [Fact]
812 void SlipstreamUninstallTest()
813 {
814 HRESULT hr = S_OK;
815 BURN_ENGINE_STATE engineState = { };
816 BURN_ENGINE_STATE* pEngineState = &engineState;
817 BURN_PLAN* pPlan = &engineState.plan;
818
819 InitializeEngineStateForCorePlan(wzSlipstreamManifestFileName, pEngineState);
820 DetectPackagesAsPresentAndCached(pEngineState);
821
822 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL);
823 NativeAssert::Succeeded(hr, "CorePlan failed");
824
825 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action);
826 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
827 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
828
829 BOOL fRollback = FALSE;
830 DWORD dwIndex = 0;
831 Assert::Equal(dwIndex, pPlan->cCacheActions);
832
833 fRollback = TRUE;
834 dwIndex = 0;
835 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
836
837 Assert::Equal(0ull, pPlan->qwEstimatedSize);
838 Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
839
840 fRollback = FALSE;
841 dwIndex = 0;
842 DWORD dwExecuteCheckpointId = 1;
843 BURN_EXECUTE_ACTION* pExecuteAction = NULL;
844 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
845 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
846 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_UNREGISTER);
847 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
848 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", BURN_DEPENDENCY_ACTION_UNREGISTER);
849 pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, TRUE);
850 ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA");
851 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
852 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
853 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_UNREGISTER);
854 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
855 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
856 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
857 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
858 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
859 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
860 Assert::Equal(dwIndex, pPlan->cExecuteActions);
861
862 fRollback = TRUE;
863 dwIndex = 0;
864 dwExecuteCheckpointId = 1;
865 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
866 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_REGISTER);
867 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
868 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", BURN_DEPENDENCY_ACTION_REGISTER);
869 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
870 pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_INSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, TRUE);
871 ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA");
872 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
873 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_REGISTER);
874 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
875 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER);
876 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
877 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
878 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
879 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
880 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
881 Assert::Equal(dwIndex, pPlan->cRollbackActions);
882
883 Assert::Equal(2ul, pPlan->cExecutePackagesTotal);
884 Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
885
886 dwIndex = 0;
887 ValidateCleanAction(pPlan, dwIndex++, L"PatchA");
888 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
889 Assert::Equal(dwIndex, pPlan->cCleanActions);
890
891 UINT uIndex = 0;
892 ValidatePlannedProvider(pPlan, uIndex++, L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", NULL);
893 ValidatePlannedProvider(pPlan, uIndex++, L"{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}", NULL);
894 ValidatePlannedProvider(pPlan, uIndex++, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", NULL);
895 Assert::Equal(uIndex, pPlan->cPlannedProviders);
896
897 Assert::Equal(3ul, pEngineState->packages.cPackages);
898 ValidatePermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"NetFx48Web");
899 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
900 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PatchA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
901 }
902
903 private:
904 // This doesn't initialize everything, just enough for CorePlan to work.
905 void InitializeEngineStateForCorePlan(LPCWSTR wzManifestFileName, BURN_ENGINE_STATE* pEngineState)
906 {
907 HRESULT hr = S_OK;
908 LPWSTR sczFilePath = NULL;
909
910 ::InitializeCriticalSection(&pEngineState->userExperience.csEngineActive);
911
912 hr = VariableInitialize(&pEngineState->variables);
913 NativeAssert::Succeeded(hr, "Failed to initialize variables.");
914
915 try
916 {
917 pin_ptr<const wchar_t> dataDirectory = PtrToStringChars(this->TestContext->TestDirectory);
918 hr = PathConcat(dataDirectory, L"TestData\\PlanTest", &sczFilePath);
919 NativeAssert::Succeeded(hr, "Failed to get path to test file directory.");
920 hr = PathConcat(sczFilePath, wzManifestFileName, &sczFilePath);
921 NativeAssert::Succeeded(hr, "Failed to get path to test file.");
922 Assert::True(FileExistsEx(sczFilePath, NULL), "Test file does not exist.");
923
924 hr = ManifestLoadXmlFromFile(sczFilePath, pEngineState);
925 NativeAssert::Succeeded(hr, "Failed to load manifest.");
926 }
927 finally
928 {
929 ReleaseStr(sczFilePath);
930 }
931
932 hr = CoreInitializeConstants(pEngineState);
933 NativeAssert::Succeeded(hr, "Failed to initialize core constants");
934
935 pEngineState->userExperience.pfnBAProc = PlanTestBAProc;
936 }
937
938 void PlanTestDetect(BURN_ENGINE_STATE* pEngineState)
939 {
940 HRESULT hr = S_OK;
941 BURN_REGISTRATION* pRegistration = &pEngineState->registration;
942
943 DetectReset(pRegistration, &pEngineState->packages);
944 PlanReset(&pEngineState->plan, &pEngineState->containers, &pEngineState->packages, &pEngineState->layoutPayloads);
945
946 hr = DepDependencyArrayAlloc(&pRegistration->rgIgnoredDependencies, &pRegistration->cIgnoredDependencies, pRegistration->sczProviderKey, NULL);
947 NativeAssert::Succeeded(hr, "Failed to add the bundle provider key to the list of dependencies to ignore.");
948
949 pEngineState->userExperience.fEngineActive = TRUE;
950 pEngineState->fDetected = TRUE;
951 }
952
953 void PlanTestDetectPatchInitialize(BURN_ENGINE_STATE* pEngineState)
954 {
955 HRESULT hr = MsiEngineDetectInitialize(&pEngineState->packages);
956 NativeAssert::Succeeded(hr, "MsiEngineDetectInitialize failed");
957
958 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i)
959 {
960 BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i;
961
962 if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
963 {
964 for (DWORD j = 0; j < pPackage->Msp.cTargetProductCodes; ++j)
965 {
966 BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + j;
967
968 if (BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN == pTargetProduct->patchPackageState)
969 {
970 pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
971 }
972 }
973 }
974 }
975 }
976
977 void DetectAttachedContainerAsAttached(BURN_ENGINE_STATE* pEngineState)
978 {
979 for (DWORD i = 0; i < pEngineState->containers.cContainers; ++i)
980 {
981 BURN_CONTAINER* pContainer = pEngineState->containers.rgContainers + i;
982 if (pContainer->fAttached)
983 {
984 pContainer->fActuallyAttached = TRUE;
985 }
986 }
987 }
988
989 void DetectPackageAsAbsent(BURN_PACKAGE* pPackage)
990 {
991 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
992 if (pPackage->fCanAffectRegistration)
993 {
994 pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
995 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
996 }
997 }
998
999 void DetectPackageAsPresentAndCached(BURN_PACKAGE* pPackage)
1000 {
1001 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT;
1002 pPackage->fCached = TRUE;
1003 if (pPackage->fCanAffectRegistration)
1004 {
1005 pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
1006 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
1007 }
1008 }
1009
1010 void DetectPackageDependent(BURN_PACKAGE* pPackage, LPCWSTR wzId)
1011 {
1012 HRESULT hr = S_OK;
1013
1014 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
1015 {
1016 BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders + i;
1017
1018 hr = DepDependencyArrayAlloc(&pProvider->rgDependents, &pProvider->cDependents, wzId, NULL);
1019 NativeAssert::Succeeded(hr, "Failed to add package dependent");
1020 }
1021 }
1022
1023 void DetectPackagesAsAbsent(BURN_ENGINE_STATE* pEngineState)
1024 {
1025 PlanTestDetect(pEngineState);
1026
1027 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i)
1028 {
1029 BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i;
1030 DetectPackageAsAbsent(pPackage);
1031 }
1032 }
1033
1034 void DetectPackagesAsPresentAndCached(BURN_ENGINE_STATE* pEngineState)
1035 {
1036 PlanTestDetect(pEngineState);
1037
1038 pEngineState->registration.fInstalled = TRUE;
1039
1040 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i)
1041 {
1042 BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i;
1043 DetectPackageAsPresentAndCached(pPackage);
1044 DetectPackageDependent(pPackage, pEngineState->registration.sczId);
1045
1046 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
1047 {
1048 for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j)
1049 {
1050 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED;
1051
1052 BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[j].pMspPackage;
1053 MspEngineAddDetectedTargetProduct(&pEngineState->packages, pMspPackage, j, pPackage->Msi.sczProductCode, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED);
1054
1055 BURN_MSPTARGETPRODUCT* pTargetProduct = pMspPackage->Msp.rgTargetProducts + (pMspPackage->Msp.cTargetProductCodes - 1);
1056 pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT;
1057 pTargetProduct->registrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
1058 }
1059 }
1060 }
1061 }
1062
1063 void DetectPermanentPackagesAsPresentAndCached(BURN_ENGINE_STATE* pEngineState)
1064 {
1065 PlanTestDetect(pEngineState);
1066
1067 pEngineState->registration.fInstalled = TRUE;
1068
1069 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i)
1070 {
1071 BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i;
1072 if (pPackage->fUninstallable)
1073 {
1074 DetectPackageAsAbsent(pPackage);
1075 }
1076 else
1077 {
1078 DetectPackageAsPresentAndCached(pPackage);
1079 DetectPackageDependent(pPackage, pEngineState->registration.sczId);
1080 }
1081 }
1082 }
1083
1084 BURN_RELATED_BUNDLE* DetectUpgradeBundle(
1085 __in BURN_ENGINE_STATE* pEngineState,
1086 __in LPCWSTR wzId,
1087 __in LPCWSTR wzVersion
1088 )
1089 {
1090 HRESULT hr = S_OK;
1091 BURN_RELATED_BUNDLES* pRelatedBundles = &pEngineState->registration.relatedBundles;
1092 BURN_DEPENDENCY_PROVIDER dependencyProvider = { };
1093
1094 hr = StrAllocString(&dependencyProvider.sczKey, wzId, 0);
1095 NativeAssert::Succeeded(hr, "Failed to copy provider key");
1096
1097 dependencyProvider.fImported = TRUE;
1098
1099 hr = StrAllocString(&dependencyProvider.sczVersion, wzVersion, 0);
1100 NativeAssert::Succeeded(hr, "Failed to copy version");
1101
1102 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRelatedBundles->rgRelatedBundles), pRelatedBundles->cRelatedBundles + 1, sizeof(BURN_RELATED_BUNDLE), 5);
1103 NativeAssert::Succeeded(hr, "Failed to ensure there is space for related bundles.");
1104
1105 BURN_RELATED_BUNDLE* pRelatedBundle = pRelatedBundles->rgRelatedBundles + pRelatedBundles->cRelatedBundles;
1106
1107 hr = VerParseVersion(wzVersion, 0, FALSE, &pRelatedBundle->pVersion);
1108 NativeAssert::Succeeded(hr, "Failed to parse pseudo bundle version: %ls", wzVersion);
1109
1110 pRelatedBundle->fPlannable = TRUE;
1111 pRelatedBundle->relationType = BOOTSTRAPPER_RELATION_UPGRADE;
1112
1113 hr = PseudoBundleInitialize(0, &pRelatedBundle->package, TRUE, wzId, pRelatedBundle->relationType, BOOTSTRAPPER_PACKAGE_STATE_PRESENT, TRUE, NULL, NULL, NULL, 0, FALSE, L"-quiet", L"-repair -quiet", L"-uninstall -quiet", &dependencyProvider, NULL, 0);
1114 NativeAssert::Succeeded(hr, "Failed to initialize related bundle to represent bundle: %ls", wzId);
1115
1116 ++pRelatedBundles->cRelatedBundles;
1117
1118 return pRelatedBundle;
1119 }
1120
1121 void DetectAsRelatedUpgradeBundle(
1122 __in BURN_ENGINE_STATE* pEngineState,
1123 __in LPCWSTR wzId,
1124 __in LPCWSTR wzVersion
1125 )
1126 {
1127 HRESULT hr = StrAllocString(&pEngineState->registration.sczAncestors, wzId, 0);
1128 NativeAssert::Succeeded(hr, "Failed to set registration's ancestors");
1129
1130 pEngineState->command.relationType = BOOTSTRAPPER_RELATION_UPGRADE;
1131
1132 DetectPackagesAsPresentAndCached(pEngineState);
1133 DetectUpgradeBundle(pEngineState, wzId, wzVersion);
1134
1135 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i)
1136 {
1137 BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i;
1138 DetectPackageDependent(pPackage, wzId);
1139 }
1140 }
1141
1142 void ValidateCacheContainer(
1143 __in BURN_PLAN* pPlan,
1144 __in BOOL fRollback,
1145 __in DWORD dwIndex,
1146 __in LPCWSTR wzContainerId
1147 )
1148 {
1149 BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex);
1150 Assert::Equal<DWORD>(BURN_CACHE_ACTION_TYPE_CONTAINER, pAction->type);
1151 NativeAssert::StringEqual(wzContainerId, pAction->container.pContainer->sczId);
1152 }
1153
1154 BURN_CACHE_ACTION* ValidateCacheActionExists(BURN_PLAN* pPlan, BOOL fRollback, DWORD dwIndex)
1155 {
1156 Assert::InRange(dwIndex + 1ul, 1ul, (fRollback ? pPlan->cRollbackCacheActions : pPlan->cCacheActions));
1157 return (fRollback ? pPlan->rgRollbackCacheActions : pPlan->rgCacheActions) + dwIndex;
1158 }
1159
1160 void ValidateCacheCheckpoint(
1161 __in BURN_PLAN* pPlan,
1162 __in BOOL fRollback,
1163 __in DWORD dwIndex,
1164 __in DWORD dwId
1165 )
1166 {
1167 BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex);
1168 Assert::Equal<DWORD>(BURN_CACHE_ACTION_TYPE_CHECKPOINT, pAction->type);
1169 Assert::Equal(dwId, pAction->checkpoint.dwId);
1170 }
1171
1172 DWORD ValidateCachePackage(
1173 __in BURN_PLAN* pPlan,
1174 __in BOOL fRollback,
1175 __in DWORD dwIndex,
1176 __in LPCWSTR wzPackageId
1177 )
1178 {
1179 BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex);
1180 Assert::Equal<DWORD>(BURN_CACHE_ACTION_TYPE_PACKAGE, pAction->type);
1181 NativeAssert::StringEqual(wzPackageId, pAction->package.pPackage->sczId);
1182 return dwIndex + 1;
1183 }
1184
1185 void ValidateCacheRollbackPackage(
1186 __in BURN_PLAN* pPlan,
1187 __in BOOL fRollback,
1188 __in DWORD dwIndex,
1189 __in LPCWSTR wzPackageId
1190 )
1191 {
1192 BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex);
1193 Assert::Equal<DWORD>(BURN_CACHE_ACTION_TYPE_ROLLBACK_PACKAGE, pAction->type);
1194 NativeAssert::StringEqual(wzPackageId, pAction->rollbackPackage.pPackage->sczId);
1195 }
1196
1197 void ValidateCacheSignalSyncpoint(
1198 __in BURN_PLAN* pPlan,
1199 __in BOOL fRollback,
1200 __in DWORD dwIndex
1201 )
1202 {
1203 BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex);
1204 Assert::Equal<DWORD>(BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT, pAction->type);
1205 Assert::NotEqual((DWORD_PTR)NULL, (DWORD_PTR)pAction->syncpoint.hEvent);
1206 }
1207
1208 void ValidateCleanAction(
1209 __in BURN_PLAN* pPlan,
1210 __in DWORD dwIndex,
1211 __in LPCWSTR wzPackageId
1212 )
1213 {
1214 Assert::InRange(dwIndex + 1ul, 1ul, pPlan->cCleanActions);
1215
1216 BURN_CLEAN_ACTION* pCleanAction = pPlan->rgCleanActions + dwIndex;
1217 Assert::NotEqual((DWORD_PTR)0, (DWORD_PTR)pCleanAction->pPackage);
1218 NativeAssert::StringEqual(wzPackageId, pCleanAction->pPackage->sczId);
1219 }
1220
1221 BURN_EXECUTE_ACTION* ValidateExecuteActionExists(BURN_PLAN* pPlan, BOOL fRollback, DWORD dwIndex)
1222 {
1223 Assert::InRange(dwIndex + 1ul, 1ul, (fRollback ? pPlan->cRollbackActions : pPlan->cExecuteActions));
1224 return (fRollback ? pPlan->rgRollbackActions : pPlan->rgExecuteActions) + dwIndex;
1225 }
1226
1227 void ValidateExecuteBeginMsiTransaction(
1228 __in BURN_PLAN* pPlan,
1229 __in BOOL fRollback,
1230 __in DWORD dwIndex,
1231 __in LPCWSTR wzRollbackBoundaryId
1232 )
1233 {
1234 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1235 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION, pAction->type);
1236 NativeAssert::StringEqual(wzRollbackBoundaryId, pAction->msiTransaction.pRollbackBoundary->sczId);
1237 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1238 }
1239
1240 void ValidateExecuteCheckpoint(
1241 __in BURN_PLAN* pPlan,
1242 __in BOOL fRollback,
1243 __in DWORD dwIndex,
1244 __in DWORD dwId
1245 )
1246 {
1247 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1248 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_CHECKPOINT, pAction->type);
1249 Assert::Equal(dwId, pAction->checkpoint.dwId);
1250 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1251 }
1252
1253 void ValidateExecuteCommitMsiTransaction(
1254 __in BURN_PLAN* pPlan,
1255 __in BOOL fRollback,
1256 __in DWORD dwIndex,
1257 __in LPCWSTR wzRollbackBoundaryId
1258 )
1259 {
1260 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1261 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION, pAction->type);
1262 NativeAssert::StringEqual(wzRollbackBoundaryId, pAction->msiTransaction.pRollbackBoundary->sczId);
1263 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1264 }
1265
1266 void ValidateExecuteExePackage(
1267 __in BURN_PLAN* pPlan,
1268 __in BOOL fRollback,
1269 __in DWORD dwIndex,
1270 __in LPCWSTR wzPackageId,
1271 __in BOOTSTRAPPER_ACTION_STATE action,
1272 __in LPCWSTR wzIgnoreDependencies
1273 )
1274 {
1275 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1276 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE, pAction->type);
1277 NativeAssert::StringEqual(wzPackageId, pAction->exePackage.pPackage->sczId);
1278 Assert::Equal<DWORD>(action, pAction->exePackage.action);
1279 NativeAssert::StringEqual(wzIgnoreDependencies, pAction->exePackage.sczIgnoreDependencies);
1280 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1281 }
1282
1283 void ValidateExecuteMsiPackage(
1284 __in BURN_PLAN* pPlan,
1285 __in BOOL fRollback,
1286 __in DWORD dwIndex,
1287 __in_z LPCWSTR wzPackageId,
1288 __in BOOTSTRAPPER_ACTION_STATE action,
1289 __in BURN_MSI_PROPERTY actionMsiProperty,
1290 __in DWORD uiLevel,
1291 __in BOOL fDisableExternalUiHandler,
1292 __in DWORD dwLoggingAttributes
1293 )
1294 {
1295 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1296 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE, pAction->type);
1297 NativeAssert::StringEqual(wzPackageId, pAction->msiPackage.pPackage->sczId);
1298 Assert::Equal<DWORD>(action, pAction->msiPackage.action);
1299 Assert::Equal<DWORD>(actionMsiProperty, pAction->msiPackage.actionMsiProperty);
1300 Assert::Equal<DWORD>(uiLevel, pAction->msiPackage.uiLevel);
1301 Assert::Equal<BOOL>(fDisableExternalUiHandler, pAction->msiPackage.fDisableExternalUiHandler);
1302 NativeAssert::NotNull(pAction->msiPackage.sczLogPath);
1303 Assert::Equal<DWORD>(dwLoggingAttributes, pAction->msiPackage.dwLoggingAttributes);
1304 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1305 }
1306
1307 BURN_EXECUTE_ACTION* ValidateDeletedExecuteMspTarget(
1308 __in BURN_PLAN* pPlan,
1309 __in BOOL fRollback,
1310 __in DWORD dwIndex,
1311 __in_z LPCWSTR wzPackageId,
1312 __in BOOTSTRAPPER_ACTION_STATE action,
1313 __in_z LPCWSTR wzTargetProductCode,
1314 __in BOOL fPerMachineTarget,
1315 __in BURN_MSI_PROPERTY actionMsiProperty,
1316 __in DWORD uiLevel,
1317 __in BOOL fDisableExternalUiHandler,
1318 __in BOOL fDeleted
1319 )
1320 {
1321 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1322 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_MSP_TARGET, pAction->type);
1323 NativeAssert::StringEqual(wzPackageId, pAction->mspTarget.pPackage->sczId);
1324 Assert::Equal<DWORD>(action, pAction->mspTarget.action);
1325 NativeAssert::StringEqual(wzTargetProductCode, pAction->mspTarget.sczTargetProductCode);
1326 Assert::Equal<BOOL>(fPerMachineTarget, pAction->mspTarget.fPerMachineTarget);
1327 Assert::Equal<DWORD>(actionMsiProperty, pAction->mspTarget.actionMsiProperty);
1328 Assert::Equal<DWORD>(uiLevel, pAction->mspTarget.uiLevel);
1329 Assert::Equal<BOOL>(fDisableExternalUiHandler, pAction->mspTarget.fDisableExternalUiHandler);
1330 NativeAssert::NotNull(pAction->mspTarget.sczLogPath);
1331 Assert::Equal<BOOL>(fDeleted, pAction->fDeleted);
1332 return pAction;
1333 }
1334
1335 void ValidateExecuteMspTargetPatch(
1336 __in BURN_EXECUTE_ACTION* pAction,
1337 __in DWORD dwIndex,
1338 __in_z LPCWSTR wzPackageId
1339 )
1340 {
1341 Assert::InRange(dwIndex + 1ul, 1ul, pAction->mspTarget.cOrderedPatches);
1342 BURN_ORDERED_PATCHES* pOrderedPatch = pAction->mspTarget.rgOrderedPatches + dwIndex;
1343 NativeAssert::StringEqual(wzPackageId, pOrderedPatch->pPackage->sczId);
1344 }
1345
1346 void ValidateExecutePackageDependency(
1347 __in BURN_PLAN* pPlan,
1348 __in BOOL fRollback,
1349 __in DWORD dwIndex,
1350 __in LPCWSTR wzPackageId,
1351 __in LPCWSTR wzBundleProviderKey,
1352 __in BURN_DEPENDENCY_ACTION action
1353 )
1354 {
1355 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1356 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY, pAction->type);
1357 NativeAssert::StringEqual(wzPackageId, pAction->packageDependency.pPackage->sczId);
1358 NativeAssert::StringEqual(wzBundleProviderKey, pAction->packageDependency.sczBundleProviderKey);
1359 Assert::Equal<DWORD>(action, pAction->packageDependency.action);
1360 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1361 }
1362
1363 void ValidateExecutePackageProvider(
1364 __in BURN_PLAN* pPlan,
1365 __in BOOL fRollback,
1366 __in DWORD dwIndex,
1367 __in LPCWSTR wzPackageId,
1368 __in BURN_DEPENDENCY_ACTION action
1369 )
1370 {
1371 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1372 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER, pAction->type);
1373 NativeAssert::StringEqual(wzPackageId, pAction->packageProvider.pPackage->sczId);
1374 Assert::Equal<DWORD>(action, pAction->packageProvider.action);
1375 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1376 }
1377
1378 void ValidateExecuteRollbackBoundary(
1379 __in BURN_PLAN* pPlan,
1380 __in BOOL fRollback,
1381 __in DWORD dwIndex,
1382 __in LPCWSTR wzId,
1383 __in BOOL fVital,
1384 __in BOOL fTransaction
1385 )
1386 {
1387 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1388 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY, pAction->type);
1389 NativeAssert::StringEqual(wzId, pAction->rollbackBoundary.pRollbackBoundary->sczId);
1390 Assert::Equal<BOOL>(fVital, pAction->rollbackBoundary.pRollbackBoundary->fVital);
1391 Assert::Equal<BOOL>(fTransaction, pAction->rollbackBoundary.pRollbackBoundary->fTransaction);
1392 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1393 }
1394
1395 void ValidateExecuteUncachePackage(
1396 __in BURN_PLAN* pPlan,
1397 __in BOOL fRollback,
1398 __in DWORD dwIndex,
1399 __in LPCWSTR wzPackageId
1400 )
1401 {
1402 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1403 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_UNCACHE_PACKAGE, pAction->type);
1404 NativeAssert::StringEqual(wzPackageId, pAction->uncachePackage.pPackage->sczId);
1405 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1406 }
1407
1408 void ValidateExecuteWaitSyncpoint(
1409 __in BURN_PLAN* pPlan,
1410 __in BOOL fRollback,
1411 __in DWORD dwIndex,
1412 __in HANDLE hEvent
1413 )
1414 {
1415 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1416 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_WAIT_SYNCPOINT, pAction->type);
1417 Assert::Equal((DWORD_PTR)hEvent, (DWORD_PTR)pAction->syncpoint.hEvent);
1418 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1419 }
1420
1421 void ValidateNonPermanentPackageExpectedStates(
1422 __in BURN_PACKAGE* pPackage,
1423 __in_z LPCWSTR wzPackageId,
1424 __in BURN_PACKAGE_REGISTRATION_STATE expectedCacheState,
1425 __in BURN_PACKAGE_REGISTRATION_STATE expectedInstallState
1426 )
1427 {
1428 NativeAssert::StringEqual(wzPackageId, pPackage->sczId);
1429 Assert::Equal<BOOL>(TRUE, pPackage->fCanAffectRegistration);
1430 Assert::Equal<DWORD>(expectedCacheState, pPackage->expectedCacheRegistrationState);
1431 Assert::Equal<DWORD>(expectedInstallState, pPackage->expectedInstallRegistrationState);
1432 }
1433
1434 void ValidatePermanentPackageExpectedStates(
1435 __in BURN_PACKAGE* pPackage,
1436 __in_z LPCWSTR wzPackageId
1437 )
1438 {
1439 NativeAssert::StringEqual(wzPackageId, pPackage->sczId);
1440 Assert::Equal<BOOL>(FALSE, pPackage->fCanAffectRegistration);
1441 Assert::Equal<DWORD>(BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN, pPackage->expectedCacheRegistrationState);
1442 Assert::Equal<DWORD>(BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN, pPackage->expectedInstallRegistrationState);
1443 }
1444
1445 void ValidatePlannedProvider(
1446 __in BURN_PLAN* pPlan,
1447 __in UINT uIndex,
1448 __in LPCWSTR wzKey,
1449 __in LPCWSTR wzName
1450 )
1451 {
1452 Assert::InRange(uIndex + 1u, 1u, pPlan->cPlannedProviders);
1453
1454 DEPENDENCY* pProvider = pPlan->rgPlannedProviders + uIndex;
1455 NativeAssert::StringEqual(wzKey, pProvider->sczKey);
1456 NativeAssert::StringEqual(wzName, pProvider->sczName);
1457 }
1458 };
1459}
1460}
1461}
1462}
1463}
1464
1465static HRESULT WINAPI PlanTestBAProc(
1466 __in BOOTSTRAPPER_APPLICATION_MESSAGE /*message*/,
1467 __in const LPVOID /*pvArgs*/,
1468 __inout LPVOID /*pvResults*/,
1469 __in_opt LPVOID /*pvContext*/
1470 )
1471{
1472 return S_OK;
1473}
diff --git a/src/burn/test/BurnUnitTest/RegistrationTest.cpp b/src/burn/test/BurnUnitTest/RegistrationTest.cpp
new file mode 100644
index 00000000..7b126f61
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/RegistrationTest.cpp
@@ -0,0 +1,772 @@
1// 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.
2
3#include "precomp.h"
4
5
6#define ROOT_PATH L"SOFTWARE\\WiX_Burn_UnitTest"
7#define HKLM_PATH L"SOFTWARE\\WiX_Burn_UnitTest\\HKLM"
8#define HKCU_PATH L"SOFTWARE\\WiX_Burn_UnitTest\\HKCU"
9#define REGISTRY_UNINSTALL_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
10#define REGISTRY_RUN_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"
11
12#define TEST_UNINSTALL_KEY L"HKEY_CURRENT_USER\\" HKCU_PATH L"\\" REGISTRY_UNINSTALL_KEY L"\\{D54F896D-1952-43e6-9C67-B5652240618C}"
13#define TEST_RUN_KEY L"HKEY_CURRENT_USER\\" HKCU_PATH L"\\" REGISTRY_RUN_KEY
14
15
16static LSTATUS APIENTRY RegistrationTest_RegCreateKeyExW(
17 __in HKEY hKey,
18 __in LPCWSTR lpSubKey,
19 __reserved DWORD Reserved,
20 __in_opt LPWSTR lpClass,
21 __in DWORD dwOptions,
22 __in REGSAM samDesired,
23 __in_opt CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
24 __out PHKEY phkResult,
25 __out_opt LPDWORD lpdwDisposition
26 );
27static LSTATUS APIENTRY RegistrationTest_RegOpenKeyExW(
28 __in HKEY hKey,
29 __in_opt LPCWSTR lpSubKey,
30 __reserved DWORD ulOptions,
31 __in REGSAM samDesired,
32 __out PHKEY phkResult
33 );
34static LSTATUS APIENTRY RegistrationTest_RegDeleteKeyExW(
35 __in HKEY hKey,
36 __in LPCWSTR lpSubKey,
37 __in REGSAM samDesired,
38 __reserved DWORD Reserved
39 );
40
41namespace Microsoft
42{
43namespace Tools
44{
45namespace WindowsInstallerXml
46{
47namespace Test
48{
49namespace Bootstrapper
50{
51 using namespace Microsoft::Win32;
52 using namespace System;
53 using namespace System::IO;
54 using namespace Xunit;
55
56 public ref class RegistrationTest : BurnUnitTest
57 {
58 public:
59 RegistrationTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
60 {
61 }
62
63 [Fact]
64 void RegisterBasicTest()
65 {
66 HRESULT hr = S_OK;
67 IXMLDOMElement* pixeBundle = NULL;
68 LPWSTR sczCurrentProcess = NULL;
69 BURN_VARIABLES variables = { };
70 BURN_USER_EXPERIENCE userExperience = { };
71 BOOTSTRAPPER_COMMAND command = { };
72 BURN_REGISTRATION registration = { };
73 BURN_LOGGING logging = { };
74 BURN_PACKAGES packages = { };
75 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
76
77 try
78 {
79 // set mock API's
80 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
81
82 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
83
84 logging.sczPath = L"BurnUnitTest.txt";
85
86 LPCWSTR wzDocument =
87 L"<Bundle>"
88 L" <UX>"
89 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
90 L" </UX>"
91 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
92 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
93 L" </Registration>"
94 L"</Bundle>";
95
96 // load XML document
97 LoadBundleXmlHelper(wzDocument, &pixeBundle);
98
99 hr = VariableInitialize(&variables);
100 TestThrowOnFailure(hr, L"Failed to initialize variables.");
101
102 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
103 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
104
105 hr = RegistrationParseFromXml(&registration, pixeBundle);
106 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
107
108 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
109 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
110
111 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
112 TestThrowOnFailure(hr, L"Failed to get current process path.");
113
114 // write registration
115 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
116 TestThrowOnFailure(hr, L"Failed to register bundle.");
117
118 // verify that registration was created
119 Assert::True(Directory::Exists(cacheDirectory));
120 Assert::True(File::Exists(Path::Combine(cacheDirectory, gcnew String(L"setup.exe"))));
121
122 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
123 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)(Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr)));
124
125 // end session
126 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
127 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
128
129 // verify that registration was removed
130 Assert::False(Directory::Exists(cacheDirectory));
131
132 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
133 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
134 }
135 finally
136 {
137 ReleaseStr(sczCurrentProcess);
138 ReleaseObject(pixeBundle);
139 UserExperienceUninitialize(&userExperience);
140 RegistrationUninitialize(&registration);
141 VariablesUninitialize(&variables);
142
143 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
144 if (Directory::Exists(cacheDirectory))
145 {
146 Directory::Delete(cacheDirectory, true);
147 }
148
149 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
150 }
151 }
152
153 [Fact]
154 void RegisterArpMinimumTest()
155 {
156 HRESULT hr = S_OK;
157 IXMLDOMElement* pixeBundle = NULL;
158 LPWSTR sczCurrentProcess = NULL;
159 BURN_VARIABLES variables = { };
160 BURN_USER_EXPERIENCE userExperience = { };
161 BOOTSTRAPPER_COMMAND command = { };
162 BURN_REGISTRATION registration = { };
163 BURN_LOGGING logging = { };
164 BURN_PACKAGES packages = { };
165 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
166 try
167 {
168 // set mock API's
169 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
170
171 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
172
173 logging.sczPath = L"BurnUnitTest.txt";
174
175 LPCWSTR wzDocument =
176 L"<Bundle>"
177 L" <UX>"
178 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
179 L" </UX>"
180 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
181 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='Product1' DisplayVersion='1.0.0.0' />"
182 L" </Registration>"
183 L"</Bundle>";
184
185 // load XML document
186 LoadBundleXmlHelper(wzDocument, &pixeBundle);
187
188 hr = VariableInitialize(&variables);
189 TestThrowOnFailure(hr, L"Failed to initialize variables.");
190
191 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
192 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
193
194 hr = RegistrationParseFromXml(&registration, pixeBundle);
195 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
196
197 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
198 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
199
200 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
201 TestThrowOnFailure(hr, L"Failed to get current process path.");
202
203 //
204 // install
205 //
206
207 // write registration
208 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
209 TestThrowOnFailure(hr, L"Failed to register bundle.");
210
211 // verify that registration was created
212 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
213 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
214
215 // complete registration
216 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
217 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
218
219 // verify that registration was updated
220 Assert::Equal(Int32(BURN_RESUME_MODE_ARP), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
221 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
222 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
223
224 //
225 // uninstall
226 //
227
228 // write registration
229 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER, 0);
230 TestThrowOnFailure(hr, L"Failed to register bundle.");
231
232 // verify that registration was updated
233 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
234 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
235 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
236
237 // delete registration
238 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
239 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
240
241 // verify that registration was removed
242 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
243 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
244 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
245 }
246 finally
247 {
248 ReleaseStr(sczCurrentProcess);
249 ReleaseObject(pixeBundle);
250 UserExperienceUninitialize(&userExperience);
251 RegistrationUninitialize(&registration);
252 VariablesUninitialize(&variables);
253
254 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
255 if (Directory::Exists(cacheDirectory))
256 {
257 Directory::Delete(cacheDirectory, true);
258 }
259
260 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
261 }
262 }
263
264 [Fact]
265 void RegisterVariablesTest()
266 {
267 HRESULT hr = S_OK;
268 IXMLDOMElement* pixeBundle = NULL;
269 LPWSTR sczCurrentProcess = NULL;
270 BURN_VARIABLES variables = { };
271 BURN_USER_EXPERIENCE userExperience = { };
272 BOOTSTRAPPER_COMMAND command = { };
273 BURN_REGISTRATION registration = { };
274 BURN_LOGGING logging = { };
275 BURN_PACKAGES packages = { };
276 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
277 try
278 {
279 // set mock API's
280 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
281
282 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
283
284 logging.sczPath = L"BurnUnitTest.txt";
285
286 LPCWSTR wzDocument =
287 L"<Bundle>"
288 L" <UX>"
289 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
290 L" </UX>"
291 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='bar' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
292 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='Product1' DisplayVersion='1.0.0.0' />"
293 L" </Registration>"
294 L"</Bundle>";
295
296 // load XML document
297 LoadBundleXmlHelper(wzDocument, &pixeBundle);
298
299 hr = VariableInitialize(&variables);
300 TestThrowOnFailure(hr, L"Failed to initialize variables.");
301
302 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
303 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
304
305 hr = RegistrationParseFromXml(&registration, pixeBundle);
306 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
307
308 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
309 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
310
311 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
312 TestThrowOnFailure(hr, L"Failed to get current process path.");
313
314 //
315 // install
316 //
317
318 // write registration
319 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
320 TestThrowOnFailure(hr, L"Failed to register bundle.");
321
322 // verify that registration was created
323 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
324 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
325
326 // complete registration
327 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
328 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
329
330 // verify that registration variables were updated
331 registration.fInstalled = TRUE;
332
333 hr = RegistrationSetVariables(&registration, &variables);
334 TestThrowOnFailure(hr, L"Failed to set registration variables.");
335
336 Assert::Equal(1ll, VariableGetNumericHelper(&variables, BURN_BUNDLE_INSTALLED));
337 Assert::Equal(1ll, VariableGetNumericHelper(&variables, BURN_REBOOT_PENDING));
338 Assert::Equal<String^>(gcnew String(L"foo"), VariableGetStringHelper(&variables, BURN_BUNDLE_TAG));
339 Assert::Equal<String^>(gcnew String(L"bar"), VariableGetStringHelper(&variables, BURN_BUNDLE_PROVIDER_KEY));
340 Assert::Equal<String^>(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, BURN_BUNDLE_VERSION));
341
342 //
343 // uninstall
344 //
345
346 // delete registration
347 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
348 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
349
350 // verify that registration was removed
351 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
352 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
353 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
354 }
355 finally
356 {
357 ReleaseStr(sczCurrentProcess);
358 ReleaseObject(pixeBundle);
359 UserExperienceUninitialize(&userExperience);
360 RegistrationUninitialize(&registration);
361 VariablesUninitialize(&variables);
362
363 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
364 if (Directory::Exists(cacheDirectory))
365 {
366 Directory::Delete(cacheDirectory, true);
367 }
368
369 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
370 }
371 }
372
373 [Fact]
374 void RegisterArpFullTest()
375 {
376 HRESULT hr = S_OK;
377 IXMLDOMElement* pixeBundle = NULL;
378 LPWSTR sczCurrentProcess = NULL;
379 BURN_VARIABLES variables = { };
380 BURN_USER_EXPERIENCE userExperience = { };
381 BOOTSTRAPPER_COMMAND command = { };
382 BURN_REGISTRATION registration = { };
383 BURN_LOGGING logging = { };
384 BURN_PACKAGES packages = { };
385 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
386 try
387 {
388 // set mock API's
389 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
390
391 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
392
393 logging.sczPath = L"BurnUnitTest.txt";
394
395 LPCWSTR wzDocument =
396 L"<Bundle>"
397 L" <UX UxDllPayloadId='ux.dll'>"
398 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
399 L" </UX>"
400 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
401 L" <Arp Register='yes' DisplayName='DisplayName1' DisplayVersion='1.2.3.4' Publisher='Publisher1' HelpLink='http://www.microsoft.com/help'"
402 L" HelpTelephone='555-555-5555' AboutUrl='http://www.microsoft.com/about' UpdateUrl='http://www.microsoft.com/update'"
403 L" Comments='Comments1' Contact='Contact1' DisableModify='yes' DisableRemove='yes' />"
404 L" </Registration>"
405 L"</Bundle>";
406
407 // load XML document
408 LoadBundleXmlHelper(wzDocument, &pixeBundle);
409
410 hr = VariableInitialize(&variables);
411 TestThrowOnFailure(hr, L"Failed to initialize variables.");
412
413 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
414 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
415
416 hr = RegistrationParseFromXml(&registration, pixeBundle);
417 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
418
419 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
420 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
421
422 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
423 TestThrowOnFailure(hr, L"Failed to get current process path.");
424
425 //
426 // install
427 //
428
429 // write registration
430 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
431 TestThrowOnFailure(hr, L"Failed to register bundle.");
432
433 // verify that registration was created
434 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
435 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
436
437 // finish registration
438 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
439 TestThrowOnFailure(hr, L"Failed to register bundle.");
440
441 // verify that registration was updated
442 Assert::Equal(Int32(BURN_RESUME_MODE_ARP), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
443 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
444 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
445
446 Assert::Equal<String^>(gcnew String(L"DisplayName1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"DisplayName"), nullptr));
447 Assert::Equal<String^>(gcnew String(L"1.2.3.4"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"DisplayVersion"), nullptr));
448 Assert::Equal<String^>(gcnew String(L"Publisher1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Publisher"), nullptr));
449 Assert::Equal<String^>(gcnew String(L"http://www.microsoft.com/help"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"HelpLink"), nullptr));
450 Assert::Equal<String^>(gcnew String(L"555-555-5555"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"HelpTelephone"), nullptr));
451 Assert::Equal<String^>(gcnew String(L"http://www.microsoft.com/about"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"URLInfoAbout"), nullptr));
452 Assert::Equal<String^>(gcnew String(L"http://www.microsoft.com/update"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"URLUpdateInfo"), nullptr));
453 Assert::Equal<String^>(gcnew String(L"Comments1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Comments"), nullptr));
454 Assert::Equal<String^>(gcnew String(L"Contact1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Contact"), nullptr));
455 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"NoModify"), nullptr));
456 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"NoRemove"), nullptr));
457
458 //
459 // uninstall
460 //
461
462 // write registration
463 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER, 0);
464 TestThrowOnFailure(hr, L"Failed to register bundle.");
465
466 // verify that registration was updated
467 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
468 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
469
470 // delete registration
471 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
472 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
473
474 // verify that registration was removed
475 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
476 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
477 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
478 }
479 finally
480 {
481 ReleaseStr(sczCurrentProcess);
482 ReleaseObject(pixeBundle);
483 UserExperienceUninitialize(&userExperience);
484 RegistrationUninitialize(&registration);
485 VariablesUninitialize(&variables);
486
487 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
488 if (Directory::Exists(cacheDirectory))
489 {
490 Directory::Delete(cacheDirectory, true);
491 }
492
493 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
494 }
495 }
496
497 [Fact(Skip = "Currently fails")]
498 void ResumeTest()
499 {
500 HRESULT hr = S_OK;
501 IXMLDOMElement* pixeBundle = NULL;
502 LPWSTR sczCurrentProcess = NULL;
503 BURN_VARIABLES variables = { };
504 BURN_USER_EXPERIENCE userExperience = { };
505 BOOTSTRAPPER_COMMAND command = { };
506 BURN_REGISTRATION registration = { };
507 BURN_LOGGING logging = { };
508 BURN_PACKAGES packages = { };
509 BYTE rgbData[256] = { };
510 BOOTSTRAPPER_RESUME_TYPE resumeType = BOOTSTRAPPER_RESUME_TYPE_NONE;
511 BYTE* pbBuffer = NULL;
512 SIZE_T cbBuffer = 0;
513 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
514 try
515 {
516 for (DWORD i = 0; i < 256; ++i)
517 {
518 rgbData[i] = (BYTE)i;
519 }
520
521 // set mock API's
522 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
523
524 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
525
526 logging.sczPath = L"BurnUnitTest.txt";
527
528 LPCWSTR wzDocument =
529 L"<Bundle>"
530 L" <UX>"
531 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
532 L" </UX>"
533 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
534 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
535 L" </Registration>"
536 L"</Bundle>";
537
538 // load XML document
539 LoadBundleXmlHelper(wzDocument, &pixeBundle);
540
541 hr = VariableInitialize(&variables);
542 TestThrowOnFailure(hr, L"Failed to initialize variables.");
543
544 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
545 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
546
547 hr = RegistrationParseFromXml(&registration, pixeBundle);
548 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
549
550 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
551 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
552
553 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
554 TestThrowOnFailure(hr, L"Failed to get current process path.");
555
556 // read resume type before session
557 hr = RegistrationDetectResumeType(&registration, &resumeType);
558 TestThrowOnFailure(hr, L"Failed to read resume type.");
559
560 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_NONE, (int)resumeType);
561
562 // begin session
563 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
564 TestThrowOnFailure(hr, L"Failed to register bundle.");
565
566 hr = RegistrationSaveState(&registration, rgbData, sizeof(rgbData));
567 TestThrowOnFailure(hr, L"Failed to save state.");
568
569 // read interrupted resume type
570 hr = RegistrationDetectResumeType(&registration, &resumeType);
571 TestThrowOnFailure(hr, L"Failed to read interrupted resume type.");
572
573 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED, (int)resumeType);
574
575 // suspend session
576 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_SUSPEND, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
577 TestThrowOnFailure(hr, L"Failed to suspend session.");
578
579 // verify that run key was removed
580 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
581
582 // read suspend resume type
583 hr = RegistrationDetectResumeType(&registration, &resumeType);
584 TestThrowOnFailure(hr, L"Failed to read suspend resume type.");
585
586 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_SUSPEND, (int)resumeType);
587
588 // read state back
589 hr = RegistrationLoadState(&registration, &pbBuffer, &cbBuffer);
590 TestThrowOnFailure(hr, L"Failed to load state.");
591
592 Assert::Equal((SIZE_T)sizeof(rgbData), cbBuffer);
593 Assert::True(0 == memcmp(pbBuffer, rgbData, sizeof(rgbData)));
594
595 // write active resume mode
596 hr = RegistrationSessionResume(&registration, &variables);
597 TestThrowOnFailure(hr, L"Failed to write active resume mode.");
598
599 // verify that run key was put back
600 Assert::NotEqual((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
601
602 // end session
603 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
604 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
605
606 // read resume type after session
607 hr = RegistrationDetectResumeType(&registration, &resumeType);
608 TestThrowOnFailure(hr, L"Failed to read resume type.");
609
610 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_NONE, (int)resumeType);
611 }
612 finally
613 {
614 ReleaseStr(sczCurrentProcess);
615 ReleaseObject(pixeBundle);
616 UserExperienceUninitialize(&userExperience);
617 RegistrationUninitialize(&registration);
618 VariablesUninitialize(&variables);
619
620 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
621 if (Directory::Exists(cacheDirectory))
622 {
623 Directory::Delete(cacheDirectory, true);
624 }
625
626 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
627 }
628 }
629
630 //BOOTSTRAPPER_RESUME_TYPE_NONE,
631 //BOOTSTRAPPER_RESUME_TYPE_INVALID, // resume information is present but invalid
632 //BOOTSTRAPPER_RESUME_TYPE_UNEXPECTED, // relaunched after an unexpected interruption
633 //BOOTSTRAPPER_RESUME_TYPE_REBOOT_PENDING, // reboot has not taken place yet
634 //BOOTSTRAPPER_RESUME_TYPE_REBOOT, // relaunched after reboot
635 //BOOTSTRAPPER_RESUME_TYPE_SUSPEND, // relaunched after suspend
636 //BOOTSTRAPPER_RESUME_TYPE_ARP, // launched from ARP
637 };
638}
639}
640}
641}
642}
643
644
645static LSTATUS APIENTRY RegistrationTest_RegCreateKeyExW(
646 __in HKEY hKey,
647 __in LPCWSTR lpSubKey,
648 __reserved DWORD Reserved,
649 __in_opt LPWSTR lpClass,
650 __in DWORD dwOptions,
651 __in REGSAM samDesired,
652 __in_opt CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
653 __out PHKEY phkResult,
654 __out_opt LPDWORD lpdwDisposition
655 )
656{
657 LSTATUS ls = ERROR_SUCCESS;
658 LPCWSTR wzRoot = NULL;
659 HKEY hkRoot = NULL;
660
661 if (HKEY_LOCAL_MACHINE == hKey)
662 {
663 wzRoot = HKLM_PATH;
664 }
665 else if (HKEY_CURRENT_USER == hKey)
666 {
667 wzRoot = HKCU_PATH;
668 }
669 else
670 {
671 hkRoot = hKey;
672 }
673
674 if (wzRoot)
675 {
676 ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE, &hkRoot);
677 if (ERROR_SUCCESS != ls)
678 {
679 ExitFunction();
680 }
681 }
682
683 ls = ::RegCreateKeyExW(hkRoot, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
684
685LExit:
686 ReleaseRegKey(hkRoot);
687
688 return ls;
689}
690
691static LSTATUS APIENTRY RegistrationTest_RegOpenKeyExW(
692 __in HKEY hKey,
693 __in_opt LPCWSTR lpSubKey,
694 __reserved DWORD ulOptions,
695 __in REGSAM samDesired,
696 __out PHKEY phkResult
697 )
698{
699 LSTATUS ls = ERROR_SUCCESS;
700 LPCWSTR wzRoot = NULL;
701 HKEY hkRoot = NULL;
702
703 if (HKEY_LOCAL_MACHINE == hKey)
704 {
705 wzRoot = HKLM_PATH;
706 }
707 else if (HKEY_CURRENT_USER == hKey)
708 {
709 wzRoot = HKCU_PATH;
710 }
711 else
712 {
713 hkRoot = hKey;
714 }
715
716 if (wzRoot)
717 {
718 ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE, &hkRoot);
719 if (ERROR_SUCCESS != ls)
720 {
721 ExitFunction();
722 }
723 }
724
725 ls = ::RegOpenKeyExW(hkRoot, lpSubKey, ulOptions, samDesired, phkResult);
726
727LExit:
728 ReleaseRegKey(hkRoot);
729
730 return ls;
731}
732
733static LSTATUS APIENTRY RegistrationTest_RegDeleteKeyExW(
734 __in HKEY hKey,
735 __in LPCWSTR lpSubKey,
736 __in REGSAM samDesired,
737 __reserved DWORD Reserved
738 )
739{
740 LSTATUS ls = ERROR_SUCCESS;
741 LPCWSTR wzRoot = NULL;
742 HKEY hkRoot = NULL;
743
744 if (HKEY_LOCAL_MACHINE == hKey)
745 {
746 wzRoot = HKLM_PATH;
747 }
748 else if (HKEY_CURRENT_USER == hKey)
749 {
750 wzRoot = HKCU_PATH;
751 }
752 else
753 {
754 hkRoot = hKey;
755 }
756
757 if (wzRoot)
758 {
759 ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE | samDesired, &hkRoot);
760 if (ERROR_SUCCESS != ls)
761 {
762 ExitFunction();
763 }
764 }
765
766 ls = ::RegDeleteKeyExW(hkRoot, lpSubKey, samDesired, Reserved);
767
768LExit:
769 ReleaseRegKey(hkRoot);
770
771 return ls;
772}
diff --git a/src/burn/test/BurnUnitTest/SearchTest.cpp b/src/burn/test/BurnUnitTest/SearchTest.cpp
new file mode 100644
index 00000000..eca01f5f
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/SearchTest.cpp
@@ -0,0 +1,815 @@
1// 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.
2
3#include "precomp.h"
4
5
6static INSTALLSTATE WINAPI MsiComponentSearchTest_MsiGetComponentPathW(
7 __in LPCWSTR szProduct,
8 __in LPCWSTR szComponent,
9 __out_ecount_opt(*pcchBuf) LPWSTR lpPathBuf,
10 __inout_opt LPDWORD pcchBuf
11 );
12static INSTALLSTATE WINAPI MsiComponentSearchTest_MsiLocateComponentW(
13 __in LPCWSTR szComponent,
14 __out_ecount_opt(*pcchBuf) LPWSTR lpPathBuf,
15 __inout_opt LPDWORD pcchBuf
16 );
17static UINT WINAPI MsiProductSearchTest_MsiGetProductInfoW(
18 __in LPCWSTR szProductCode,
19 __in LPCWSTR szProperty,
20 __out_ecount_opt(*pcchValue) LPWSTR szValue,
21 __inout_opt LPDWORD pcchValue
22 );
23static UINT WINAPI MsiProductSearchTest_MsiGetProductInfoExW(
24 __in LPCWSTR szProductCode,
25 __in_opt LPCWSTR szUserSid,
26 __in MSIINSTALLCONTEXT dwContext,
27 __in LPCWSTR szProperty,
28 __out_ecount_opt(*pcchValue) LPWSTR szValue,
29 __inout_opt LPDWORD pcchValue
30 );
31
32using namespace System;
33using namespace Xunit;
34using namespace Microsoft::Win32;
35
36namespace Microsoft
37{
38namespace Tools
39{
40namespace WindowsInstallerXml
41{
42namespace Test
43{
44namespace Bootstrapper
45{
46 public ref class SearchTest : BurnUnitTest
47 {
48 public:
49 SearchTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
50 {
51 }
52
53 [Fact]
54 void DirectorySearchTest()
55 {
56 HRESULT hr = S_OK;
57 IXMLDOMElement* pixeBundle = NULL;
58 BURN_VARIABLES variables = { };
59 BURN_SEARCHES searches = { };
60 BURN_EXTENSIONS burnExtensions = { };
61 try
62 {
63 hr = VariableInitialize(&variables);
64 TestThrowOnFailure(hr, L"Failed to initialize variables.");
65
66 pin_ptr<const WCHAR> wzDirectory1 = PtrToStringChars(this->TestContext->TestDirectory);
67 pin_ptr<const WCHAR> wzDirectory2 = PtrToStringChars(System::IO::Path::Combine(this->TestContext->TestDirectory, gcnew String(L"none")));
68
69 VariableSetStringHelper(&variables, L"Directory1", wzDirectory1, FALSE);
70 VariableSetStringHelper(&variables, L"Directory2", wzDirectory2, FALSE);
71
72 LPCWSTR wzDocument =
73 L"<Bundle>"
74 L" <DirectorySearch Id='Search1' Type='exists' Path='[Directory1]' Variable='Variable1' />"
75 L" <DirectorySearch Id='Search2' Type='exists' Path='[Directory2]' Variable='Variable2' />"
76 L"</Bundle>";
77
78 // load XML document
79 LoadBundleXmlHelper(wzDocument, &pixeBundle);
80
81 hr = SearchesParseFromXml(&searches, &burnExtensions, pixeBundle);
82 TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
83
84 // execute searches
85 hr = SearchesExecute(&searches, &variables);
86 TestThrowOnFailure(hr, L"Failed to execute searches.");
87
88 // check variable values
89 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable1"));
90 Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable2"));
91 }
92 finally
93 {
94 ReleaseObject(pixeBundle);
95 VariablesUninitialize(&variables);
96 SearchesUninitialize(&searches);
97 }
98 }
99
100 [Fact(Skip = "Currently fails")]
101 void FileSearchTest()
102 {
103 HRESULT hr = S_OK;
104 IXMLDOMElement* pixeBundle = NULL;
105 BURN_VARIABLES variables = { };
106 BURN_SEARCHES searches = { };
107 BURN_EXTENSIONS burnExtensions = { };
108 ULARGE_INTEGER uliVersion = { };
109 VERUTIL_VERSION* pVersion = NULL;
110 try
111 {
112 hr = VariableInitialize(&variables);
113 TestThrowOnFailure(hr, L"Failed to initialize variables.");
114
115 pin_ptr<const WCHAR> wzFile1 = PtrToStringChars(System::IO::Path::Combine(this->TestContext->TestDirectory, gcnew String(L"none.txt")));
116 pin_ptr<const WCHAR> wzFile2 = PtrToStringChars(System::Reflection::Assembly::GetExecutingAssembly()->Location);
117
118 hr = FileVersion(wzFile2, &uliVersion.HighPart, &uliVersion.LowPart);
119 TestThrowOnFailure(hr, L"Failed to get DLL version.");
120
121 hr = VerVersionFromQword(uliVersion.QuadPart, &pVersion);
122 NativeAssert::Succeeded(hr, "Failed to create version.");
123
124 VariableSetStringHelper(&variables, L"File1", wzFile1, FALSE);
125 VariableSetStringHelper(&variables, L"File2", wzFile2, FALSE);
126
127 LPCWSTR wzDocument =
128 L"<Bundle>"
129 L" <FileSearch Id='Search1' Type='exists' Path='[File1]' Variable='Variable1' />"
130 L" <FileSearch Id='Search2' Type='exists' Path='[File2]' Variable='Variable2' />"
131 L" <FileSearch Id='Search3' Type='version' Path='[File2]' Variable='Variable3' />"
132 L"</Bundle>";
133
134 // load XML document
135 LoadBundleXmlHelper(wzDocument, &pixeBundle);
136
137 hr = SearchesParseFromXml(&searches, &burnExtensions, pixeBundle);
138 TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
139
140 // execute searches
141 hr = SearchesExecute(&searches, &variables);
142 TestThrowOnFailure(hr, L"Failed to execute searches.");
143
144 // check variable values
145 Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable1"));
146 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable2"));
147 Assert::Equal<String^>(gcnew String(pVersion->sczVersion), VariableGetVersionHelper(&variables, L"Variable3"));
148 }
149 finally
150 {
151 ReleaseVerutilVersion(pVersion);
152 ReleaseObject(pixeBundle);
153 VariablesUninitialize(&variables);
154 SearchesUninitialize(&searches);
155 }
156 }
157
158 [Fact]
159 void RegistrySearchTest()
160 {
161 HRESULT hr = S_OK;
162 IXMLDOMElement* pixeBundle = NULL;
163 BURN_VARIABLES variables = { };
164 BURN_SEARCHES searches = { };
165 BURN_EXTENSIONS burnExtensions = { };
166 HKEY hkey32 = NULL;
167 HKEY hkey64 = NULL;
168 BOOL f64bitMachine = (nullptr != Environment::GetEnvironmentVariable("ProgramFiles(x86)"));
169
170 try
171 {
172 hr = VariableInitialize(&variables);
173 TestThrowOnFailure(hr, L"Failed to initialize variables.");
174
175 Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value"), gcnew String(L"String"), gcnew String(L"String1 %TEMP%"), RegistryValueKind::String);
176 Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value"), gcnew String(L"StringExpand"), gcnew String(L"String1 %TEMP%"), RegistryValueKind::ExpandString);
177 Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value"), gcnew String(L"DWord"), 1, RegistryValueKind::DWord);
178 Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value"), gcnew String(L"QWord"), 1ll, RegistryValueKind::QWord);
179 Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value"), gcnew String(L"VersionString"), gcnew String(L"1.1.1.1"), RegistryValueKind::String);
180 Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value"), gcnew String(L"VersionQWord"), MAKEQWORDVERSION(1,1,1,1), RegistryValueKind::QWord);
181 Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\String"), nullptr, gcnew String(L"String1"), RegistryValueKind::String);
182 Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Numeric"), nullptr, 1ll, RegistryValueKind::DWord);
183
184 if (f64bitMachine)
185 {
186 hr = RegCreate(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness\\", KEY_WRITE | KEY_WOW64_32KEY, &hkey32);
187 Assert::True(SUCCEEDED(hr));
188
189 hr = RegCreate(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness\\", KEY_WRITE | KEY_WOW64_64KEY, &hkey64);
190 Assert::True(SUCCEEDED(hr));
191
192 hr = RegWriteString(hkey64, L"TestStringSpecificToBitness", L"64-bit");
193 Assert::True(SUCCEEDED(hr));
194
195 hr = RegWriteString(hkey32, L"TestStringSpecificToBitness", L"32-bit");
196 Assert::True(SUCCEEDED(hr));
197 }
198
199 VariableSetStringHelper(&variables, L"MyKey", L"SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value", FALSE);
200 VariableSetStringHelper(&variables, L"MyValue", L"String", FALSE);
201 VariableSetStringHelper(&variables, L"Variable27", L"Default27", FALSE);
202 VariableSetStringHelper(&variables, L"Variable28", L"Default28", FALSE);
203
204 LPCWSTR wzDocument =
205 L"<Bundle>"
206 L" <RegistrySearch Id='Search1' Type='exists' Root='HKLM' Key='SOFTWARE\\Microsoft' Variable='Variable1' />"
207 L" <RegistrySearch Id='Search2' Type='exists' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\None' Variable='Variable2' />"
208 L" <RegistrySearch Id='Search3' Type='exists' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='None' Variable='Variable3' />"
209 L" <RegistrySearch Id='Search4' Type='exists' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='String' Variable='Variable4' />"
210 L" <RegistrySearch Id='Search5' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='String' Variable='Variable5' VariableType='string' />"
211 L" <RegistrySearch Id='Search6' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='String' Variable='Variable6' VariableType='string' ExpandEnvironment='no' />"
212 L" <RegistrySearch Id='Search7' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='String' Variable='Variable7' VariableType='string' ExpandEnvironment='yes' />"
213 L" <RegistrySearch Id='Search8' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='StringExpand' Variable='Variable8' VariableType='string' />"
214 L" <RegistrySearch Id='Search9' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='StringExpand' Variable='Variable9' VariableType='string' ExpandEnvironment='no' />"
215 L" <RegistrySearch Id='Search10' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='StringExpand' Variable='Variable10' VariableType='string' ExpandEnvironment='yes' />"
216 L" <RegistrySearch Id='Search11' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='DWord' Variable='Variable11' VariableType='numeric' />"
217 L" <RegistrySearch Id='Search12' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='QWord' Variable='Variable12' VariableType='numeric' />"
218 L" <RegistrySearch Id='Search13' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='VersionString' Variable='Variable13' VariableType='version' />"
219 L" <RegistrySearch Id='Search14' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='VersionQWord' Variable='Variable14' VariableType='version' />"
220 L" <RegistrySearch Id='Search15' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\String' Variable='Variable15' VariableType='string' />"
221 L" <RegistrySearch Id='Search16' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Numeric' Variable='Variable16' VariableType='numeric' />"
222 L" <RegistrySearch Id='Search17' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\None' Variable='Variable17' VariableType='numeric' />"
223 L" <RegistrySearch Id='Search18' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Numeric' Value='None' Variable='Variable18' VariableType='numeric' />"
224 L" <RegistrySearch Id='Search19' Type='exists' Root='HKCU' Key='[MyKey]' Value='[MyValue]' Variable='Variable19' />"
225 L" <RegistrySearch Id='Search20' Type='value' Root='HKCU' Key='[MyKey]' Value='[MyValue]' Variable='Variable20' VariableType='string' />"
226 L" <RegistrySearch Id='Search21' Type='value' Root='HKCU' Key='SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness' Value='TestStringSpecificToBitness' Variable='Variable21' VariableType='string' Win64='no' />"
227 L" <RegistrySearch Id='Search22' Type='value' Root='HKCU' Key='SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness' Value='TestStringSpecificToBitness' Variable='Variable22' VariableType='string' Win64='yes' />"
228 L" <RegistrySearch Id='Search23' Type='exists' Root='HKU' Key='.DEFAULT\\Environment' Variable='Variable23' />"
229 L" <RegistrySearch Id='Search24' Type='exists' Root='HKU' Key='.DEFAULT\\System\\NetworkServiceSidSubkeyDoesNotExist' Variable='Variable24' />"
230 L" <RegistrySearch Id='Search25' Type='value' Root='HKCR' Key='.msi' Variable='Variable25' VariableType='string' />"
231 L" <RegistrySearch Id='Search26' Type='value' Root='HKCR' Key='.msi' Variable='Variable26' VariableType='formatted' />"
232 L" <RegistrySearch Id='Search27' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\StringDoesNotExist' Value='String' Variable='Variable27' VariableType='string' />"
233 L" <RegistrySearch Id='Search28' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\String' Value='DoesNotExist' Variable='Variable28' VariableType='string' />"
234 L"</Bundle>";
235
236 // load XML document
237 LoadBundleXmlHelper(wzDocument, &pixeBundle);
238
239 hr = SearchesParseFromXml(&searches, &burnExtensions, pixeBundle);
240 TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
241
242 // execute searches
243 hr = SearchesExecute(&searches, &variables);
244 TestThrowOnFailure(hr, L"Failed to execute searches.");
245
246 // check variable values
247 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable1"));
248 Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable2"));
249 Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable3"));
250 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable4"));
251 Assert::Equal<String^>(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable5"));
252 Assert::Equal<String^>(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable6"));
253 Assert::Equal<String^>(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable7"));
254 Assert::Equal<String^>(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable8"));
255 Assert::Equal<String^>(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable9"));
256 Assert::NotEqual(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable10"));
257 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable11"));
258 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable12"));
259 Assert::Equal<String^>(gcnew String(L"1.1.1.1"), VariableGetVersionHelper(&variables, L"Variable13"));
260 Assert::Equal<String^>(gcnew String(L"1.1.1.1"), VariableGetVersionHelper(&variables, L"Variable14"));
261 Assert::Equal<String^>(gcnew String(L"String1"), VariableGetStringHelper(&variables, L"Variable15"));
262 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable16"));
263 Assert::False(VariableExistsHelper(&variables, L"Variable17"));
264 Assert::False(VariableExistsHelper(&variables, L"Variable18"));
265 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable19"));
266 Assert::Equal<String^>(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable20"));
267 if (f64bitMachine)
268 {
269 Assert::Equal<String^>(gcnew String(L"32-bit"), VariableGetStringHelper(&variables, L"Variable21"));
270 Assert::Equal<String^>(gcnew String(L"64-bit"), VariableGetStringHelper(&variables, L"Variable22"));
271 }
272
273 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable23"));
274 Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable24"));
275 Assert::Equal<String^>(gcnew String(L"Msi.Package"), VariableGetStringHelper(&variables, L"Variable25"));
276 Assert::Equal<String^>(gcnew String(L"Msi.Package"), VariableGetStringHelper(&variables, L"Variable26"));
277 Assert::Equal<String^>(gcnew String(L"Default27"), VariableGetStringHelper(&variables, L"Variable27"));
278 Assert::Equal<String^>(gcnew String(L"Default28"), VariableGetStringHelper(&variables, L"Variable28"));
279 }
280 finally
281 {
282 ReleaseRegKey(hkey32);
283 ReleaseRegKey(hkey64);
284 ReleaseObject(pixeBundle);
285 VariablesUninitialize(&variables);
286 SearchesUninitialize(&searches);
287
288 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(L"SOFTWARE\\Microsoft\\WiX_Burn_UnitTest"));
289 if (f64bitMachine)
290 {
291 RegDelete(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness", REG_KEY_32BIT, FALSE);
292 RegDelete(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest", REG_KEY_32BIT, FALSE);
293 RegDelete(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness", REG_KEY_64BIT, FALSE);
294 RegDelete(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest", REG_KEY_64BIT, FALSE);
295 }
296 }
297 }
298
299 [Fact]
300 void MsiComponentSearchTest()
301 {
302 HRESULT hr = S_OK;
303 IXMLDOMElement* pixeBundle = NULL;
304 BURN_VARIABLES variables = { };
305 BURN_SEARCHES searches = { };
306 BURN_EXTENSIONS burnExtensions = { };
307 try
308 {
309 hr = VariableInitialize(&variables);
310 TestThrowOnFailure(hr, L"Failed to initialize variables.");
311
312 // set mock API's
313 WiuFunctionOverride(NULL, MsiComponentSearchTest_MsiGetComponentPathW, MsiComponentSearchTest_MsiLocateComponentW, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
314
315 LPCWSTR wzDocument =
316 L"<Bundle>"
317 L" <MsiComponentSearch Id='Search1' Type='state' ComponentId='{BAD00000-1000-0000-0000-000000000000}' Variable='Variable1' />"
318 L" <MsiComponentSearch Id='Search2' Type='state' ProductCode='{BAD00000-0000-0000-0000-000000000000}' ComponentId='{BAD00000-1000-0000-0000-000000000000}' Variable='Variable2' />"
319 L" <MsiComponentSearch Id='Search3' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{BAD00000-1000-0000-0000-000000000000}' Variable='Variable3' />"
320 L" <MsiComponentSearch Id='Search4' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-1000-0000-000000000000}' Variable='Variable4' />"
321 L" <MsiComponentSearch Id='Search5' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-2000-0000-000000000000}' Variable='Variable5' />"
322 L" <MsiComponentSearch Id='Search6' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-3000-0000-000000000000}' Variable='Variable6' />"
323 L" <MsiComponentSearch Id='Search7' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-4000-0000-000000000000}' Variable='Variable7' />"
324 L" <MsiComponentSearch Id='Search8' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-5000-0000-000000000000}' Variable='Variable8' />"
325 L" <MsiComponentSearch Id='Search9' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-6000-0000-000000000000}' Variable='Variable9' />" // todo: value key path
326 L" <MsiComponentSearch Id='Search10' Type='state' ComponentId='{600D0000-1000-1000-0000-000000000000}' Variable='Variable10' />"
327 L" <MsiComponentSearch Id='Search11' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-1000-0000-000000000000}' Variable='Variable11' />"
328 L" <MsiComponentSearch Id='Search12' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-2000-0000-000000000000}' Variable='Variable12' />"
329 L" <MsiComponentSearch Id='Search13' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-3000-0000-000000000000}' Variable='Variable13' />"
330 L" <MsiComponentSearch Id='Search14' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-4000-0000-000000000000}' Variable='Variable14' />"
331 L" <MsiComponentSearch Id='Search15' Type='directory' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-1000-0000-000000000000}' Variable='Variable15' />"
332 L" <MsiComponentSearch Id='Search16' Type='directory' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-2000-0000-000000000000}' Variable='Variable16' />"
333 L" <MsiComponentSearch Id='Search17' Type='directory' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-3000-0000-000000000000}' Variable='Variable17' />"
334 L" <MsiComponentSearch Id='Search18' Type='directory' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-4000-0000-000000000000}' Variable='Variable18' />"
335 L" <MsiComponentSearch Id='Search19' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-7000-0000-000000000000}' Variable='Variable19' />"
336 L"</Bundle>";
337
338 // load XML document
339 LoadBundleXmlHelper(wzDocument, &pixeBundle);
340
341 hr = SearchesParseFromXml(&searches, &burnExtensions, pixeBundle);
342 TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
343
344 // execute searches
345 hr = SearchesExecute(&searches, &variables);
346 TestThrowOnFailure(hr, L"Failed to execute searches.");
347
348 // check variable values
349 Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable1"));
350 Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable2"));
351 Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable3"));
352 Assert::Equal<String^>(gcnew String(L"C:\\directory\\file1.txt"), VariableGetStringHelper(&variables, L"Variable4"));
353 Assert::Equal<String^>(gcnew String(L"C:\\directory\\file2.txt"), VariableGetStringHelper(&variables, L"Variable5"));
354 Assert::Equal<String^>(gcnew String(L"C:\\directory\\file3.txt"), VariableGetStringHelper(&variables, L"Variable6"));
355 Assert::Equal<String^>(gcnew String(L"C:\\directory\\file4.txt"), VariableGetStringHelper(&variables, L"Variable7"));
356 Assert::Equal<String^>(gcnew String(L"02:\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\"), VariableGetStringHelper(&variables, L"Variable8"));
357 Assert::Equal<String^>(gcnew String(L"02:\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value"), VariableGetStringHelper(&variables, L"Variable9"));
358 Assert::Equal(3ll, VariableGetNumericHelper(&variables, L"Variable10"));
359 Assert::Equal(3ll, VariableGetNumericHelper(&variables, L"Variable11"));
360 Assert::Equal(4ll, VariableGetNumericHelper(&variables, L"Variable12"));
361 Assert::Equal(4ll, VariableGetNumericHelper(&variables, L"Variable13"));
362 Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable14"));
363 Assert::Equal<String^>(gcnew String(L"C:\\directory\\"), VariableGetStringHelper(&variables, L"Variable15"));
364 Assert::Equal<String^>(gcnew String(L"C:\\directory\\"), VariableGetStringHelper(&variables, L"Variable16"));
365 Assert::Equal<String^>(gcnew String(L"C:\\directory\\"), VariableGetStringHelper(&variables, L"Variable17"));
366 Assert::Equal<String^>(gcnew String(L"C:\\directory\\"), VariableGetStringHelper(&variables, L"Variable18"));
367 Assert::Equal<String^>(gcnew String(L"C:\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\file5.txt"), VariableGetStringHelper(&variables, L"Variable19"));
368 }
369 finally
370 {
371 ReleaseObject(pixeBundle);
372 VariablesUninitialize(&variables);
373 SearchesUninitialize(&searches);
374 }
375 }
376
377 [Fact]
378 void MsiProductSearchTest()
379 {
380 HRESULT hr = S_OK;
381 IXMLDOMElement* pixeBundle = NULL;
382 BURN_VARIABLES variables = { };
383 BURN_SEARCHES searches = { };
384 BURN_EXTENSIONS burnExtensions = { };
385 try
386 {
387 hr = VariableInitialize(&variables);
388 TestThrowOnFailure(hr, L"Failed to initialize variables.");
389
390 // set mock API's
391 WiuFunctionOverride(NULL, NULL, NULL, NULL, MsiProductSearchTest_MsiGetProductInfoW, MsiProductSearchTest_MsiGetProductInfoExW, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
392
393 LPCWSTR wzDocument =
394 L"<Bundle>"
395 L" <MsiProductSearch Id='Search1' Type='state' ProductCode='{BAD00000-0000-0000-0000-000000000000}' Variable='Variable1' />"
396 L" <MsiProductSearch Id='Search2' Type='version' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable2' />"
397 L" <MsiProductSearch Id='Search3' Type='language' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable3' />"
398 L" <MsiProductSearch Id='Search4' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable4' />"
399 L" <MsiProductSearch Id='Search5' Type='assignment' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable5' />"
400 L" <MsiProductSearch Id='Search6' Type='version' ProductCode='{600D0000-1000-0000-0000-000000000000}' Variable='Variable6' />"
401 L"</Bundle>";
402
403 // load XML document
404 LoadBundleXmlHelper(wzDocument, &pixeBundle);
405
406 hr = SearchesParseFromXml(&searches, &burnExtensions, pixeBundle);
407 TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
408
409 // execute searches
410 hr = SearchesExecute(&searches, &variables);
411 TestThrowOnFailure(hr, L"Failed to execute searches.");
412
413 // check variable values
414 Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable1"));
415 Assert::Equal<String^>(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, L"Variable2"));
416 Assert::Equal(1033ll, VariableGetNumericHelper(&variables, L"Variable3"));
417 Assert::Equal(5ll, VariableGetNumericHelper(&variables, L"Variable4"));
418 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable5"));
419 Assert::Equal<String^>(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, L"Variable6"));
420 }
421 finally
422 {
423 ReleaseObject(pixeBundle);
424 VariablesUninitialize(&variables);
425 SearchesUninitialize(&searches);
426 }
427 }
428
429 [Fact]
430 void MsiFeatureSearchTest()
431 {
432 HRESULT hr = S_OK;
433 IXMLDOMElement* pixeBundle = NULL;
434 BURN_VARIABLES variables = { };
435 BURN_SEARCHES searches = { };
436 BURN_EXTENSIONS burnExtensions = { };
437 try
438 {
439 LPCWSTR wzDocument =
440 L"<Bundle>"
441 L" <MsiFeatureSearch Id='Search1' Type='state' ProductCode='{BAD00000-0000-0000-0000-000000000000}' FeatureId='' Variable='Variable1' />"
442 L"</Bundle>";
443
444 hr = VariableInitialize(&variables);
445 TestThrowOnFailure(hr, L"Failed to initialize variables.");
446
447 // load XML document
448 LoadBundleXmlHelper(wzDocument, &pixeBundle);
449
450 hr = SearchesParseFromXml(&searches, &burnExtensions, pixeBundle);
451 TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
452
453 // execute searches
454 hr = SearchesExecute(&searches, &variables);
455 TestThrowOnFailure(hr, L"Failed to execute searches.");
456 }
457 finally
458 {
459 ReleaseObject(pixeBundle);
460 VariablesUninitialize(&variables);
461 SearchesUninitialize(&searches);
462 }
463 }
464
465 [Fact]
466 void ConditionalSearchTest()
467 {
468 HRESULT hr = S_OK;
469 IXMLDOMElement* pixeBundle = NULL;
470 BURN_VARIABLES variables = { };
471 BURN_SEARCHES searches = { };
472 BURN_EXTENSIONS burnExtensions = { };
473 try
474 {
475 LPCWSTR wzDocument =
476 L"<Bundle>"
477 L" <RegistrySearch Id='Search1' Type='exists' Root='HKLM' Key='SOFTWARE\\Microsoft' Variable='Variable1' Condition='0' />"
478 L" <RegistrySearch Id='Search2' Type='exists' Root='HKLM' Key='SOFTWARE\\Microsoft' Variable='Variable2' Condition='1' />"
479 L" <RegistrySearch Id='Search3' Type='exists' Root='HKLM' Key='SOFTWARE\\Microsoft' Variable='Variable3' Condition='=' />"
480 L"</Bundle>";
481
482 hr = VariableInitialize(&variables);
483 TestThrowOnFailure(hr, L"Failed to initialize variables.");
484
485 // load XML document
486 LoadBundleXmlHelper(wzDocument, &pixeBundle);
487
488 hr = SearchesParseFromXml(&searches, &burnExtensions, pixeBundle);
489 TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
490
491 // execute searches
492 hr = SearchesExecute(&searches, &variables);
493 TestThrowOnFailure(hr, L"Failed to execute searches.");
494
495 // check variable values
496 Assert::False(VariableExistsHelper(&variables, L"Variable1"));
497 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable2"));
498 Assert::False(VariableExistsHelper(&variables, L"Variable3"));
499 }
500 finally
501 {
502 ReleaseObject(pixeBundle);
503 VariablesUninitialize(&variables);
504 SearchesUninitialize(&searches);
505 }
506 }
507 [Fact]
508 void NoSearchesTest()
509 {
510 HRESULT hr = S_OK;
511 IXMLDOMElement* pixeBundle = NULL;
512 BURN_VARIABLES variables = { };
513 BURN_SEARCHES searches = { };
514 BURN_EXTENSIONS burnExtensions = { };
515 try
516 {
517 LPCWSTR wzDocument =
518 L"<Bundle>"
519 L"</Bundle>";
520
521 hr = VariableInitialize(&variables);
522 TestThrowOnFailure(hr, L"Failed to initialize variables.");
523
524 // load XML document
525 LoadBundleXmlHelper(wzDocument, &pixeBundle);
526
527 hr = SearchesParseFromXml(&searches, &burnExtensions, pixeBundle);
528 TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
529
530 // execute searches
531 hr = SearchesExecute(&searches, &variables);
532 TestThrowOnFailure(hr, L"Failed to execute searches.");
533 }
534 finally
535 {
536 ReleaseObject(pixeBundle);
537 VariablesUninitialize(&variables);
538 SearchesUninitialize(&searches);
539 }
540 }
541
542 [Fact]
543 void SetVariableSearchTest()
544 {
545 HRESULT hr = S_OK;
546 IXMLDOMElement* pixeBundle = NULL;
547 BURN_VARIABLES variables = { };
548 BURN_SEARCHES searches = { };
549 BURN_EXTENSIONS burnExtensions = { };
550 try
551 {
552 LPCWSTR wzDocument =
553 L"<Bundle>"
554 L" <SetVariable Id='Search1' Type='string' Value='VAL1' Variable='PROP1' />"
555 L" <SetVariable Id='Search2' Type='numeric' Value='2' Variable='PROP2' />"
556 L" <SetVariable Id='Search3' Type='string' Value='VAL3' Variable='PROP3' />"
557 L" <SetVariable Id='Search4' Type='string' Value='VAL4' Variable='PROP4' />"
558 L" <SetVariable Id='Search5' Type='string' Value='VAL5' Variable='PROP5' />"
559 L" <SetVariable Id='Search6' Type='string' Value='VAL6' Variable='PROP6' />"
560 L" <SetVariable Id='Search7' Type='string' Value='7' Variable='PROP7' />"
561 L" <SetVariable Id='Search8' Type='version' Value='1.1.0.0' Variable='PROP8' />"
562 L" <SetVariable Id='Search9' Type='formatted' Value='[VAL9]' Variable='PROP9' />"
563 L" <SetVariable Id='Search10' Type='numeric' Value='42' Variable='OVERWRITTEN_STRING' />"
564 L" <SetVariable Id='Search11' Type='string' Value='NEW' Variable='OVERWRITTEN_NUMBER' />"
565 L" <SetVariable Id='Search12' Variable='REMOVED_NUMBER' />"
566 L"</Bundle>";
567
568 hr = VariableInitialize(&variables);
569 TestThrowOnFailure(hr, L"Failed to initialize variables.");
570
571 // set variables
572 VariableSetStringHelper(&variables, L"OVERWRITTEN_STRING", L"ORIGINAL", FALSE);
573 VariableSetNumericHelper(&variables, L"OVERWRITTEN_NUMBER", 5);
574 VariableSetNumericHelper(&variables, L"REMOVED_NUMBER", 22);
575
576 // load XML document
577 LoadBundleXmlHelper(wzDocument, &pixeBundle);
578
579 hr = SearchesParseFromXml(&searches, &burnExtensions, pixeBundle);
580 TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
581
582 // execute searches
583 hr = SearchesExecute(&searches, &variables);
584 TestThrowOnFailure(hr, L"Failed to execute searches.");
585
586 // check variable values
587 Assert::Equal<String^>(gcnew String(L"VAL1"), VariableGetStringHelper(&variables, L"PROP1"));
588 Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"PROP2"));
589 Assert::Equal<String^>(gcnew String(L"2"), VariableGetStringHelper(&variables, L"PROP2"));
590 Assert::Equal<String^>(gcnew String(L"VAL3"), VariableGetStringHelper(&variables, L"PROP3"));
591 Assert::Equal<String^>(gcnew String(L"VAL4"), VariableGetStringHelper(&variables, L"PROP4"));
592 Assert::Equal<String^>(gcnew String(L"VAL5"), VariableGetStringHelper(&variables, L"PROP5"));
593 Assert::Equal<String^>(gcnew String(L"VAL6"), VariableGetStringHelper(&variables, L"PROP6"));
594 Assert::Equal(7ll, VariableGetNumericHelper(&variables, L"PROP7"));
595 Assert::Equal<String^>(gcnew String(L"1.1.0.0"), VariableGetVersionHelper(&variables, L"PROP8"));
596 Assert::Equal<String^>(gcnew String(L"1.1.0.0"), VariableGetStringHelper(&variables, L"PROP8"));
597 Assert::Equal<String^>(gcnew String(L"[VAL9]"), VariableGetStringHelper(&variables, L"PROP9"));
598
599 Assert::Equal(42ll, VariableGetNumericHelper(&variables, L"OVERWRITTEN_STRING"));
600 Assert::Equal<String^>(gcnew String(L"NEW"), VariableGetStringHelper(&variables, L"OVERWRITTEN_NUMBER"));
601 Assert::Equal((int)BURN_VARIANT_TYPE_NONE, VariableGetTypeHelper(&variables, L"REMOVED_NUMBER"));
602 }
603 finally
604 {
605 ReleaseObject(pixeBundle);
606 VariablesUninitialize(&variables);
607 SearchesUninitialize(&searches);
608 }
609 }
610 };
611}
612}
613}
614}
615}
616
617
618static INSTALLSTATE WINAPI MsiComponentSearchTest_MsiGetComponentPathW(
619 __in LPCWSTR szProduct,
620 __in LPCWSTR szComponent,
621 __out_ecount_opt(*pcchBuf) LPWSTR lpPathBuf,
622 __inout_opt LPDWORD pcchBuf
623 )
624{
625 INSTALLSTATE is = INSTALLSTATE_INVALIDARG;
626 String^ product = gcnew String(szProduct);
627
628 if (String::Equals(product, gcnew String(L"{BAD00000-0000-0000-0000-000000000000}")))
629 {
630 is = INSTALLSTATE_UNKNOWN;
631 }
632 else if (String::Equals(product, gcnew String(L"{600D0000-0000-0000-0000-000000000000}")))
633 {
634 is = MsiComponentSearchTest_MsiLocateComponentW(szComponent, lpPathBuf, pcchBuf);
635 }
636
637 return is;
638}
639
640static INSTALLSTATE WINAPI MsiComponentSearchTest_MsiLocateComponentW(
641 __in LPCWSTR szComponent,
642 __out_ecount_opt(*pcchBuf) LPWSTR lpPathBuf,
643 __inout_opt LPDWORD pcchBuf
644 )
645{
646 HRESULT hr = S_OK;
647 INSTALLSTATE is = INSTALLSTATE_INVALIDARG;
648 String^ component = gcnew String(szComponent);
649 LPCWSTR wzValue = NULL;
650
651 if (String::Equals(component, gcnew String(L"{BAD00000-1000-0000-0000-000000000000}")))
652 {
653 is = INSTALLSTATE_UNKNOWN;
654 }
655 else if (String::Equals(component, gcnew String(L"{600D0000-1000-1000-0000-000000000000}")))
656 {
657 wzValue = L"C:\\directory\\file1.txt";
658 is = INSTALLSTATE_LOCAL;
659 }
660 else if (String::Equals(component, gcnew String(L"{600D0000-1000-2000-0000-000000000000}")))
661 {
662 wzValue = L"C:\\directory\\file2.txt";
663 is = INSTALLSTATE_SOURCE;
664 }
665 else if (String::Equals(component, gcnew String(L"{600D0000-1000-3000-0000-000000000000}")))
666 {
667 wzValue = L"C:\\directory\\file3.txt";
668 is = INSTALLSTATE_SOURCEABSENT;
669 }
670 else if (String::Equals(component, gcnew String(L"{600D0000-1000-4000-0000-000000000000}")))
671 {
672 wzValue = L"C:\\directory\\file4.txt";
673 is = INSTALLSTATE_ABSENT;
674 }
675 else if (String::Equals(component, gcnew String(L"{600D0000-1000-5000-0000-000000000000}")))
676 {
677 wzValue = L"02:\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\";
678 is = INSTALLSTATE_LOCAL;
679 }
680 else if (String::Equals(component, gcnew String(L"{600D0000-1000-6000-0000-000000000000}")))
681 {
682 wzValue = L"02:\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value";
683 is = INSTALLSTATE_LOCAL;
684 }
685 else if (String::Equals(component, gcnew String(L"{600D0000-1000-7000-0000-000000000000}")))
686 {
687 wzValue = L"C:\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\directory\\file5.txt";
688 is = INSTALLSTATE_ABSENT;
689 }
690
691 if (wzValue && lpPathBuf)
692 {
693 hr = ::StringCchCopyW(lpPathBuf, *pcchBuf, wzValue);
694 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
695 {
696 *pcchBuf = lstrlenW(wzValue);
697 is = INSTALLSTATE_MOREDATA;
698 }
699 else if (FAILED(hr))
700 {
701 is = INSTALLSTATE_INVALIDARG;
702 }
703 }
704
705 return is;
706}
707
708static UINT WINAPI MsiProductSearchTest_MsiGetProductInfoW(
709 __in LPCWSTR szProductCode,
710 __in LPCWSTR szProperty,
711 __out_ecount_opt(*pcchValue) LPWSTR szValue,
712 __inout_opt LPDWORD pcchValue
713 )
714{
715 if (String::Equals(gcnew String(szProductCode), gcnew String(L"{600D0000-0000-0000-0000-000000000000}")) &&
716 String::Equals(gcnew String(szProperty), gcnew String(INSTALLPROPERTY_PRODUCTSTATE)))
717 {
718 // force call to WiuGetProductInfoEx
719 return ERROR_UNKNOWN_PROPERTY;
720 }
721
722 UINT er = MsiProductSearchTest_MsiGetProductInfoExW(szProductCode, NULL, MSIINSTALLCONTEXT_MACHINE, szProperty, szValue, pcchValue);
723 return er;
724}
725
726static UINT WINAPI MsiProductSearchTest_MsiGetProductInfoExW(
727 __in LPCWSTR szProductCode,
728 __in_opt LPCWSTR /*szUserSid*/,
729 __in MSIINSTALLCONTEXT dwContext,
730 __in LPCWSTR szProperty,
731 __out_ecount_opt(*pcchValue) LPWSTR szValue,
732 __inout_opt LPDWORD pcchValue
733 )
734{
735 HRESULT hr = S_OK;
736 DWORD er = ERROR_FUNCTION_FAILED;
737 LPCWSTR wzValue = NULL;
738
739 String^ productCode = gcnew String(szProductCode);
740 String^ _property = gcnew String(szProperty);
741 switch (dwContext)
742 {
743 case MSIINSTALLCONTEXT_USERMANAGED:
744 er = ERROR_UNKNOWN_PRODUCT;
745 break;
746 case MSIINSTALLCONTEXT_USERUNMANAGED:
747 if (String::Equals(productCode, gcnew String(L"{600D0000-0000-0000-0000-000000000000}")))
748 {
749 if (String::Equals(_property, gcnew String(INSTALLPROPERTY_PRODUCTSTATE)))
750 {
751 wzValue = L"5";
752 }
753 }
754 break;
755 case MSIINSTALLCONTEXT_MACHINE:
756 if (String::Equals(productCode, gcnew String(L"{BAD00000-0000-0000-0000-000000000000}")))
757 {
758 er = ERROR_UNKNOWN_PRODUCT;
759 }
760 else if (String::Equals(productCode, gcnew String(L"{600D0000-0000-0000-0000-000000000000}")))
761 {
762 if (String::Equals(_property, gcnew String(INSTALLPROPERTY_VERSIONSTRING)))
763 {
764 wzValue = L"1.0.0.0";
765 }
766 else if (String::Equals(_property, gcnew String(INSTALLPROPERTY_LANGUAGE)))
767 {
768 wzValue = L"1033";
769 }
770 else if (String::Equals(_property, gcnew String(INSTALLPROPERTY_ASSIGNMENTTYPE)))
771 {
772 wzValue = L"1";
773 }
774 else if (String::Equals(_property, gcnew String(INSTALLPROPERTY_PRODUCTSTATE)))
775 {
776 // try again in per-user context
777 er = ERROR_UNKNOWN_PRODUCT;
778 }
779 }
780 else if (String::Equals(productCode, gcnew String(L"{600D0000-1000-0000-0000-000000000000}")))
781 {
782 static BOOL fFlipp = FALSE;
783 if (fFlipp)
784 {
785 if (String::Equals(_property, gcnew String(INSTALLPROPERTY_VERSIONSTRING)))
786 {
787 wzValue = L"1.0.0.0";
788 }
789 }
790 else
791 {
792 *pcchValue = MAX_PATH * 2;
793 er = ERROR_MORE_DATA;
794 }
795 fFlipp = !fFlipp;
796 }
797 break;
798 }
799
800 if (wzValue)
801 {
802 hr = ::StringCchCopyW(szValue, *pcchValue, wzValue);
803 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
804 {
805 *pcchValue = lstrlenW(wzValue);
806 er = ERROR_MORE_DATA;
807 }
808 else if (SUCCEEDED(hr))
809 {
810 er = ERROR_SUCCESS;
811 }
812 }
813
814 return er;
815}
diff --git a/src/burn/test/BurnUnitTest/TestData/CacheTest/CacheSignatureTest.File b/src/burn/test/BurnUnitTest/TestData/CacheTest/CacheSignatureTest.File
new file mode 100644
index 00000000..896ac017
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/TestData/CacheTest/CacheSignatureTest.File
@@ -0,0 +1 @@
This file has a known hash. \ No newline at end of file
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/BasicFunctionality_BundleA_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/BasicFunctionality_BundleA_manifest.xml
new file mode 100644
index 00000000..65e3c63d
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/BasicFunctionality_BundleA_manifest.xml
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~BasicFunctionalityTests_BundleA" Extension=".log" /><RelatedBundle Id="{8C7E2C47-1EE7-4BBE-99A2-EAB7F3693F48}" Action="Upgrade" /><Variable Id="TestGroupName" Value="BasicFunctionalityTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><UX><Payload Id="WixStandardBootstrapperApplication" FilePath="wixstdba.dll" FileSize="245760" Hash="23F0568ADACD69D72B259F876B437707A0D41069" Packaging="embedded" SourcePath="u3" /><Payload Id="pay00kQk8rVqabvZJ20B.w1mpx7GDo" FilePath="thm.xml" FileSize="7980" Hash="7A88582165EEE4CA1D23F1B7DD58F8023552E049" Packaging="embedded" SourcePath="u0" /><Payload Id="payI2_GHsNfx8LnXWC6YRRG.VuyhI4" FilePath="thm.wxl" FileSize="4194" Hash="906294A9515835C5C8F4C5E86A32E179041C90DD" Packaging="embedded" SourcePath="u1" /><Payload Id="payjqSD44latbvJnf4vAQuVMUST73A" FilePath="logo.png" FileSize="852" Hash="239F10674BF6022854C1F1BF7C91955BDE34D3E4" Packaging="embedded" SourcePath="u2" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" FileSize="3698" Hash="AADECC6EF50E87D0642A5667CD612EF53E2CFB9A" Packaging="embedded" SourcePath="u4" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" FileSize="252" Hash="86688B13D3364ADB90BBA552F544D4D546AFD63D" Packaging="embedded" SourcePath="u5" /></UX><Container Id="WixAttachedContainer" FileSize="6959" Hash="4FC82B3432B5892D2A4EC593264A916DBDA9CE45" FilePath="BundleA.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="PackageA" FilePath="PackageA.msi" FileSize="32768" Hash="89C61F8A105A81B08036401152A1FDE67CDC0158" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="cab9Ins_fTP3wNwq5Gxo41ch5VUPaQ" FilePath="1a.cab" FileSize="975" Hash="11DE5863C4B2A8762D0EE23FE25B7774CA07676B" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}" ExecutableName="BundleA.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}"><Arp Register="yes" DisplayName="~BasicFunctionalityTests - BundleA" DisplayVersion="1.0.0.0" /></Registration><Chain><MsiPackage Id="PackageA" Cache="keep" CacheId="{64633047-D172-4BBB-B202-64337D15C952}v1.0.0.0" InstallSize="1951" Size="33743" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" ProductCode="{64633047-D172-4BBB-B202-64337D15C952}" Language="1033" Version="1.0.0.0" UpgradeCode="{7FD50F1B-D134-4365-923C-DFA160F74738}"><MsiProperty Id="ARPSYSTEMCOMPONENT" Value="1" /><MsiProperty Id="MSIFASTINSTALL" Value="7" /><Provides Key="{64633047-D172-4BBB-B202-64337D15C952}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - PackageA" /><RelatedPackage Id="{7FD50F1B-D134-4365-923C-DFA160F74738}" MaxVersion="1.0.0.0" MaxInclusive="no" OnlyDetect="no" LangInclusive="no"><Language Id="1033" /></RelatedPackage><RelatedPackage Id="{7FD50F1B-D134-4365-923C-DFA160F74738}" MinVersion="1.0.0.0" MinInclusive="no" OnlyDetect="yes" LangInclusive="no"><Language Id="1033" /></RelatedPackage><PayloadRef Id="PackageA" /><PayloadRef Id="cab9Ins_fTP3wNwq5Gxo41ch5VUPaQ" /></MsiPackage></Chain></BurnManifest> \ No newline at end of file
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/MsiTransaction_BundleAv1_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/MsiTransaction_BundleAv1_manifest.xml
new file mode 100644
index 00000000..cca9a982
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/MsiTransaction_BundleAv1_manifest.xml
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~MsiTransactionTests_BundleAv1" Extension=".log" /><RelatedBundle Id="{90ED10D5-B187-4470-B498-05D80DAB729A}" Action="Upgrade" /><Variable Id="TestGroupName" Value="MsiTransactionTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><UX><Payload Id="WixStandardBootstrapperApplication" FilePath="wixstdba.dll" FileSize="245760" Hash="23F0568ADACD69D72B259F876B437707A0D41069" Packaging="embedded" SourcePath="u3" /><Payload Id="pay00kQk8rVqabvZJ20B.w1mpx7GDo" FilePath="thm.xml" FileSize="7980" Hash="7A88582165EEE4CA1D23F1B7DD58F8023552E049" Packaging="embedded" SourcePath="u0" /><Payload Id="payI2_GHsNfx8LnXWC6YRRG.VuyhI4" FilePath="thm.wxl" FileSize="4194" Hash="906294A9515835C5C8F4C5E86A32E179041C90DD" Packaging="embedded" SourcePath="u1" /><Payload Id="payjqSD44latbvJnf4vAQuVMUST73A" FilePath="logo.png" FileSize="852" Hash="239F10674BF6022854C1F1BF7C91955BDE34D3E4" Packaging="embedded" SourcePath="u2" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" FileSize="6742" Hash="E124C9502891F1277A47D1AEC0F1755BA605E6E3" Packaging="embedded" SourcePath="u4" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" FileSize="252" Hash="86688B13D3364ADB90BBA552F544D4D546AFD63D" Packaging="embedded" SourcePath="u5" /></UX><Container Id="WixAttachedContainer" FileSize="16403" Hash="AABC770A92954AE4234A322A3621333B3FDDE225" FilePath="BundleAv1.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="PackageA" FilePath="PackageA.msi" FileSize="32768" Hash="C763E00CD117F79643F58442B87F51721554686D" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="PackageB" FilePath="PackageBv1.msi" FileSize="32768" Hash="25570B420BD65BE187AB56B695A0CC36712A224F" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><Payload Id="PackageC" FilePath="PackageCv1.msi" FileSize="32768" Hash="23472E6C185E9B3DC9C53F92435D1C4F018C06DB" Packaging="embedded" SourcePath="a2" Container="WixAttachedContainer" /><Payload Id="cab9Ins_fTP3wNwq5Gxo41ch5VUPaQ" FilePath="1a.cab" FileSize="975" Hash="11DE5863C4B2A8762D0EE23FE25B7774CA07676B" Packaging="embedded" SourcePath="a3" Container="WixAttachedContainer" /><Payload Id="cablKtJUKxAbhSMIBwQU6vJ_CDsIkE" FilePath="1bv1.cab" FileSize="975" Hash="11DE5863C4B2A8762D0EE23FE25B7774CA07676B" Packaging="embedded" SourcePath="a4" Container="WixAttachedContainer" /><Payload Id="cab3wekki1le1R8RPDV2B8_g8jcjZc" FilePath="1cv1.cab" FileSize="975" Hash="11DE5863C4B2A8762D0EE23FE25B7774CA07676B" Packaging="embedded" SourcePath="a5" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><RollbackBoundary Id="rbaOCA08D8ky7uBOK71_6FWz1K3TuQ" Vital="yes" Transaction="yes" /><Registration Id="{E6469F05-BDC8-4EB8-B218-67412543EFAA}" ExecutableName="BundleAv1.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{E6469F05-BDC8-4EB8-B218-67412543EFAA}"><Arp Register="yes" DisplayName="~MsiTransactionTests - BundleAv1" DisplayVersion="1.0.0.0" /></Registration><Chain><MsiPackage Id="PackageA" Cache="keep" CacheId="{01E6B748-7B95-4BA9-976D-B6F35076CEF4}v1.0.0.0" InstallSize="1951" Size="33743" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" ProductCode="{01E6B748-7B95-4BA9-976D-B6F35076CEF4}" Language="1033" Version="1.0.0.0" UpgradeCode="{7772FCDF-5FDB-497D-B5DF-C6D17D667976}"><MsiProperty Id="ARPSYSTEMCOMPONENT" Value="1" /><MsiProperty Id="MSIFASTINSTALL" Value="7" /><Provides Key="{01E6B748-7B95-4BA9-976D-B6F35076CEF4}" Version="1.0.0.0" DisplayName="~MsiTransactionTests - PackageA" /><RelatedPackage Id="{7772FCDF-5FDB-497D-B5DF-C6D17D667976}" MaxVersion="1.0.0.0" MaxInclusive="no" OnlyDetect="no" LangInclusive="no"><Language Id="1033" /></RelatedPackage><RelatedPackage Id="{7772FCDF-5FDB-497D-B5DF-C6D17D667976}" MinVersion="1.0.0.0" MinInclusive="no" OnlyDetect="yes" LangInclusive="no"><Language Id="1033" /></RelatedPackage><PayloadRef Id="PackageA" /><PayloadRef Id="cab9Ins_fTP3wNwq5Gxo41ch5VUPaQ" /></MsiPackage><MsiPackage Id="PackageB" Cache="keep" CacheId="{D1D01094-23CE-4AF0-84B6-4A1A133F21D3}v1.0.0.0" InstallSize="1951" Size="33743" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryForward="rbaOCA08D8ky7uBOK71_6FWz1K3TuQ" LogPathVariable="WixBundleLog_PackageB" RollbackLogPathVariable="WixBundleRollbackLog_PackageB" ProductCode="{D1D01094-23CE-4AF0-84B6-4A1A133F21D3}" Language="1033" Version="1.0.0.0" UpgradeCode="{EAFC0C6B-626E-415C-8132-536FBD19F49B}"><MsiProperty Id="ARPSYSTEMCOMPONENT" Value="1" /><MsiProperty Id="MSIFASTINSTALL" Value="7" /><Provides Key="{D1D01094-23CE-4AF0-84B6-4A1A133F21D3}" Version="1.0.0.0" DisplayName="~MsiTransactionTests - PackageBv1" /><RelatedPackage Id="{EAFC0C6B-626E-415C-8132-536FBD19F49B}" MaxVersion="1.0.0.0" MaxInclusive="no" OnlyDetect="no" LangInclusive="no"><Language Id="1033" /></RelatedPackage><RelatedPackage Id="{EAFC0C6B-626E-415C-8132-536FBD19F49B}" MinVersion="1.0.0.0" MinInclusive="no" OnlyDetect="yes" LangInclusive="no"><Language Id="1033" /></RelatedPackage><PayloadRef Id="PackageB" /><PayloadRef Id="cablKtJUKxAbhSMIBwQU6vJ_CDsIkE" /></MsiPackage><MsiPackage Id="PackageC" Cache="keep" CacheId="{A497C5E5-C78B-4F0B-BF72-B33E1DB1C4B8}v1.0.0.0" InstallSize="1951" Size="33743" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="rbaOCA08D8ky7uBOK71_6FWz1K3TuQ" LogPathVariable="WixBundleLog_PackageC" RollbackLogPathVariable="WixBundleRollbackLog_PackageC" ProductCode="{A497C5E5-C78B-4F0B-BF72-B33E1DB1C4B8}" Language="1033" Version="1.0.0.0" UpgradeCode="{A18BDC12-DAEC-43EE-87D1-31B2C2BC6269}"><MsiProperty Id="ARPSYSTEMCOMPONENT" Value="1" /><MsiProperty Id="MSIFASTINSTALL" Value="7" /><Provides Key="{A497C5E5-C78B-4F0B-BF72-B33E1DB1C4B8}" Version="1.0.0.0" DisplayName="~MsiTransactionTests - PackageCv1" /><RelatedPackage Id="{A18BDC12-DAEC-43EE-87D1-31B2C2BC6269}" MaxVersion="1.0.0.0" MaxInclusive="no" OnlyDetect="no" LangInclusive="no"><Language Id="1033" /></RelatedPackage><RelatedPackage Id="{A18BDC12-DAEC-43EE-87D1-31B2C2BC6269}" MinVersion="1.0.0.0" MinInclusive="no" OnlyDetect="yes" LangInclusive="no"><Language Id="1033" /></RelatedPackage><PayloadRef Id="PackageC" /><PayloadRef Id="cab3wekki1le1R8RPDV2B8_g8jcjZc" /></MsiPackage></Chain></BurnManifest> \ No newline at end of file
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml
new file mode 100644
index 00000000..996976b2
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~SlipstreamTests_BundleA" Extension=".log" /><RelatedBundle Id="{62C28DAF-A13E-4F55-ACA1-FB843630789C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="SlipstreamTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" FileSize="140288" Hash="4569C53566B1025E243E0C29A96C608BD4019979" Packaging="embedded" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" FileSize="783" Hash="B5BDD5E7179A94C2C817069913CA8C099DF811B9" Packaging="embedded" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" FileSize="25088" Hash="DB12DB6565CDBC4E9705204830E421ACEB710129" Packaging="embedded" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" FileSize="118272" Hash="3A7A20D97B0546A23A025EE5774BE237C14D2957" Packaging="embedded" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" FileSize="114688" Hash="56BA3EA94BEBF8EB562C914495E1594E74F05DBE" Packaging="embedded" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" FileSize="3599" Hash="8D9797C1E1A50AECB8B85FFCEA6A2A2EF611BD7F" Packaging="embedded" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" FileSize="797" Hash="75AE41181581FD6376CA9CA88147011E48BF9A30" Packaging="embedded" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" FileSize="2237" Hash="068B3C5E27AECE7987EABAA2802C9EB07B39EAF8" Packaging="embedded" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" FileSize="1998" Hash="A989D9B892F497215D81F903591ECB6CD50CFFFC" Packaging="embedded" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" FileSize="2428" Hash="E6B8E4B1AA89430EB6A5A1E997CA3D1D2F968285" Packaging="embedded" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" FileSize="2256" Hash="612CD2FD0CF3800639385C0BF4D805B24507D356" Packaging="embedded" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" FileSize="2409" Hash="E59A8F11D95AC17FC70BD718706EE36BFA50EF02" Packaging="embedded" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" FileSize="3368" Hash="154E0A658BA7EE59889224A231423634A9725547" Packaging="embedded" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" FileSize="2205" Hash="6AAE55269E42F99A5D88ADD18C433384DEB9E956" Packaging="embedded" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" FileSize="2276" Hash="7DC74874357F50AE8C4871D8F4DC06B337CF6352" Packaging="embedded" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" FileSize="2362" Hash="B60C34DE38E6E48BA0841E8A962C17179FC1B69A" Packaging="embedded" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" FileSize="2273" Hash="902D231AD6306087F215DEABB7F2AB2F8072C401" Packaging="embedded" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" FileSize="2518" Hash="4095A1AFCF18C01F7DA51A1A389C2FBBB1A82A12" Packaging="embedded" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" FileSize="2209" Hash="99CE8B42300EF656E6BD44F01766DC638CB0496F" Packaging="embedded" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" FileSize="2282" Hash="87117EE32E0004E25DDCEB1A7D417F3A02856A50" Packaging="embedded" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" FileSize="2141" Hash="5AED841C6A870C3A8BAF8A10D00F887A781D0CF0" Packaging="embedded" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" FileSize="2338" Hash="07E37CBC59298F24A5C8C3B8FEB7A45DADF8CD07" Packaging="embedded" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" FileSize="2118" Hash="AEC0CE51E8E335E9B86F1AC7E39CCD172B896582" Packaging="embedded" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" FileSize="2851" Hash="9628BADB173B171ED85D902634D9AA5D91FE9721" Packaging="embedded" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" FileSize="2304" Hash="B584E8C0D7F9B7A1BB70BC00E42BFD35BED5D81D" Packaging="embedded" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" FileSize="2102" Hash="67E93F555DBFEF8508E79F7CA8CE76B881308760" Packaging="embedded" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" FileSize="2273" Hash="AEB8C90D66942A5CD73EA52A6F2ADD4F7D518A0D" Packaging="embedded" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" FileSize="2170" Hash="B1D4B71907B8BD82DD8B047404AF10FDBBE5CBA0" Packaging="embedded" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" FileSize="1953" Hash="C8FB8982EC71C48D6EA021ADD9AAA7BCB0656281" Packaging="embedded" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" FileSize="2182" Hash="825F27A543907ED27E815EC67DFD48AF7BF5831E" Packaging="embedded" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" FileSize="2369" Hash="39C07C31077AAFDC0DD208273AA41654CAD80FDD" Packaging="embedded" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" FileSize="245760" Hash="6499FA21D178131DDE13A4EF44ABEC32E91D65D4" Packaging="embedded" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" FileSize="11264" Hash="9E6452891E401EB211DD41550A09FDF98EC0992F" Packaging="embedded" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" FileSize="14292" Hash="CDF09A0723F4F33C13670BBAFCFFA7E660E15DFC" Packaging="embedded" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" FileSize="252" Hash="86688B13D3364ADB90BBA552F544D4D546AFD63D" Packaging="embedded" SourcePath="u34" /></UX><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1479400" Hash="5A84A8E612E270E27D0061D58DB6B470153BE1F9" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="PackageAv1.msi" FileSize="32768" Hash="2369B16B7219B3C834DFBC5D2AF8B2EF8803D43D" Packaging="external" SourcePath="PackageAv1.msi" /><Payload Id="PatchA" FilePath="PatchA.msp" FileSize="20480" Hash="FABC6C18E4A778E127E84CDF67F93A291CAEC8BB" Packaging="external" SourcePath="PatchA.msp" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{22D1DDBA-284D-40A7-BD14-95EA07906F21}" ExecutableName="BundleA.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{22D1DDBA-284D-40A7-BD14-95EA07906F21}"><Arp Register="yes" DisplayName="~SlipstreamTests - BundleA" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="keep" CacheId="5A84A8E612E270E27D0061D58DB6B470153BE1F9" InstallSize="1479400" Size="1479400" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="/uninstall /q /norestart /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" RepairArguments="/q /norestart /repair /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" Repairable="yes" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><MsiPackage Id="PackageA" Cache="keep" CacheId="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}v1.0.0.0" InstallSize="2103" Size="32768" PerMachine="yes" Permanent="no" Vital="yes" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" ProductCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Language="1033" Version="1.0.0.0" UpgradeCode="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}"><MsiProperty Id="ARPSYSTEMCOMPONENT" Value="1" /><MsiProperty Id="MSIFASTINSTALL" Value="7" /><SlipstreamMsp Id="PatchA" /><Provides Key="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Version="1.0.0.0" DisplayName="~SlipstreamTests - PackageA" /><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MaxVersion="1.0.0.0" MaxInclusive="no" OnlyDetect="no" LangInclusive="no"><Language Id="1033" /></RelatedPackage><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MinVersion="1.0.0.0" MinInclusive="no" OnlyDetect="yes" LangInclusive="no"><Language Id="1033" /></RelatedPackage><PayloadRef Id="PackageA" /></MsiPackage><MspPackage Id="PatchA" Cache="keep" CacheId="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" InstallSize="20480" Size="20480" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PatchA" RollbackLogPathVariable="WixBundleRollbackLog_PatchA" PatchCode="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" PatchXml="&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;&lt;MsiPatch xmlns=&quot;http://www.microsoft.com/msi/patch_applicability.xsd&quot; SchemaVersion=&quot;1.0.0.0&quot; PatchGUID=&quot;{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}&quot; MinMsiVersion=&quot;5&quot; TargetsRTM=&quot;true&quot;&gt;&lt;TargetProduct MinMsiVersion=&quot;500&quot;&gt;&lt;TargetProductCode Validate=&quot;true&quot;&gt;{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}&lt;/TargetProductCode&gt;&lt;TargetVersion Validate=&quot;true&quot; ComparisonType=&quot;Equal&quot; ComparisonFilter=&quot;MajorMinorUpdate&quot;&gt;1.0.0.0&lt;/TargetVersion&gt;&lt;UpdatedVersion&gt;1.0.1.0&lt;/UpdatedVersion&gt;&lt;TargetLanguage Validate=&quot;false&quot;&gt;1033&lt;/TargetLanguage&gt;&lt;UpdatedLanguages&gt;1033&lt;/UpdatedLanguages&gt;&lt;UpgradeCode Validate=&quot;true&quot;&gt;{DB87BB66-FE5D-4293-81AC-EE313D3F864B}&lt;/UpgradeCode&gt;&lt;/TargetProduct&gt;&lt;TargetProductCode&gt;{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}&lt;/TargetProductCode&gt;&lt;/MsiPatch&gt;"><Provides Key="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" DisplayName="SlipstreamTests - Patch A" /><PayloadRef Id="PatchA" /></MspPackage></Chain><PatchTargetCode TargetCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Product="yes" /></BurnManifest> \ No newline at end of file
diff --git a/src/burn/test/BurnUnitTest/VariableHelpers.cpp b/src/burn/test/BurnUnitTest/VariableHelpers.cpp
new file mode 100644
index 00000000..40f958f8
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/VariableHelpers.cpp
@@ -0,0 +1,217 @@
1// 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.
2
3#include "precomp.h"
4
5
6using namespace System;
7using namespace Xunit;
8
9
10namespace Microsoft
11{
12namespace Tools
13{
14namespace WindowsInstallerXml
15{
16namespace Test
17{
18namespace Bootstrapper
19{
20 void VariableSetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LPCWSTR wzValue, BOOL fFormatted)
21 {
22 HRESULT hr = S_OK;
23
24 hr = VariableSetString(pVariables, wzVariable, wzValue, FALSE, fFormatted);
25 TestThrowOnFailure2(hr, L"Failed to set %s to: %s", wzVariable, wzValue);
26 }
27
28 void VariableSetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LONGLONG llValue)
29 {
30 HRESULT hr = S_OK;
31
32 hr = VariableSetNumeric(pVariables, wzVariable, llValue, FALSE);
33 TestThrowOnFailure2(hr, L"Failed to set %s to: %I64d", wzVariable, llValue);
34 }
35
36 void VariableSetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LPCWSTR wzValue)
37 {
38 HRESULT hr = S_OK;
39 VERUTIL_VERSION* pVersion = NULL;
40
41 try
42 {
43 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
44 TestThrowOnFailure1(hr, L"Failed to parse version '%ls'", wzValue);
45
46 hr = VariableSetVersion(pVariables, wzVariable, pVersion, FALSE);
47 TestThrowOnFailure2(hr, L"Failed to set %s to: '%ls'", wzVariable, wzValue);
48 }
49 finally
50 {
51 ReleaseVerutilVersion(pVersion);
52 }
53 }
54
55 String^ VariableGetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
56 {
57 HRESULT hr = S_OK;
58 LPWSTR scz = NULL;
59 try
60 {
61 hr = VariableGetString(pVariables, wzVariable, &scz);
62 TestThrowOnFailure1(hr, L"Failed to get: %s", wzVariable);
63
64 return gcnew String(scz);
65 }
66 finally
67 {
68 ReleaseStr(scz);
69 }
70 }
71
72 __int64 VariableGetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
73 {
74 HRESULT hr = S_OK;
75 LONGLONG llValue = 0;
76
77 hr = VariableGetNumeric(pVariables, wzVariable, &llValue);
78 TestThrowOnFailure1(hr, L"Failed to get: %s", wzVariable);
79
80 return llValue;
81 }
82
83 String^ VariableGetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
84 {
85 HRESULT hr = S_OK;
86 VERUTIL_VERSION* pValue = NULL;
87
88 try
89 {
90 hr = VariableGetVersion(pVariables, wzVariable, &pValue);
91 TestThrowOnFailure1(hr, L"Failed to get: %s", wzVariable);
92
93 return gcnew String(pValue->sczVersion);
94 }
95 finally
96 {
97 ReleaseVerutilVersion(pValue);
98 }
99 }
100
101 String^ VariableGetFormattedHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, BOOL* pfContainsHiddenVariable)
102 {
103 HRESULT hr = S_OK;
104 LPWSTR scz = NULL;
105 try
106 {
107 hr = VariableGetFormatted(pVariables, wzVariable, &scz, pfContainsHiddenVariable);
108 TestThrowOnFailure1(hr, L"Failed to get formatted: %s", wzVariable);
109
110 return gcnew String(scz);
111 }
112 finally
113 {
114 ReleaseStr(scz);
115 }
116 }
117
118 String^ VariableFormatStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzIn)
119 {
120 HRESULT hr = S_OK;
121 LPWSTR scz = NULL;
122 try
123 {
124 hr = VariableFormatString(pVariables, wzIn, &scz, NULL);
125 TestThrowOnFailure1(hr, L"Failed to format string: '%s'", wzIn);
126
127 return gcnew String(scz);
128 }
129 finally
130 {
131 ReleaseStr(scz);
132 }
133 }
134
135 String^ VariableEscapeStringHelper(LPCWSTR wzIn)
136 {
137 HRESULT hr = S_OK;
138 LPWSTR scz = NULL;
139 try
140 {
141 hr = VariableEscapeString(wzIn, &scz);
142 TestThrowOnFailure1(hr, L"Failed to escape string: '%s'", wzIn);
143
144 return gcnew String(scz);
145 }
146 finally
147 {
148 ReleaseStr(scz);
149 }
150 }
151
152 bool EvaluateConditionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzCondition)
153 {
154 HRESULT hr = S_OK;
155 BOOL f = FALSE;
156
157 hr = ConditionEvaluate(pVariables, wzCondition, &f);
158 TestThrowOnFailure1(hr, L"Failed to evaluate condition: '%s'", wzCondition);
159
160 return f ? true : false;
161 }
162
163 bool EvaluateFailureConditionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzCondition)
164 {
165 HRESULT hr = S_OK;
166 BOOL f = FALSE;
167
168 hr = ConditionEvaluate(pVariables, wzCondition, &f);
169 return E_INVALIDDATA == hr ? true : false;
170 }
171
172 bool VariableExistsHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
173 {
174 HRESULT hr = S_OK;
175 BURN_VARIANT value = { };
176
177 try
178 {
179 hr = VariableGetVariant(pVariables, wzVariable, &value);
180 if (E_NOTFOUND == hr || value.Type == BURN_VARIANT_TYPE_NONE)
181 {
182 return false;
183 }
184 else
185 {
186 TestThrowOnFailure1(hr, L"Failed to find variable: '%s'", wzVariable);
187 return true;
188 }
189 }
190 finally
191 {
192 BVariantUninitialize(&value);
193 }
194 }
195
196 int VariableGetTypeHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
197 {
198 HRESULT hr = S_OK;
199 BURN_VARIANT value = { };
200
201 try
202 {
203 hr = VariableGetVariant(pVariables, wzVariable, &value);
204 TestThrowOnFailure1(hr, L"Failed to find variable: '%s'", wzVariable);
205
206 return (int)value.Type;
207 }
208 finally
209 {
210 BVariantUninitialize(&value);
211 }
212 }
213}
214}
215}
216}
217}
diff --git a/src/burn/test/BurnUnitTest/VariableHelpers.h b/src/burn/test/BurnUnitTest/VariableHelpers.h
new file mode 100644
index 00000000..d460c60f
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/VariableHelpers.h
@@ -0,0 +1,36 @@
1#pragma once
2// 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.
3
4
5namespace Microsoft
6{
7namespace Tools
8{
9namespace WindowsInstallerXml
10{
11namespace Test
12{
13namespace Bootstrapper
14{
15
16
17void VariableSetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LPCWSTR wzValue, BOOL fFormatted);
18void VariableSetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LONGLONG llValue);
19void VariableSetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LPCWSTR wzValue);
20System::String^ VariableGetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
21__int64 VariableGetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
22System::String^ VariableGetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
23System::String^ VariableGetFormattedHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, BOOL* pfContainsHiddenVariable);
24System::String^ VariableFormatStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzIn);
25System::String^ VariableEscapeStringHelper(LPCWSTR wzIn);
26bool EvaluateConditionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzCondition);
27bool EvaluateFailureConditionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzCondition);
28bool VariableExistsHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
29int VariableGetTypeHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
30
31
32}
33}
34}
35}
36}
diff --git a/src/burn/test/BurnUnitTest/VariableTest.cpp b/src/burn/test/BurnUnitTest/VariableTest.cpp
new file mode 100644
index 00000000..5c9dce03
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/VariableTest.cpp
@@ -0,0 +1,532 @@
1// 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.
2
3#include "precomp.h"
4#undef GetTempPath
5#undef GetEnvironmentVariable
6
7namespace Microsoft
8{
9namespace Tools
10{
11namespace WindowsInstallerXml
12{
13namespace Test
14{
15namespace Bootstrapper
16{
17 using namespace System;
18 using namespace Xunit;
19
20 public ref class VariableTest : BurnUnitTest
21 {
22 public:
23 VariableTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
24 {
25 }
26
27 [Fact]
28 void VariablesBasicTest()
29 {
30 HRESULT hr = S_OK;
31 BURN_VARIABLES variables = { };
32 try
33 {
34 hr = VariableInitialize(&variables);
35 TestThrowOnFailure(hr, L"Failed to initialize variables.");
36
37 // set variables
38 VariableSetStringHelper(&variables, L"PROP1", L"VAL1", FALSE);
39 VariableSetNumericHelper(&variables, L"PROP2", 2);
40 VariableSetStringHelper(&variables, L"PROP5", L"VAL5", FALSE);
41 VariableSetStringHelper(&variables, L"PROP3", L"VAL3", FALSE);
42 VariableSetStringHelper(&variables, L"PROP4", L"VAL4", FALSE);
43 VariableSetStringHelper(&variables, L"PROP6", L"VAL6", FALSE);
44 VariableSetStringHelper(&variables, L"PROP7", L"7", FALSE);
45 VariableSetVersionHelper(&variables, L"PROP8", L"1.1.0.0");
46 VariableSetStringHelper(&variables, L"PROP9", L"[VAL9]", TRUE);
47
48 // set overwritten variables
49 VariableSetStringHelper(&variables, L"OVERWRITTEN_STRING", L"ORIGINAL", FALSE);
50 VariableSetNumericHelper(&variables, L"OVERWRITTEN_STRING", 42);
51
52 VariableSetNumericHelper(&variables, L"OVERWRITTEN_NUMBER", 5);
53 VariableSetStringHelper(&variables, L"OVERWRITTEN_NUMBER", L"NEW", FALSE);
54
55 // get and verify variable values
56 Assert::Equal<String^>(gcnew String(L"VAL1"), VariableGetStringHelper(&variables, L"PROP1"));
57 Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"PROP2"));
58 Assert::Equal<String^>(gcnew String(L"2"), VariableGetStringHelper(&variables, L"PROP2"));
59 Assert::Equal<String^>(gcnew String(L"VAL3"), VariableGetStringHelper(&variables, L"PROP3"));
60 Assert::Equal<String^>(gcnew String(L"VAL4"), VariableGetStringHelper(&variables, L"PROP4"));
61 Assert::Equal<String^>(gcnew String(L"VAL5"), VariableGetStringHelper(&variables, L"PROP5"));
62 Assert::Equal<String^>(gcnew String(L"VAL6"), VariableGetStringHelper(&variables, L"PROP6"));
63 Assert::Equal(7ll, VariableGetNumericHelper(&variables, L"PROP7"));
64 Assert::Equal<String^>(gcnew String(L"1.1.0.0"), VariableGetVersionHelper(&variables, L"PROP8"));
65 Assert::Equal<String^>(gcnew String(L"1.1.0.0"), VariableGetStringHelper(&variables, L"PROP8"));
66 Assert::Equal<String^>(gcnew String(L"[VAL9]"), VariableGetStringHelper(&variables, L"PROP9"));
67
68 Assert::Equal(42ll, VariableGetNumericHelper(&variables, L"OVERWRITTEN_STRING"));
69 Assert::Equal<String^>(gcnew String(L"NEW"), VariableGetStringHelper(&variables, L"OVERWRITTEN_NUMBER"));
70 }
71 finally
72 {
73 VariablesUninitialize(&variables);
74 }
75 }
76
77 [Fact]
78 void VariablesParseXmlTest()
79 {
80 HRESULT hr = S_OK;
81 IXMLDOMElement* pixeBundle = NULL;
82 BURN_VARIABLES variables = { };
83 BOOL fContainsHiddenData = FALSE;
84 try
85 {
86 LPCWSTR wzDocument =
87 L"<Bundle>"
88 L" <Variable Id='Var1' Type='numeric' Value='1' Hidden='no' Persisted='no' />"
89 L" <Variable Id='Var2' Type='string' Value='String value.' Hidden='no' Persisted='no' />"
90 L" <Variable Id='Var3' Type='version' Value='1.2.3.4' Hidden='no' Persisted='no' />"
91 L" <Variable Id='Var4' Hidden='no' Persisted='no' />"
92 L" <Variable Id='Var5' Type='string' Value='' Hidden='no' Persisted='no' />"
93 L" <Variable Id='Var6' Type='formatted' Value='[Formatted]' Hidden='no' Persisted='no' />"
94 L" <Variable Id='Formatted' Type='formatted' Value='supersecret' Hidden='yes' Persisted='no' />"
95 L"</Bundle>";
96
97 hr = VariableInitialize(&variables);
98 TestThrowOnFailure(hr, L"Failed to initialize variables.");
99
100 // load XML document
101 LoadBundleXmlHelper(wzDocument, &pixeBundle);
102
103 hr = VariablesParseFromXml(&variables, pixeBundle);
104 TestThrowOnFailure(hr, L"Failed to parse variables from XML.");
105
106 // get and verify variable values
107 Assert::Equal((int)BURN_VARIANT_TYPE_NUMERIC, VariableGetTypeHelper(&variables, L"Var1"));
108 Assert::Equal((int)BURN_VARIANT_TYPE_STRING, VariableGetTypeHelper(&variables, L"Var2"));
109 Assert::Equal((int)BURN_VARIANT_TYPE_VERSION, VariableGetTypeHelper(&variables, L"Var3"));
110 Assert::Equal((int)BURN_VARIANT_TYPE_NONE, VariableGetTypeHelper(&variables, L"Var4"));
111 Assert::Equal((int)BURN_VARIANT_TYPE_FORMATTED, VariableGetTypeHelper(&variables, L"Var6"));
112
113 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Var1"));
114 Assert::Equal<String^>(gcnew String(L"String value."), VariableGetStringHelper(&variables, L"Var2"));
115 Assert::Equal<String^>(gcnew String(L"1.2.3.4"), VariableGetVersionHelper(&variables, L"Var3"));
116 Assert::Equal<String^>(gcnew String(L"[Formatted]"), VariableGetStringHelper(&variables, L"Var6"));
117 Assert::Equal<String^>(gcnew String(L"supersecret"), VariableGetFormattedHelper(&variables, L"Formatted", &fContainsHiddenData));
118 Assert::Equal<BOOL>(TRUE, fContainsHiddenData);
119 Assert::Equal<String^>(gcnew String(L"supersecret"), VariableGetFormattedHelper(&variables, L"Var6", &fContainsHiddenData));
120 Assert::Equal<BOOL>(TRUE, fContainsHiddenData);
121 Assert::Equal<String^>(gcnew String(L"String value."), VariableGetFormattedHelper(&variables, L"Var2", &fContainsHiddenData));
122 Assert::Equal<BOOL>(FALSE, fContainsHiddenData);
123 }
124 finally
125 {
126 ReleaseObject(pixeBundle);
127 VariablesUninitialize(&variables);
128 }
129 }
130
131 [Fact]
132 void VariablesFormatTest()
133 {
134 HRESULT hr = S_OK;
135 BURN_VARIABLES variables = { };
136 LPWSTR scz = NULL;
137 SIZE_T cch = 0;
138 BOOL fContainsHiddenData = FALSE;
139 try
140 {
141 hr = VariableInitialize(&variables);
142 TestThrowOnFailure(hr, L"Failed to initialize variables.");
143
144 // set variables
145 VariableSetStringHelper(&variables, L"PROP1", L"VAL1", FALSE);
146 VariableSetStringHelper(&variables, L"PROP2", L"VAL2", FALSE);
147 VariableSetNumericHelper(&variables, L"PROP3", 3);
148 VariableSetStringHelper(&variables, L"PROP4", L"[PROP1]", FALSE);
149 VariableSetStringHelper(&variables, L"PROP5", L"[PROP2]", FALSE);
150 VariableSetStringHelper(&variables, L"PROP6", L"[PROP4]", TRUE);
151 VariableSetStringHelper(&variables, L"PROP7", L"[PROP5]", TRUE);
152
153 // test string formatting
154 Assert::Equal<String^>(gcnew String(L"NOPROP"), VariableFormatStringHelper(&variables, L"NOPROP"));
155 Assert::Equal<String^>(gcnew String(L"VAL1"), VariableFormatStringHelper(&variables, L"[PROP1]"));
156 Assert::Equal<String^>(gcnew String(L" VAL1 "), VariableFormatStringHelper(&variables, L" [PROP1] "));
157 Assert::Equal<String^>(gcnew String(L"PRE VAL1"), VariableFormatStringHelper(&variables, L"PRE [PROP1]"));
158 Assert::Equal<String^>(gcnew String(L"VAL1 POST"), VariableFormatStringHelper(&variables, L"[PROP1] POST"));
159 Assert::Equal<String^>(gcnew String(L"PRE VAL1 POST"), VariableFormatStringHelper(&variables, L"PRE [PROP1] POST"));
160 Assert::Equal<String^>(gcnew String(L"VAL1 MID VAL2"), VariableFormatStringHelper(&variables, L"[PROP1] MID [PROP2]"));
161 Assert::Equal<String^>(gcnew String(L""), VariableFormatStringHelper(&variables, L"[NONE]"));
162 Assert::Equal<String^>(gcnew String(L""), VariableFormatStringHelper(&variables, L"[prop1]"));
163 Assert::Equal<String^>(gcnew String(L"["), VariableFormatStringHelper(&variables, L"[\\[]"));
164 Assert::Equal<String^>(gcnew String(L"]"), VariableFormatStringHelper(&variables, L"[\\]]"));
165 Assert::Equal<String^>(gcnew String(L"[]"), VariableFormatStringHelper(&variables, L"[]"));
166 Assert::Equal<String^>(gcnew String(L"[NONE"), VariableFormatStringHelper(&variables, L"[NONE"));
167 Assert::Equal<String^>(gcnew String(L"VAL2"), VariableGetFormattedHelper(&variables, L"PROP2", &fContainsHiddenData));
168 Assert::Equal<BOOL>(FALSE, fContainsHiddenData);
169 Assert::Equal<String^>(gcnew String(L"3"), VariableGetFormattedHelper(&variables, L"PROP3", &fContainsHiddenData));
170 Assert::Equal<BOOL>(FALSE, fContainsHiddenData);
171 Assert::Equal<String^>(gcnew String(L"[PROP1]"), VariableGetFormattedHelper(&variables, L"PROP4", &fContainsHiddenData));
172 Assert::Equal<BOOL>(FALSE, fContainsHiddenData);
173 Assert::Equal<String^>(gcnew String(L"[PROP2]"), VariableGetFormattedHelper(&variables, L"PROP5", &fContainsHiddenData));
174 Assert::Equal<BOOL>(FALSE, fContainsHiddenData);
175 Assert::Equal<String^>(gcnew String(L"[PROP1]"), VariableGetFormattedHelper(&variables, L"PROP6", &fContainsHiddenData));
176 Assert::Equal<BOOL>(FALSE, fContainsHiddenData);
177 Assert::Equal<String^>(gcnew String(L"[PROP2]"), VariableGetFormattedHelper(&variables, L"PROP7", &fContainsHiddenData));
178 Assert::Equal<BOOL>(FALSE, fContainsHiddenData);
179
180 hr = VariableFormatString(&variables, L"PRE [PROP1] POST", &scz, &cch);
181 TestThrowOnFailure(hr, L"Failed to format string");
182
183 Assert::Equal((SIZE_T)lstrlenW(scz), cch);
184
185 hr = VariableFormatString(&variables, L"PRE [PROP1] POST", NULL, &cch);
186 TestThrowOnFailure(hr, L"Failed to format string");
187
188 Assert::Equal((SIZE_T)lstrlenW(scz), cch);
189 }
190 finally
191 {
192 VariablesUninitialize(&variables);
193 ReleaseStr(scz);
194 }
195 }
196
197 [Fact]
198 void VariablesEscapeTest()
199 {
200 // test string escaping
201 Assert::Equal<String^>(gcnew String(L"[\\[]"), VariableEscapeStringHelper(L"["));
202 Assert::Equal<String^>(gcnew String(L"[\\]]"), VariableEscapeStringHelper(L"]"));
203 Assert::Equal<String^>(gcnew String(L" [\\[]TEXT[\\]] "), VariableEscapeStringHelper(L" [TEXT] "));
204 }
205
206 [Fact]
207 void VariablesConditionTest()
208 {
209 HRESULT hr = S_OK;
210 BURN_VARIABLES variables = { };
211 try
212 {
213 hr = VariableInitialize(&variables);
214 TestThrowOnFailure(hr, L"Failed to initialize variables.");
215
216 // set variables
217 VariableSetStringHelper(&variables, L"PROP1", L"VAL1", FALSE);
218 VariableSetStringHelper(&variables, L"PROP2", L"VAL2", FALSE);
219 VariableSetStringHelper(&variables, L"PROP3", L"VAL3", FALSE);
220 VariableSetStringHelper(&variables, L"PROP4", L"BEGIN MID END", FALSE);
221 VariableSetNumericHelper(&variables, L"PROP5", 5);
222 VariableSetNumericHelper(&variables, L"PROP6", 6);
223 VariableSetStringHelper(&variables, L"PROP7", L"", FALSE);
224 VariableSetNumericHelper(&variables, L"PROP8", 0);
225 VariableSetStringHelper(&variables, L"_PROP9", L"VAL9", FALSE);
226 VariableSetNumericHelper(&variables, L"PROP10", -10);
227 VariableSetNumericHelper(&variables, L"PROP11", 9223372036854775807ll);
228 VariableSetNumericHelper(&variables, L"PROP12", -9223372036854775808ll);
229 VariableSetNumericHelper(&variables, L"PROP13", 0x00010000);
230 VariableSetNumericHelper(&variables, L"PROP14", 0x00000001);
231 VariableSetNumericHelper(&variables, L"PROP15", 0x00010001);
232 VariableSetVersionHelper(&variables, L"PROP16", L"0.0.0.0");
233 VariableSetVersionHelper(&variables, L"PROP17", L"1.0.0.0");
234 VariableSetVersionHelper(&variables, L"PROP18", L"1.1.0.0");
235 VariableSetVersionHelper(&variables, L"PROP19", L"1.1.1.0");
236 VariableSetVersionHelper(&variables, L"PROP20", L"1.1.1.1");
237 VariableSetNumericHelper(&variables, L"vPROP21", 1);
238 VariableSetVersionHelper(&variables, L"PROP22", L"65535.65535.65535.65535");
239 VariableSetStringHelper(&variables, L"PROP23", L"1.1.1", FALSE);
240 VariableSetStringHelper(&variables, L"PROP24", L"[PROP1]", TRUE);
241 VariableSetStringHelper(&variables, L"PROP25", L"[PROP7]", TRUE);
242 VariableSetStringHelper(&variables, L"PROP26", L"[PROP8]", TRUE);
243 VariableSetStringHelper(&variables, L"PROP27", L"[PROP16]", TRUE);
244
245 // test conditions
246 Assert::True(EvaluateConditionHelper(&variables, L"PROP1"));
247 Assert::True(EvaluateConditionHelper(&variables, L"PROP5"));
248 Assert::False(EvaluateConditionHelper(&variables, L"PROP7"));
249 Assert::False(EvaluateConditionHelper(&variables, L"PROP8"));
250 Assert::True(EvaluateConditionHelper(&variables, L"_PROP9"));
251 Assert::True(EvaluateConditionHelper(&variables, L"PROP16"));
252 Assert::True(EvaluateConditionHelper(&variables, L"PROP17"));
253 Assert::True(EvaluateConditionHelper(&variables, L"PROP24=\"VAL1\""));
254 Assert::False(EvaluateConditionHelper(&variables, L"PROP25"));
255 Assert::True(EvaluateConditionHelper(&variables, L"PROP26"));
256 Assert::True(EvaluateConditionHelper(&variables, L"PROP27"));
257
258 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\""));
259 Assert::False(EvaluateConditionHelper(&variables, L"NONE = \"NOT\""));
260 Assert::False(EvaluateConditionHelper(&variables, L"PROP1 <> \"VAL1\""));
261 Assert::False(EvaluateConditionHelper(&variables, L"PROP1 ~<> \"VAL1\""));
262 Assert::False(EvaluateConditionHelper(&variables, L"PROP1 ~<> \"Val1\""));
263 Assert::True(EvaluateConditionHelper(&variables, L"NONE <> \"NOT\""));
264 Assert::True(EvaluateConditionHelper(&variables, L"NONE ~<> \"NOT\""));
265
266 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 ~= \"val1\""));
267 Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"val1\""));
268 Assert::False(EvaluateConditionHelper(&variables, L"PROP1 ~<> \"val1\""));
269 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 <> \"val1\""));
270
271 Assert::True(EvaluateConditionHelper(&variables, L"PROP5 = 5"));
272 Assert::False(EvaluateConditionHelper(&variables, L"PROP5 = 0"));
273 Assert::False(EvaluateConditionHelper(&variables, L"PROP5 <> 5"));
274 Assert::True(EvaluateConditionHelper(&variables, L"PROP5 <> 0"));
275
276 Assert::True(EvaluateConditionHelper(&variables, L"PROP10 = -10"));
277 Assert::False(EvaluateConditionHelper(&variables, L"PROP10 <> -10"));
278
279 Assert::True(EvaluateConditionHelper(&variables, L"PROP17 = v1"));
280 Assert::False(EvaluateConditionHelper(&variables, L"PROP17 = v0"));
281 Assert::False(EvaluateConditionHelper(&variables, L"PROP17 <> v1"));
282 Assert::True(EvaluateConditionHelper(&variables, L"PROP17 <> v0"));
283
284 Assert::True(EvaluateConditionHelper(&variables, L"PROP16 = v0"));
285 Assert::True(EvaluateConditionHelper(&variables, L"PROP17 = v1"));
286 Assert::True(EvaluateConditionHelper(&variables, L"PROP18 = v1.1"));
287 Assert::True(EvaluateConditionHelper(&variables, L"PROP19 = v1.1.1"));
288 Assert::True(EvaluateConditionHelper(&variables, L"PROP20 = v1.1.1.1"));
289 Assert::True(EvaluateConditionHelper(&variables, L"PROP20 > v1.1.1.1.0"));
290 Assert::True(EvaluateConditionHelper(&variables, L"PROP20 > v1.1.1.1.1"));
291 Assert::True(EvaluateConditionHelper(&variables, L"vPROP21 = 1"));
292 Assert::True(EvaluateConditionHelper(&variables, L"PROP23 = v1.1.1"));
293 Assert::True(EvaluateConditionHelper(&variables, L"v1.1.1 = PROP23"));
294 Assert::False(EvaluateConditionHelper(&variables, L"v1.1.1<>PROP23"));
295 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 <> v1.1.1"));
296 Assert::True(EvaluateConditionHelper(&variables, L"v1.1.1 <> PROP1"));
297
298 Assert::False(EvaluateConditionHelper(&variables, L"PROP11 = 9223372036854775806"));
299 Assert::True(EvaluateConditionHelper(&variables, L"PROP11 = 9223372036854775807"));
300 Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP11 = 9223372036854775808"));
301 Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP11 = 92233720368547758070000"));
302
303 Assert::False(EvaluateConditionHelper(&variables, L"PROP12 = -9223372036854775807"));
304 Assert::True(EvaluateConditionHelper(&variables, L"PROP12 = -9223372036854775808"));
305 Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP12 = -9223372036854775809"));
306 Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP12 = -92233720368547758080000"));
307
308 Assert::True(EvaluateConditionHelper(&variables, L"PROP22 = v65535.65535.65535.65535"));
309 Assert::True(EvaluateConditionHelper(&variables, L"PROP22 < v65536.65535.65535.65535"));
310 Assert::True(EvaluateConditionHelper(&variables, L"PROP22 < v65535.655350000.65535.65535"));
311
312 Assert::True(EvaluateConditionHelper(&variables, L"PROP5 < 6"));
313 Assert::False(EvaluateConditionHelper(&variables, L"PROP5 < 5"));
314 Assert::True(EvaluateConditionHelper(&variables, L"PROP5 > 4"));
315 Assert::False(EvaluateConditionHelper(&variables, L"PROP5 > 5"));
316 Assert::True(EvaluateConditionHelper(&variables, L"PROP5 <= 6"));
317 Assert::True(EvaluateConditionHelper(&variables, L"PROP5 <= 5"));
318 Assert::False(EvaluateConditionHelper(&variables, L"PROP5 <= 4"));
319 Assert::True(EvaluateConditionHelper(&variables, L"PROP5 >= 4"));
320 Assert::True(EvaluateConditionHelper(&variables, L"PROP5 >= 5"));
321 Assert::False(EvaluateConditionHelper(&variables, L"PROP5 >= 6"));
322
323 Assert::True(EvaluateConditionHelper(&variables, L"PROP4 << \"BEGIN\""));
324 Assert::False(EvaluateConditionHelper(&variables, L"PROP4 << \"END\""));
325 Assert::True(EvaluateConditionHelper(&variables, L"PROP4 >> \"END\""));
326 Assert::False(EvaluateConditionHelper(&variables, L"PROP4 >> \"BEGIN\""));
327 Assert::True(EvaluateConditionHelper(&variables, L"PROP4 >< \"MID\""));
328 Assert::False(EvaluateConditionHelper(&variables, L"PROP4 >< \"NONE\""));
329
330 Assert::True(EvaluateConditionHelper(&variables, L"PROP16 < v1.1"));
331 Assert::False(EvaluateConditionHelper(&variables, L"PROP16 < v0"));
332 Assert::True(EvaluateConditionHelper(&variables, L"PROP17 > v0.12"));
333 Assert::False(EvaluateConditionHelper(&variables, L"PROP17 > v1"));
334 Assert::True(EvaluateConditionHelper(&variables, L"PROP18 >= v1.0"));
335 Assert::True(EvaluateConditionHelper(&variables, L"PROP18 >= v1.1"));
336 Assert::False(EvaluateConditionHelper(&variables, L"PROP18 >= v2.1"));
337 Assert::True(EvaluateConditionHelper(&variables, L"PROP19 <= v1.1234.1"));
338 Assert::True(EvaluateConditionHelper(&variables, L"PROP19 <= v1.1.1"));
339 Assert::False(EvaluateConditionHelper(&variables, L"PROP19 <= v1.0.123"));
340
341 Assert::True(EvaluateConditionHelper(&variables, L"PROP6 = \"6\""));
342 Assert::True(EvaluateConditionHelper(&variables, L"\"6\" = PROP6"));
343 Assert::False(EvaluateConditionHelper(&variables, L"PROP6 = \"ABC\""));
344 Assert::False(EvaluateConditionHelper(&variables, L"\"ABC\" = PROP6"));
345 Assert::False(EvaluateConditionHelper(&variables, L"\"ABC\" = PROP6"));
346
347 Assert::True(EvaluateConditionHelper(&variables, L"PROP13 << 1"));
348 Assert::False(EvaluateConditionHelper(&variables, L"PROP13 << 0"));
349 Assert::True(EvaluateConditionHelper(&variables, L"PROP14 >> 1"));
350 Assert::False(EvaluateConditionHelper(&variables, L"PROP14 >> 0"));
351 Assert::True(EvaluateConditionHelper(&variables, L"PROP15 >< 65537"));
352 Assert::False(EvaluateConditionHelper(&variables, L"PROP15 >< 0"));
353
354 Assert::False(EvaluateConditionHelper(&variables, L"NOT PROP1"));
355 Assert::True(EvaluateConditionHelper(&variables, L"NOT (PROP1 <> \"VAL1\")"));
356
357 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND PROP2 = \"VAL2\""));
358 Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
359 Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"NOT\" AND PROP2 = \"VAL2\""));
360 Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"NOT\" AND PROP2 = \"NOT\""));
361
362 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" OR PROP2 = \"VAL2\""));
363 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" OR PROP2 = \"NOT\""));
364 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"NOT\" OR PROP2 = \"VAL2\""));
365 Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"NOT\" OR PROP2 = \"NOT\""));
366
367 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND PROP2 = \"VAL2\" OR PROP3 = \"NOT\""));
368 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\" OR PROP3 = \"VAL3\""));
369 Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\" OR PROP3 = \"NOT\""));
370 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND (PROP2 = \"NOT\" OR PROP3 = \"VAL3\")"));
371 Assert::True(EvaluateConditionHelper(&variables, L"(PROP1 = \"VAL1\" AND PROP2 = \"VAL2\") OR PROP3 = \"NOT\""));
372
373 Assert::True(EvaluateConditionHelper(&variables, L"PROP3 = \"NOT\" OR PROP1 = \"VAL1\" AND PROP2 = \"VAL2\""));
374 Assert::True(EvaluateConditionHelper(&variables, L"PROP3 = \"VAL3\" OR PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
375 Assert::False(EvaluateConditionHelper(&variables, L"PROP3 = \"NOT\" OR PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
376 Assert::True(EvaluateConditionHelper(&variables, L"(PROP3 = \"NOT\" OR PROP1 = \"VAL1\") AND PROP2 = \"VAL2\""));
377 Assert::True(EvaluateConditionHelper(&variables, L"PROP3 = \"NOT\" OR (PROP1 = \"VAL1\" AND PROP2 = \"VAL2\")"));
378
379 Assert::True(EvaluateFailureConditionHelper(&variables, L"="));
380 Assert::True(EvaluateFailureConditionHelper(&variables, L"(PROP1"));
381 Assert::True(EvaluateFailureConditionHelper(&variables, L"(PROP1 = \""));
382 Assert::True(EvaluateFailureConditionHelper(&variables, L"1A"));
383 Assert::True(EvaluateFailureConditionHelper(&variables, L"*"));
384
385 Assert::True(EvaluateFailureConditionHelper(&variables, L"1 == 1"));
386 }
387 finally
388 {
389 VariablesUninitialize(&variables);
390 }
391 }
392
393 [Fact]
394 void VariablesSerializationTest()
395 {
396 HRESULT hr = S_OK;
397 BYTE* pbBuffer = NULL;
398 SIZE_T cbBuffer = 0;
399 SIZE_T iBuffer = 0;
400 BURN_VARIABLES variables1 = { };
401 BURN_VARIABLES variables2 = { };
402 try
403 {
404 // serialize
405 hr = VariableInitialize(&variables1);
406 TestThrowOnFailure(hr, L"Failed to initialize variables.");
407
408 VariableSetStringHelper(&variables1, L"PROP1", L"VAL1", FALSE);
409 VariableSetNumericHelper(&variables1, L"PROP2", 2);
410 VariableSetVersionHelper(&variables1, L"PROP3", L"1.1.1.1");
411 VariableSetStringHelper(&variables1, L"PROP4", L"VAL4", FALSE);
412 VariableSetStringHelper(&variables1, L"PROP5", L"[PROP1]", TRUE);
413
414 hr = VariableSerialize(&variables1, FALSE, &pbBuffer, &cbBuffer);
415 TestThrowOnFailure(hr, L"Failed to serialize variables.");
416
417 // deserialize
418 hr = VariableInitialize(&variables2);
419 TestThrowOnFailure(hr, L"Failed to initialize variables.");
420
421 hr = VariableDeserialize(&variables2, FALSE, pbBuffer, cbBuffer, &iBuffer);
422 TestThrowOnFailure(hr, L"Failed to deserialize variables.");
423
424 Assert::Equal<String^>(gcnew String(L"VAL1"), VariableGetStringHelper(&variables2, L"PROP1"));
425 Assert::Equal(2ll, VariableGetNumericHelper(&variables2, L"PROP2"));
426 Assert::Equal<String^>(gcnew String(L"1.1.1.1"), VariableGetVersionHelper(&variables2, L"PROP3"));
427 Assert::Equal<String^>(gcnew String(L"VAL4"), VariableGetStringHelper(&variables2, L"PROP4"));
428 Assert::Equal<String^>(gcnew String(L"[PROP1]"), VariableGetStringHelper(&variables2, L"PROP5"));
429
430 Assert::Equal((int)BURN_VARIANT_TYPE_STRING, VariableGetTypeHelper(&variables2, L"PROP1"));
431 Assert::Equal((int)BURN_VARIANT_TYPE_NUMERIC, VariableGetTypeHelper(&variables2, L"PROP2"));
432 Assert::Equal((int)BURN_VARIANT_TYPE_VERSION, VariableGetTypeHelper(&variables2, L"PROP3"));
433 Assert::Equal((int)BURN_VARIANT_TYPE_STRING, VariableGetTypeHelper(&variables2, L"PROP4"));
434 Assert::Equal((int)BURN_VARIANT_TYPE_FORMATTED, VariableGetTypeHelper(&variables2, L"PROP5"));
435 }
436 finally
437 {
438 ReleaseBuffer(pbBuffer);
439 VariablesUninitialize(&variables1);
440 VariablesUninitialize(&variables2);
441 }
442 }
443
444 [Fact]
445 void VariablesBuiltInTest()
446 {
447 HRESULT hr = S_OK;
448 BURN_VARIABLES variables = { };
449 try
450 {
451 hr = VariableInitialize(&variables);
452 TestThrowOnFailure(hr, L"Failed to initialize variables.");
453
454 // VersionMsi
455 Assert::True(EvaluateConditionHelper(&variables, L"VersionMsi >= v1.1"));
456
457 // VersionNT
458 Assert::True(EvaluateConditionHelper(&variables, L"VersionNT <> v0.0.0.0"));
459
460 // VersionNT64
461 if (nullptr == Environment::GetEnvironmentVariable("ProgramFiles(x86)"))
462 {
463 Assert::False(EvaluateConditionHelper(&variables, L"VersionNT64"));
464 }
465 else
466 {
467 Assert::True(EvaluateConditionHelper(&variables, L"VersionNT64"));
468 }
469
470 // attempt to set a built-in property
471 hr = VariableSetString(&variables, L"VersionNT", L"VAL", FALSE, FALSE);
472 Assert::Equal(E_INVALIDARG, hr);
473 Assert::False(EvaluateConditionHelper(&variables, L"VersionNT = \"VAL\""));
474
475 VariableGetNumericHelper(&variables, L"NTProductType");
476 VariableGetNumericHelper(&variables, L"NTSuiteBackOffice");
477 VariableGetNumericHelper(&variables, L"NTSuiteDataCenter");
478 VariableGetNumericHelper(&variables, L"NTSuiteEnterprise");
479 VariableGetNumericHelper(&variables, L"NTSuitePersonal");
480 VariableGetNumericHelper(&variables, L"NTSuiteSmallBusiness");
481 VariableGetNumericHelper(&variables, L"NTSuiteSmallBusinessRestricted");
482 VariableGetNumericHelper(&variables, L"NTSuiteWebServer");
483 VariableGetNumericHelper(&variables, L"CompatibilityMode");
484 VariableGetNumericHelper(&variables, L"Privileged");
485 VariableGetNumericHelper(&variables, L"SystemLanguageID");
486 VariableGetNumericHelper(&variables, L"TerminalServer");
487 VariableGetNumericHelper(&variables, L"UserUILanguageID");
488 VariableGetNumericHelper(&variables, L"UserLanguageID");
489
490 // known folders
491 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::ApplicationData) + "\\", VariableGetStringHelper(&variables, L"AppDataFolder"));
492 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::CommonApplicationData) + "\\", VariableGetStringHelper(&variables, L"CommonAppDataFolder"));
493
494 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::ProgramFiles) + "\\", VariableGetStringHelper(&variables, L"ProgramFilesFolder"));
495 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::DesktopDirectory) + "\\", VariableGetStringHelper(&variables, L"DesktopFolder"));
496 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::Favorites) + "\\", VariableGetStringHelper(&variables, L"FavoritesFolder"));
497 VariableGetStringHelper(&variables, L"FontsFolder");
498 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData) + "\\", VariableGetStringHelper(&variables, L"LocalAppDataFolder"));
499 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::Personal) + "\\", VariableGetStringHelper(&variables, L"PersonalFolder"));
500 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::Programs) + "\\", VariableGetStringHelper(&variables, L"ProgramMenuFolder"));
501 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::SendTo) + "\\", VariableGetStringHelper(&variables, L"SendToFolder"));
502 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::StartMenu) + "\\", VariableGetStringHelper(&variables, L"StartMenuFolder"));
503 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::Startup) + "\\", VariableGetStringHelper(&variables, L"StartupFolder"));
504 VariableGetStringHelper(&variables, L"SystemFolder");
505 VariableGetStringHelper(&variables, L"WindowsFolder");
506 VariableGetStringHelper(&variables, L"WindowsVolume");
507
508 Assert::Equal<String^>(System::IO::Path::GetTempPath(), System::IO::Path::GetFullPath(VariableGetStringHelper(&variables, L"TempFolder")));
509
510 VariableGetStringHelper(&variables, L"AdminToolsFolder");
511 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::CommonProgramFiles) + "\\", VariableGetStringHelper(&variables, L"CommonFilesFolder"));
512 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::MyPictures) + "\\", VariableGetStringHelper(&variables, L"MyPicturesFolder"));
513 Assert::Equal<String^>(Environment::GetFolderPath(Environment::SpecialFolder::Templates) + "\\", VariableGetStringHelper(&variables, L"TemplateFolder"));
514
515 if (Environment::Is64BitOperatingSystem)
516 {
517 VariableGetStringHelper(&variables, L"ProgramFiles64Folder");
518 VariableGetStringHelper(&variables, L"CommonFiles64Folder");
519 VariableGetStringHelper(&variables, L"System64Folder");
520 }
521 }
522 finally
523 {
524 VariablesUninitialize(&variables);
525 }
526 }
527 };
528}
529}
530}
531}
532}
diff --git a/src/burn/test/BurnUnitTest/VariantTest.cpp b/src/burn/test/BurnUnitTest/VariantTest.cpp
new file mode 100644
index 00000000..43899a2b
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/VariantTest.cpp
@@ -0,0 +1,221 @@
1// 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.
2
3#include "precomp.h"
4
5namespace Microsoft
6{
7namespace Tools
8{
9namespace WindowsInstallerXml
10{
11namespace Test
12{
13namespace Bootstrapper
14{
15 using namespace System;
16 using namespace Xunit;
17
18 public ref class VariantTest : BurnUnitTest
19 {
20 public:
21 VariantTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
22 {
23 }
24
25 [Fact]
26 void VariantBasicTest()
27 {
28 BURN_VARIANT expectedVariants[10];
29 BURN_VARIANT actualVariants[10];
30 for (DWORD i = 0; i < 10; i++)
31 {
32 BVariantUninitialize(expectedVariants + i);
33 BVariantUninitialize(actualVariants + i);
34 }
35
36 try
37 {
38 InitNumericValue(expectedVariants + 0, 2, FALSE, L"PROP1", actualVariants + 0);
39 InitStringValue(expectedVariants + 1, L"VAL2", FALSE, L"PROP2", actualVariants + 1);
40 InitVersionValue(expectedVariants + 2, L"1.1.0.0", FALSE, L"PROP3", actualVariants + 2);
41 InitNoneValue(expectedVariants + 3, FALSE, L"PROP4", actualVariants + 3);
42 InitNoneValue(expectedVariants + 4, TRUE, L"PROP5", actualVariants + 4);
43 InitVersionValue(expectedVariants + 5, L"1.1.1.0", TRUE, L"PROP6", actualVariants + 5);
44 InitStringValue(expectedVariants + 6, L"7", TRUE, L"PROP7", actualVariants + 6);
45 InitNumericValue(expectedVariants + 7, 11, TRUE, L"PROP8", actualVariants + 7);
46 InitFormattedValue(expectedVariants + 8, L"VAL9", FALSE, L"PROP9", actualVariants + 8);
47 InitFormattedValue(expectedVariants + 9, L"VAL10", TRUE, L"PROP10", actualVariants + 9);
48
49 VerifyNumericValue(expectedVariants + 0, actualVariants + 0);
50 VerifyStringValue(expectedVariants + 1, actualVariants + 1);
51 VerifyVersionValue(expectedVariants + 2, actualVariants + 2);
52 VerifyNoneValue(expectedVariants + 3, actualVariants + 3);
53 VerifyNoneValue(expectedVariants + 4, actualVariants + 4);
54 VerifyVersionValue(expectedVariants + 5, actualVariants + 5);
55 VerifyStringValue(expectedVariants + 6, actualVariants + 6);
56 VerifyNumericValue(expectedVariants + 7, actualVariants + 7);
57 VerifyFormattedValue(expectedVariants + 8, actualVariants + 8);
58 VerifyFormattedValue(expectedVariants + 9, actualVariants + 9);
59 }
60 finally
61 {
62 for (DWORD i = 0; i < 10; i++)
63 {
64 BVariantUninitialize(expectedVariants + i);
65 BVariantUninitialize(actualVariants + i);
66 }
67 }
68 }
69
70 private:
71 void InitFormattedValue(BURN_VARIANT* pValue, LPWSTR wzValue, BOOL /*fHidden*/, LPCWSTR wz, BURN_VARIANT* pActualValue)
72 {
73 HRESULT hr = S_OK;
74 pValue->Type = BURN_VARIANT_TYPE_FORMATTED;
75
76 hr = StrAllocString(&pValue->sczValue, wzValue, 0);
77 NativeAssert::Succeeded(hr, "Failed to alloc string: {0}", wzValue);
78
79 hr = BVariantCopy(pValue, pActualValue);
80 NativeAssert::Succeeded(hr, "Failed to copy variant {0}", wz);
81 }
82
83 void InitNoneValue(BURN_VARIANT* pValue, BOOL /*fHidden*/, LPCWSTR wz, BURN_VARIANT* pActualValue)
84 {
85 HRESULT hr = S_OK;
86 pValue->Type = BURN_VARIANT_TYPE_NONE;
87
88 hr = BVariantCopy(pValue, pActualValue);
89 NativeAssert::Succeeded(hr, "Failed to copy variant {0}", wz);
90 }
91
92 void InitNumericValue(BURN_VARIANT* pValue, LONGLONG llValue, BOOL /*fHidden*/, LPCWSTR wz, BURN_VARIANT* pActualValue)
93 {
94 HRESULT hr = S_OK;
95 pValue->Type = BURN_VARIANT_TYPE_NUMERIC;
96 pValue->llValue = llValue;
97
98 hr = BVariantCopy(pValue, pActualValue);
99 NativeAssert::Succeeded(hr, "Failed to copy variant {0}", wz);
100 }
101
102 void InitStringValue(BURN_VARIANT* pValue, LPWSTR wzValue, BOOL /*fHidden*/, LPCWSTR wz, BURN_VARIANT* pActualValue)
103 {
104 HRESULT hr = S_OK;
105 pValue->Type = BURN_VARIANT_TYPE_STRING;
106
107 hr = StrAllocString(&pValue->sczValue, wzValue, 0);
108 NativeAssert::Succeeded(hr, "Failed to alloc string: {0}", wzValue);
109
110 hr = BVariantCopy(pValue, pActualValue);
111 NativeAssert::Succeeded(hr, "Failed to copy variant {0}", wz);
112 }
113
114 void InitVersionValue(BURN_VARIANT* pValue, LPCWSTR wzValue, BOOL /*fHidden*/, LPCWSTR wz, BURN_VARIANT* pActualValue)
115 {
116 HRESULT hr = S_OK;
117 VERUTIL_VERSION* pVersion = NULL;
118
119 try
120 {
121 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
122 NativeAssert::Succeeded(hr, "Failed to parse version {0}", wzValue);
123
124 pValue->Type = BURN_VARIANT_TYPE_VERSION;
125 pValue->pValue = pVersion;
126 pVersion = NULL;
127
128 hr = BVariantCopy(pValue, pActualValue);
129 NativeAssert::Succeeded(hr, "Failed to copy variant {0}", wz);
130 }
131 finally
132 {
133 ReleaseVerutilVersion(pVersion);
134 }
135 }
136
137 void VerifyFormattedValue(BURN_VARIANT* pExpectedValue, BURN_VARIANT* pActualValue)
138 {
139 HRESULT hr = S_OK;
140 LPWSTR sczValue = NULL;
141 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_FORMATTED, pExpectedValue->Type);
142 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_FORMATTED, pActualValue->Type);
143
144 try
145 {
146 hr = BVariantGetString(pActualValue, &sczValue);
147 NativeAssert::Succeeded(hr, "Failed to get string value");
148
149 NativeAssert::StringEqual(pExpectedValue->sczValue, sczValue);
150 }
151 finally
152 {
153 ReleaseStr(sczValue);
154 }
155 }
156
157 void VerifyNumericValue(BURN_VARIANT* pExpectedValue, BURN_VARIANT* pActualValue)
158 {
159 HRESULT hr = S_OK;
160 LONGLONG llValue = 0;
161 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_NUMERIC, pExpectedValue->Type);
162 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_NUMERIC, pActualValue->Type);
163
164 hr = BVariantGetNumeric(pActualValue, &llValue);
165 NativeAssert::Succeeded(hr, "Failed to get numeric value");
166
167 NativeAssert::Equal<LONGLONG>(pExpectedValue->llValue, llValue);
168 }
169
170 void VerifyNoneValue(BURN_VARIANT* pExpectedValue, BURN_VARIANT* pActualValue)
171 {
172 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_NONE, pExpectedValue->Type);
173 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_NONE, pActualValue->Type);
174 NativeAssert::Equal<LONGLONG>(pExpectedValue->llValue, pActualValue->llValue);
175 }
176
177 void VerifyStringValue(BURN_VARIANT* pExpectedValue, BURN_VARIANT* pActualValue)
178 {
179 HRESULT hr = S_OK;
180 LPWSTR sczValue = NULL;
181 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_STRING, pExpectedValue->Type);
182 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_STRING, pActualValue->Type);
183
184 try
185 {
186 hr = BVariantGetString(pActualValue, &sczValue);
187 NativeAssert::Succeeded(hr, "Failed to get string value");
188
189 NativeAssert::StringEqual(pExpectedValue->sczValue, sczValue);
190 }
191 finally
192 {
193 ReleaseStr(sczValue);
194 }
195 }
196
197 void VerifyVersionValue(BURN_VARIANT* pExpectedValue, BURN_VARIANT* pActualValue)
198 {
199 HRESULT hr = S_OK;
200 VERUTIL_VERSION* pValue = NULL;
201 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_VERSION, pExpectedValue->Type);
202 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_VERSION, pActualValue->Type);
203
204 try
205 {
206 hr = BVariantGetVersion(pActualValue, &pValue);
207 NativeAssert::Succeeded(hr, "Failed to get version value");
208
209 NativeAssert::StringEqual(pExpectedValue->pValue->sczVersion, pActualValue->pValue->sczVersion);
210 }
211 finally
212 {
213 ReleaseVerutilVersion(pValue);
214 }
215 }
216 };
217}
218}
219}
220}
221}
diff --git a/src/burn/test/BurnUnitTest/packages.config b/src/burn/test/BurnUnitTest/packages.config
new file mode 100644
index 00000000..1d36c387
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/packages.config
@@ -0,0 +1,15 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3<packages>
4 <package id="WixBuildTools.TestSupport" version="4.0.47" />
5 <package id="WixBuildTools.TestSupport.Native" version="4.0.47" />
6 <package id="WixToolset.DUtil" version="4.0.70" targetFramework="native" />
7 <package id="WixToolset.BootstrapperCore.Native" version="4.0.57" targetFramework="native" />
8 <package id="xunit.abstractions" version="2.0.3" />
9 <package id="xunit.assert" version="2.4.1" />
10 <package id="xunit.core" version="2.4.1" />
11 <package id="xunit.extensibility.core" version="2.4.1" />
12 <package id="xunit.extensibility.execution" version="2.4.1" />
13 <package id="xunit.runner.msbuild" version="2.4.1" />
14 <package id="xunit.runner.visualstudio" version="2.4.1" />
15</packages> \ No newline at end of file
diff --git a/src/burn/test/BurnUnitTest/precomp.cpp b/src/burn/test/BurnUnitTest/precomp.cpp
new file mode 100644
index 00000000..37664a1c
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/precomp.cpp
@@ -0,0 +1,3 @@
1// 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.
2
3#include "precomp.h"
diff --git a/src/burn/test/BurnUnitTest/precomp.h b/src/burn/test/BurnUnitTest/precomp.h
new file mode 100644
index 00000000..d2b57d61
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/precomp.h
@@ -0,0 +1,79 @@
1#pragma once
2// 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.
3
4
5#include <windows.h>
6#include <Bits.h>
7#include <msiquery.h>
8#include <objbase.h>
9#include <shlobj.h>
10#include <shlwapi.h>
11#include <stdlib.h>
12#include <strsafe.h>
13#include "wininet.h"
14
15#include <dutil.h>
16#include <verutil.h>
17#include <cryputil.h>
18#include <dlutil.h>
19#include <buffutil.h>
20#include <dirutil.h>
21#include <fileutil.h>
22#include <logutil.h>
23#include <memutil.h>
24#include <pathutil.h>
25#include <regutil.h>
26#include <resrutil.h>
27#include <shelutil.h>
28#include <strutil.h>
29#include <wiutil.h>
30#include <xmlutil.h>
31#include <dictutil.h>
32#include <deputil.h>
33
34#include "BootstrapperEngine.h"
35#include "BootstrapperApplication.h"
36#include "BundleExtensionEngine.h"
37#include "BundleExtension.h"
38
39#include "platform.h"
40#include "variant.h"
41#include "variable.h"
42#include "condition.h"
43#include "section.h"
44#include "approvedexe.h"
45#include "container.h"
46#include "payload.h"
47#include "cabextract.h"
48#include "burnextension.h"
49#include "search.h"
50#include "userexperience.h"
51#include "package.h"
52#include "update.h"
53#include "pseudobundle.h"
54#include "registration.h"
55#include "plan.h"
56#include "pipe.h"
57#include "logging.h"
58#include "core.h"
59#include "cache.h"
60#include "apply.h"
61#include "exeengine.h"
62#include "msiengine.h"
63#include "mspengine.h"
64#include "msuengine.h"
65#include "dependency.h"
66#include "elevation.h"
67#include "embedded.h"
68#include "manifest.h"
69#include "splashscreen.h"
70#include "detect.h"
71
72#pragma managed
73#include <vcclr.h>
74
75#include "BurnTestException.h"
76#include "BurnTestFixture.h"
77#include "BurnUnitTest.h"
78#include "VariableHelpers.h"
79#include "ManifestHelpers.h"