@joebigelow / wix-1 / commits / 8bcb8c01

Import BurnUnitTest from old wix4 repo.

Sean Hall committed Jul 15, 2020 at 21:41 UTC 8bcb8c013a258691d4004c50af4689b90dd05c45
19 files changed +2928
src/test/BurnUnitTest/AssemblyInfo.cpp new
+12
@@ -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 +
5 +using namespace System::Reflection;
6 +using namespace System::Runtime::CompilerServices;
7 +using 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)];
src/test/BurnUnitTest/BurnTestException.h new
+93
@@ -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 +
5 +namespace Microsoft
6 +{
7 +namespace Tools
8 +{
9 +namespace WindowsInstallerXml
10 +{
11 +namespace Test
12 +{
13 +namespace 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
48 +class __TestThrowOnFailure_StringFree
49 +{
50 + LPWSTR m_scz;
51 +
52 +public:
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)
73 +inline __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 +
86 +LExit:
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))); }
src/test/BurnUnitTest/BurnTestFixture.h new
+41
@@ -0,0 +1,41 @@
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 +namespace Microsoft
6 +{
7 +namespace Tools
8 +{
9 +namespace WindowsInstallerXml
10 +{
11 +namespace Test
12 +{
13 +namespace Bootstrapper
14 +{
15 + using namespace System;
16 +
17 + public ref class BurnTestFixture
18 + {
19 + public:
20 + BurnTestFixture()
21 + {
22 + HRESULT hr = XmlInitialize();
23 + TestThrowOnFailure(hr, L"Failed to initialize XML support.");
24 +
25 + hr = RegInitialize();
26 + TestThrowOnFailure(hr, L"Failed to initialize Regutil.");
27 +
28 + PlatformInitialize();
29 + }
30 +
31 + ~BurnTestFixture()
32 + {
33 + XmlUninitialize();
34 + RegUninitialize();
35 + }
36 + };
37 +}
38 +}
39 +}
40 +}
41 +}
src/test/BurnUnitTest/BurnUnitTest.h new
+55
@@ -0,0 +1,55 @@
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 +namespace Microsoft
6 +{
7 +namespace Tools
8 +{
9 +namespace WindowsInstallerXml
10 +{
11 +namespace Test
12 +{
13 +namespace Bootstrapper
14 +{
15 + using namespace System;
16 + using namespace WixTest;
17 + using namespace Xunit;
18 +
19 + public ref class BurnUnitTest : WixTestBase, IUseFixture<BurnTestFixture^>
20 + {
21 + public:
22 + BurnUnitTest()
23 + {
24 + }
25 +
26 + virtual void TestInitialize() override
27 + {
28 + WixTestBase::TestInitialize();
29 +
30 + HRESULT hr = S_OK;
31 +
32 + LogInitialize(::GetModuleHandleW(NULL));
33 +
34 + hr = LogOpen(NULL, L"BurnUnitTest", NULL, L"txt", FALSE, FALSE, NULL);
35 + TestThrowOnFailure(hr, L"Failed to open log.");
36 + }
37 +
38 + virtual void TestUninitialize() override
39 + {
40 + LogUninitialize(FALSE);
41 +
42 + WixTestBase::TestUninitialize();
43 + }
44 +
45 + virtual void SetFixture(BurnTestFixture^ fixture)
46 + {
47 + // Don't care about the fixture, just need it to be created and disposed.
48 + UNREFERENCED_PARAMETER(fixture);
49 + }
50 + };
51 +}
52 +}
53 +}
54 +}
55 +}
src/test/BurnUnitTest/BurnUnitTest.rc new
+7
@@ -0,0 +1,7 @@
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"
7 +#include "wix.rc"
src/test/BurnUnitTest/BurnUnitTest.vcxproj new
+60
@@ -0,0 +1,60 @@
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 +
5 +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
6 + <ItemGroup Label="ProjectConfigurations">
7 + <ProjectConfiguration Include="Debug|Win32">
8 + <Configuration>Debug</Configuration>
9 + <Platform>Win32</Platform>
10 + </ProjectConfiguration>
11 + <ProjectConfiguration Include="Release|Win32">
12 + <Configuration>Release</Configuration>
13 + <Platform>Win32</Platform>
14 + </ProjectConfiguration>
15 + </ItemGroup>
16 + <PropertyGroup Label="Globals">
17 + <ProjectTypes>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}</ProjectTypes>
18 + <ProjectGuid>{9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}</ProjectGuid>
19 + <RootNamespace>UnitTest</RootNamespace>
20 + <Keyword>ManagedCProj</Keyword>
21 + <ConfigurationType>DynamicLibrary</ConfigurationType>
22 + <CharacterSet>Unicode</CharacterSet>
23 + <CLRSupport>true</CLRSupport>
24 + </PropertyGroup>
25 + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.props" />
26 + <PropertyGroup>
27 + <ProjectAdditionalIncludeDirectories>$(WixRoot)src\libs\dutil\inc;$(WixRoot)src\burn\inc;$(WixRoot)src\burn\engine;$(WixRoot)src\libs\deputil\inc</ProjectAdditionalIncludeDirectories>
28 + <ProjectAdditionalLinkLibraries>cabinet.lib;crypt32.lib;msi.lib;rpcrt4.lib;shlwapi.lib;wininet.lib;wintrust.lib;dutil.lib;deputil.lib;engine.lib;gdiplus.lib</ProjectAdditionalLinkLibraries>
29 + </PropertyGroup>
30 + <ItemGroup>
31 + <ClCompile Include="AssemblyInfo.cpp" />
32 + <ClCompile Include="ElevationTest.cpp" />
33 + <ClCompile Include="ManifestHelpers.cpp" />
34 + <ClCompile Include="ManifestTest.cpp" />
35 + <ClCompile Include="RegistrationTest.cpp" />
36 + <ClCompile Include="SearchTest.cpp" />
37 + <ClCompile Include="CacheTest.cpp" />
38 + <ClCompile Include="VariableHelpers.cpp" />
39 + <ClCompile Include="VariableTest.cpp" />
40 + </ItemGroup>
41 + <ItemGroup>
42 + <ClInclude Include="BurnTestException.h" />
43 + <ClInclude Include="BurnTestFixture.h" />
44 + <ClInclude Include="BurnUnitTest.h" />
45 + <ClInclude Include="ManifestHelpers.h" />
46 + <ClInclude Include="precomp.h" />
47 + <ClInclude Include="VariableHelpers.h" />
48 + </ItemGroup>
49 + <ItemGroup>
50 + <ResourceCompile Include="BurnUnitTest.rc" />
51 + </ItemGroup>
52 + <ItemGroup>
53 + <Reference Include="System" />
54 + <ProjectReference Include="..\..\WixTestTools\WixTestTools.csproj" />
55 + <Reference Include="xunit, Version=1.9.2.1705, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
56 + <HintPath>$(XunitPath)\xunit.dll</HintPath>
57 + </Reference>
58 + </ItemGroup>
59 + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
60 +</Project>
src/test/BurnUnitTest/BurnUnitTest.vcxproj.filters new
+74
@@ -0,0 +1,74 @@
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="ElevationTest.cpp">
22 + <Filter>Source Files</Filter>
23 + </ClCompile>
24 + <ClCompile Include="ManifestHelpers.cpp">
25 + <Filter>Source Files</Filter>
26 + </ClCompile>
27 + <ClCompile Include="ManifestTest.cpp">
28 + <Filter>Source Files</Filter>
29 + </ClCompile>
30 + <ClCompile Include="RegistrationTest.cpp">
31 + <Filter>Source Files</Filter>
32 + </ClCompile>
33 + <ClCompile Include="SearchTest.cpp">
34 + <Filter>Source Files</Filter>
35 + </ClCompile>
36 + <ClCompile Include="VariableHelpers.cpp">
37 + <Filter>Source Files</Filter>
38 + </ClCompile>
39 + <ClCompile Include="VariableTest.cpp">
40 + <Filter>Source Files</Filter>
41 + </ClCompile>
42 + <ClCompile Include="CacheTest.cpp">
43 + <Filter>Source Files</Filter>
44 + </ClCompile>
45 + <ClCompile Include="$(WixRoot)src\common\precomp.cpp">
46 + <Filter>Source Files</Filter>
47 + </ClCompile>
48 + </ItemGroup>
49 + <ItemGroup>
50 + <ClInclude Include="BurnTestException.h">
51 + <Filter>Header Files</Filter>
52 + </ClInclude>
53 + <ClInclude Include="ManifestHelpers.h">
54 + <Filter>Header Files</Filter>
55 + </ClInclude>
56 + <ClInclude Include="precomp.h">
57 + <Filter>Header Files</Filter>
58 + </ClInclude>
59 + <ClInclude Include="VariableHelpers.h">
60 + <Filter>Header Files</Filter>
61 + </ClInclude>
62 + <ClInclude Include="BurnUnitTest.h">
63 + <Filter>Header Files</Filter>
64 + </ClInclude>
65 + <ClInclude Include="BurnTestFixture.h">
66 + <Filter>Header Files</Filter>
67 + </ClInclude>
68 + </ItemGroup>
69 + <ItemGroup>
70 + <ResourceCompile Include="BurnUnitTest.rc">
71 + <Filter>Resource Files</Filter>
72 + </ResourceCompile>
73 + </ItemGroup>
74 +</Project>
\ No newline at end of file
src/test/BurnUnitTest/CacheTest.cpp new
+72
@@ -0,0 +1,72 @@
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 +namespace Microsoft
7 +{
8 +namespace Tools
9 +{
10 +namespace WindowsInstallerXml
11 +{
12 +namespace Test
13 +{
14 +namespace Bootstrapper
15 +{
16 + using namespace System;
17 + using namespace System::IO;
18 + using namespace WixTest;
19 + using namespace Xunit;
20 +
21 + public ref class CacheTest : BurnUnitTest
22 + {
23 + public:
24 + [NamedFact]
25 + void CacheSignatureTest()
26 + {
27 + HRESULT hr = S_OK;
28 + BURN_PACKAGE package = { };
29 + BURN_PAYLOAD payload = { };
30 + LPWSTR sczPayloadPath = NULL;
31 + BYTE* pb = NULL;
32 + DWORD cb = NULL;
33 +
34 + try
35 + {
36 + pin_ptr<const wchar_t> dataDirectory = PtrToStringChars(TestContext->DataDirectory);
37 + hr = PathConcat(dataDirectory, L"BurnTestPayloads\\Products\\TestExe\\TestExe.exe", &sczPayloadPath);
38 + Assert::True(S_OK == hr, "Failed to get path to test file.");
39 + Assert::True(FileExistsEx(sczPayloadPath, NULL), "Test file does not exist.");
40 +
41 + hr = StrAllocHexDecode(L"232BD16B78C1926F95D637731E1EE5379A3C4222", &pb, &cb);
42 + Assert::Equal(S_OK, hr);
43 +
44 + package.fPerMachine = FALSE;
45 + package.sczCacheId = L"Bootstrapper.CacheTest.CacheSignatureTest";
46 + payload.sczKey = L"CacheSignatureTest.PayloadKey";
47 + payload.sczFilePath = L"CacheSignatureTest.File";
48 + payload.pbHash = pb;
49 + payload.cbHash = cb;
50 +
51 + hr = CacheCompletePayload(package.fPerMachine, &payload, package.sczCacheId, sczPayloadPath, FALSE);
52 + Assert::Equal(S_OK, hr);
53 + }
54 + finally
55 + {
56 + ReleaseMem(pb);
57 + ReleaseStr(sczPayloadPath);
58 +
59 + String^ filePath = Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), "Package Cache\\Bootstrapper.CacheTest.CacheSignatureTest\\CacheSignatureTest.File");
60 + if (File::Exists(filePath))
61 + {
62 + File::SetAttributes(filePath, FileAttributes::Normal);
63 + File::Delete(filePath);
64 + }
65 + }
66 + }
67 + };
68 +}
69 +}
70 +}
71 +}
72 +}
src/test/BurnUnitTest/ElevationTest.cpp new
+218
@@ -0,0 +1,218 @@
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 +const DWORD TEST_CHILD_SENT_MESSAGE_ID = 0xFFFE;
7 +const DWORD TEST_PARENT_SENT_MESSAGE_ID = 0xFFFF;
8 +const HRESULT S_TEST_SUCCEEDED = 0x3133;
9 +const char TEST_MESSAGE_DATA[] = "{94949868-7EAE-4ac5-BEAC-AFCA2821DE01}";
10 +
11 +
12 +static BOOL STDAPICALLTYPE ElevateTest_ShellExecuteExW(
13 + __inout LPSHELLEXECUTEINFOW lpExecInfo
14 + );
15 +static DWORD CALLBACK ElevateTest_ThreadProc(
16 + __in LPVOID lpThreadParameter
17 + );
18 +static HRESULT ProcessParentMessages(
19 + __in BURN_PIPE_MESSAGE* pMsg,
20 + __in_opt LPVOID pvContext,
21 + __out DWORD* pdwResult
22 + );
23 +static HRESULT ProcessChildMessages(
24 + __in BURN_PIPE_MESSAGE* pMsg,
25 + __in_opt LPVOID pvContext,
26 + __out DWORD* pdwResult
27 + );
28 +
29 +namespace Microsoft
30 +{
31 +namespace Tools
32 +{
33 +namespace WindowsInstallerXml
34 +{
35 +namespace Test
36 +{
37 +namespace Bootstrapper
38 +{
39 + using namespace System;
40 + using namespace System::IO;
41 + using namespace System::Threading;
42 + using namespace WixTest;
43 + using namespace Xunit;
44 +
45 + public ref class ElevationTest : BurnUnitTest
46 + {
47 + public:
48 + [NamedFact]
49 + void ElevateTest()
50 + {
51 + HRESULT hr = S_OK;
52 + BURN_PIPE_CONNECTION connection = { };
53 + HANDLE hEvent = NULL;
54 + DWORD dwResult = S_OK;
55 + try
56 + {
57 + ShelFunctionOverride(ElevateTest_ShellExecuteExW);
58 +
59 + PipeConnectionInitialize(&connection);
60 +
61 + //
62 + // per-user side setup
63 + //
64 + hr = PipeCreateNameAndSecret(&connection.sczName, &connection.sczSecret);
65 + TestThrowOnFailure(hr, L"Failed to create connection name and secret.");
66 +
67 + hr = PipeCreatePipes(&connection, TRUE, &hEvent);
68 + TestThrowOnFailure(hr, L"Failed to create pipes.");
69 +
70 + hr = PipeLaunchChildProcess(L"tests\\ignore\\this\\path\\to\\burn.exe", &connection, TRUE, NULL);
71 + TestThrowOnFailure(hr, L"Failed to create elevated process.");
72 +
73 + hr = PipeWaitForChildConnect(&connection);
74 + TestThrowOnFailure(hr, L"Failed to wait for child process to connect.");
75 +
76 + // post execute message
77 + hr = PipeSendMessage(connection.hPipe, TEST_PARENT_SENT_MESSAGE_ID, NULL, 0, ProcessParentMessages, NULL, &dwResult);
78 + TestThrowOnFailure(hr, "Failed to post execute message to per-machine process.");
79 +
80 + //
81 + // initiate termination
82 + //
83 + hr = PipeTerminateChildProcess(&connection, 666, FALSE);
84 + TestThrowOnFailure(hr, L"Failed to terminate elevated process.");
85 +
86 + // check flags
87 + Assert::Equal(S_TEST_SUCCEEDED, (HRESULT)dwResult);
88 + }
89 + finally
90 + {
91 + PipeConnectionUninitialize(&connection);
92 + ReleaseHandle(hEvent);
93 + }
94 + }
95 + };
96 +}
97 +}
98 +}
99 +}
100 +}
101 +
102 +
103 +static BOOL STDAPICALLTYPE ElevateTest_ShellExecuteExW(
104 + __inout LPSHELLEXECUTEINFOW lpExecInfo
105 + )
106 +{
107 + HRESULT hr = S_OK;
108 + LPWSTR scz = NULL;
109 +
110 + hr = StrAllocString(&scz, lpExecInfo->lpParameters, 0);
111 + ExitOnFailure(hr, "Failed to copy arguments.");
112 +
113 + // Pretend this thread is the elevated process.
114 + lpExecInfo->hProcess = ::CreateThread(NULL, 0, ElevateTest_ThreadProc, scz, 0, NULL);
115 + ExitOnNullWithLastError(lpExecInfo->hProcess, hr, "Failed to create thread.");
116 + scz = NULL;
117 +
118 +LExit:
119 + ReleaseStr(scz);
120 +
121 + return SUCCEEDED(hr);
122 +}
123 +
124 +static DWORD CALLBACK ElevateTest_ThreadProc(
125 + __in LPVOID lpThreadParameter
126 + )
127 +{
128 + HRESULT hr = S_OK;
129 + LPWSTR sczArguments = (LPWSTR)lpThreadParameter;
130 + BURN_PIPE_CONNECTION connection = { };
131 + BURN_PIPE_RESULT result = { };
132 +
133 + PipeConnectionInitialize(&connection);
134 +
135 + StrAlloc(&connection.sczName, MAX_PATH);
136 + StrAlloc(&connection.sczSecret, MAX_PATH);
137 +
138 + // parse command line arguments
139 + if (3 != swscanf_s(sczArguments, L"-q -burn.elevated %s %s %u", connection.sczName, MAX_PATH, connection.sczSecret, MAX_PATH, &connection.dwProcessId))
140 + {
141 + hr = E_INVALIDARG;
142 + ExitOnFailure(hr, "Failed to parse argument string.");
143 + }
144 +
145 + // set up connection with per-user process
146 + hr = PipeChildConnect(&connection, TRUE);
147 + ExitOnFailure(hr, "Failed to connect to per-user process.");
148 +
149 + // pump messages
150 + hr = PipePumpMessages(connection.hPipe, ProcessChildMessages, static_cast<LPVOID>(connection.hPipe), &result);
151 + ExitOnFailure(hr, "Failed while pumping messages in child 'process'.");
152 +
153 +LExit:
154 + PipeConnectionUninitialize(&connection);
155 + ReleaseStr(sczArguments);
156 +
157 + return FAILED(hr) ? (DWORD)hr : result.dwResult;
158 +}
159 +
160 +static HRESULT ProcessParentMessages(
161 + __in BURN_PIPE_MESSAGE* pMsg,
162 + __in_opt LPVOID /*pvContext*/,
163 + __out DWORD* pdwResult
164 + )
165 +{
166 + HRESULT hr = S_OK;
167 + HRESULT hrResult = E_INVALIDDATA;
168 +
169 + // Process the message.
170 + switch (pMsg->dwMessage)
171 + {
172 + case TEST_CHILD_SENT_MESSAGE_ID:
173 + if (sizeof(TEST_MESSAGE_DATA) == pMsg->cbData && 0 == memcmp(TEST_MESSAGE_DATA, pMsg->pvData, sizeof(TEST_MESSAGE_DATA)))
174 + {
175 + hrResult = S_TEST_SUCCEEDED;
176 + }
177 + break;
178 +
179 + default:
180 + hr = E_INVALIDARG;
181 + ExitOnRootFailure(hr, "Unexpected elevated message sent to parent process, msg: %u", pMsg->dwMessage);
182 + }
183 +
184 + *pdwResult = static_cast<DWORD>(hrResult);
185 +
186 +LExit:
187 + return hr;
188 +}
189 +
190 +static HRESULT ProcessChildMessages(
191 + __in BURN_PIPE_MESSAGE* pMsg,
192 + __in_opt LPVOID pvContext,
193 + __out DWORD* pdwResult
194 + )
195 +{
196 + HRESULT hr = S_OK;
197 + HANDLE hPipe = static_cast<HANDLE>(pvContext);
198 + DWORD dwResult = 0;
199 +
200 + // Process the message.
201 + switch (pMsg->dwMessage)
202 + {
203 + case TEST_PARENT_SENT_MESSAGE_ID:
204 + // send test message
205 + hr = PipeSendMessage(hPipe, TEST_CHILD_SENT_MESSAGE_ID, (LPVOID)TEST_MESSAGE_DATA, sizeof(TEST_MESSAGE_DATA), NULL, NULL, &dwResult);
206 + ExitOnFailure(hr, "Failed to send message to per-machine process.");
207 + break;
208 +
209 + default:
210 + hr = E_INVALIDARG;
211 + ExitOnRootFailure(hr, "Unexpected elevated message sent to child process, msg: %u", pMsg->dwMessage);
212 + }
213 +
214 + *pdwResult = dwResult;
215 +
216 +LExit:
217 + return hr;
218 +}
src/test/BurnUnitTest/ManifestHelpers.cpp new
+41
@@ -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 +
6 +using namespace System;
7 +using namespace Xunit;
8 +
9 +
10 +namespace Microsoft
11 +{
12 +namespace Tools
13 +{
14 +namespace WindowsInstallerXml
15 +{
16 +namespace Test
17 +{
18 +namespace 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 +}
src/test/BurnUnitTest/ManifestHelpers.h new
+24
@@ -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 +
5 +namespace Microsoft
6 +{
7 +namespace Tools
8 +{
9 +namespace WindowsInstallerXml
10 +{
11 +namespace Test
12 +{
13 +namespace Bootstrapper
14 +{
15 +
16 +
17 +void LoadBundleXmlHelper(LPCWSTR wzDocument, IXMLDOMElement** ppixeBundle);
18 +
19 +
20 +}
21 +}
22 +}
23 +}
24 +}
src/test/BurnUnitTest/ManifestTest.cpp new
+59
@@ -0,0 +1,59 @@
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 +namespace Microsoft
6 +{
7 +namespace Tools
8 +{
9 +namespace WindowsInstallerXml
10 +{
11 +namespace Test
12 +{
13 +namespace Bootstrapper
14 +{
15 + using namespace System;
16 + using namespace WixTest;
17 + using namespace Xunit;
18 +
19 + public ref class ManifestTest : BurnUnitTest
20 + {
21 + public:
22 + [NamedFact]
23 + void ManifestLoadXmlTest()
24 + {
25 + HRESULT hr = S_OK;
26 + BURN_ENGINE_STATE engineState = { };
27 + try
28 + {
29 + LPCSTR szDocument =
30 + "<Bundle>"
31 + " <UX UxDllPayloadId='ux.dll'>"
32 + " <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
33 + " </UX>"
34 + " <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no' />"
35 + " <Variable Id='Variable1' Type='numeric' Value='1' Hidden='no' Persisted='no' />"
36 + " <RegistrySearch Id='Search1' Type='exists' Root='HKLM' Key='SOFTWARE\\Microsoft' Variable='Variable1' Condition='0' />"
37 + "</Bundle>";
38 +
39 + hr = VariableInitialize(&engineState.variables);
40 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
41 +
42 + // load manifest from XML
43 + hr = ManifestLoadXmlFromBuffer((BYTE*)szDocument, lstrlenA(szDocument), &engineState);
44 + TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
45 +
46 + // check variable values
47 + Assert::True(VariableExistsHelper(&engineState.variables, L"Variable1"));
48 + }
49 + finally
50 + {
51 + //CoreUninitialize(&engineState);
52 + }
53 + }
54 + };
55 +}
56 +}
57 +}
58 +}
59 +}
src/test/BurnUnitTest/RegistrationTest.cpp new
+655
@@ -0,0 +1,655 @@
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 +
16 +static 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 + );
27 +static 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 + );
34 +static LSTATUS APIENTRY RegistrationTest_RegDeleteKeyExW(
35 + __in HKEY hKey,
36 + __in LPCWSTR lpSubKey,
37 + __in REGSAM samDesired,
38 + __reserved DWORD Reserved
39 + );
40 +
41 +namespace Microsoft
42 +{
43 +namespace Tools
44 +{
45 +namespace WindowsInstallerXml
46 +{
47 +namespace Test
48 +{
49 +namespace Bootstrapper
50 +{
51 + using namespace Microsoft::Win32;
52 + using namespace System;
53 + using namespace System::IO;
54 + using namespace WixTest;
55 + using namespace Xunit;
56 +
57 + public ref class RegistrationTest : BurnUnitTest
58 + {
59 + public:
60 + [NamedFact]
61 + void RegisterBasicTest()
62 + {
63 + HRESULT hr = S_OK;
64 + IXMLDOMElement* pixeBundle = NULL;
65 + LPWSTR sczCurrentProcess = NULL;
66 + BURN_VARIABLES variables = { };
67 + BURN_USER_EXPERIENCE userExperience = { };
68 + BOOTSTRAPPER_COMMAND command = { };
69 + BURN_REGISTRATION registration = { };
70 + BURN_LOGGING logging = { };
71 + String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
72 + try
73 + {
74 + // set mock API's
75 + RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
76 +
77 + Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
78 +
79 + logging.sczPath = L"BurnUnitTest.txt";
80 +
81 + LPCWSTR wzDocument =
82 + L"<Bundle>"
83 + L" <UX>"
84 + L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
85 + L" </UX>"
86 + 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'>"
87 + L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
88 + L" </Registration>"
89 + L"</Bundle>";
90 +
91 + // load XML document
92 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
93 +
94 + hr = VariableInitialize(&variables);
95 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
96 +
97 + hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
98 + TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
99 +
100 + hr = RegistrationParseFromXml(&registration, pixeBundle);
101 + TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
102 +
103 + hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
104 + TestThrowOnFailure(hr, L"Failed to set registration resume command.");
105 +
106 + hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
107 + TestThrowOnFailure(hr, L"Failed to get current process path.");
108 +
109 + // write registration
110 + hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
111 + TestThrowOnFailure(hr, L"Failed to register bundle.");
112 +
113 + // verify that registration was created
114 + Assert::True(Directory::Exists(cacheDirectory));
115 + Assert::True(File::Exists(Path::Combine(cacheDirectory, gcnew String(L"setup.exe"))));
116 +
117 + Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
118 + Assert::Equal(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)));
119 +
120 + // end session
121 + hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
122 + TestThrowOnFailure(hr, L"Failed to unregister bundle.");
123 +
124 + // verify that registration was removed
125 + Assert::False(Directory::Exists(cacheDirectory));
126 +
127 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
128 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
129 + }
130 + finally
131 + {
132 + ReleaseStr(sczCurrentProcess);
133 + ReleaseObject(pixeBundle);
134 + UserExperienceUninitialize(&userExperience);
135 + RegistrationUninitialize(&registration);
136 + VariablesUninitialize(&variables);
137 +
138 + Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
139 + if (Directory::Exists(cacheDirectory))
140 + {
141 + Directory::Delete(cacheDirectory, true);
142 + }
143 +
144 + RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
145 + }
146 + }
147 +
148 + [NamedFact]
149 + void RegisterArpMinimumTest()
150 + {
151 + HRESULT hr = S_OK;
152 + IXMLDOMElement* pixeBundle = NULL;
153 + LPWSTR sczCurrentProcess = NULL;
154 + BURN_VARIABLES variables = { };
155 + BURN_USER_EXPERIENCE userExperience = { };
156 + BOOTSTRAPPER_COMMAND command = { };
157 + BURN_REGISTRATION registration = { };
158 + BURN_LOGGING logging = { };
159 + String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
160 + try
161 + {
162 + // set mock API's
163 + RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
164 +
165 + Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
166 +
167 + logging.sczPath = L"BurnUnitTest.txt";
168 +
169 + LPCWSTR wzDocument =
170 + L"<Bundle>"
171 + L" <UX>"
172 + L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
173 + L" </UX>"
174 + 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'>"
175 + L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='Product1' DisplayVersion='1.0.0.0' />"
176 + L" </Registration>"
177 + L"</Bundle>";
178 +
179 + // load XML document
180 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
181 +
182 + hr = VariableInitialize(&variables);
183 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
184 +
185 + hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
186 + TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
187 +
188 + hr = RegistrationParseFromXml(&registration, pixeBundle);
189 + TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
190 +
191 + hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
192 + TestThrowOnFailure(hr, L"Failed to set registration resume command.");
193 +
194 + hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
195 + TestThrowOnFailure(hr, L"Failed to get current process path.");
196 +
197 + //
198 + // install
199 + //
200 +
201 + // write registration
202 + hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
203 + TestThrowOnFailure(hr, L"Failed to register bundle.");
204 +
205 + // verify that registration was created
206 + Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
207 + Assert::Equal(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));
208 +
209 + // complete registration
210 + hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
211 + TestThrowOnFailure(hr, L"Failed to unregister bundle.");
212 +
213 + // verify that registration was updated
214 + Assert::Equal(Int32(BURN_RESUME_MODE_ARP), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
215 + Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
216 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
217 +
218 + //
219 + // uninstall
220 + //
221 +
222 + // write registration
223 + hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER, 0);
224 + TestThrowOnFailure(hr, L"Failed to register bundle.");
225 +
226 + // verify that registration was updated
227 + Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
228 + Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
229 + Assert::Equal(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));
230 +
231 + // delete registration
232 + hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
233 + TestThrowOnFailure(hr, L"Failed to unregister bundle.");
234 +
235 + // verify that registration was removed
236 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
237 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
238 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
239 + }
240 + finally
241 + {
242 + ReleaseStr(sczCurrentProcess);
243 + ReleaseObject(pixeBundle);
244 + UserExperienceUninitialize(&userExperience);
245 + RegistrationUninitialize(&registration);
246 + VariablesUninitialize(&variables);
247 +
248 + Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
249 + if (Directory::Exists(cacheDirectory))
250 + {
251 + Directory::Delete(cacheDirectory, true);
252 + }
253 +
254 + RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
255 + }
256 + }
257 +
258 + [NamedFact]
259 + void RegisterArpFullTest()
260 + {
261 + HRESULT hr = S_OK;
262 + IXMLDOMElement* pixeBundle = NULL;
263 + LPWSTR sczCurrentProcess = NULL;
264 + BURN_VARIABLES variables = { };
265 + BURN_USER_EXPERIENCE userExperience = { };
266 + BOOTSTRAPPER_COMMAND command = { };
267 + BURN_REGISTRATION registration = { };
268 + BURN_LOGGING logging = { };
269 + String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
270 + try
271 + {
272 + // set mock API's
273 + RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
274 +
275 + Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
276 +
277 + logging.sczPath = L"BurnUnitTest.txt";
278 +
279 + LPCWSTR wzDocument =
280 + L"<Bundle>"
281 + L" <UX UxDllPayloadId='ux.dll'>"
282 + L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
283 + L" </UX>"
284 + 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'>"
285 + L" <Arp Register='yes' DisplayName='DisplayName1' DisplayVersion='1.2.3.4' Publisher='Publisher1' HelpLink='http://www.microsoft.com/help'"
286 + L" HelpTelephone='555-555-5555' AboutUrl='http://www.microsoft.com/about' UpdateUrl='http://www.microsoft.com/update'"
287 + L" Comments='Comments1' Contact='Contact1' DisableModify='yes' DisableRemove='yes' />"
288 + L" </Registration>"
289 + L"</Bundle>";
290 +
291 + // load XML document
292 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
293 +
294 + hr = VariableInitialize(&variables);
295 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
296 +
297 + hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
298 + TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
299 +
300 + hr = RegistrationParseFromXml(&registration, pixeBundle);
301 + TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
302 +
303 + hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
304 + TestThrowOnFailure(hr, L"Failed to set registration resume command.");
305 +
306 + hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
307 + TestThrowOnFailure(hr, L"Failed to get current process path.");
308 +
309 + //
310 + // install
311 + //
312 +
313 + // write registration
314 + hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
315 + TestThrowOnFailure(hr, L"Failed to register bundle.");
316 +
317 + // verify that registration was created
318 + Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
319 + Assert::Equal(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));
320 +
321 + // finish registration
322 + hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
323 + TestThrowOnFailure(hr, L"Failed to register bundle.");
324 +
325 + // verify that registration was updated
326 + Assert::Equal(Int32(BURN_RESUME_MODE_ARP), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
327 + Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
328 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
329 +
330 + Assert::Equal(gcnew String(L"DisplayName1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"DisplayName"), nullptr));
331 + Assert::Equal(gcnew String(L"1.2.3.4"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"DisplayVersion"), nullptr));
332 + Assert::Equal(gcnew String(L"Publisher1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Publisher"), nullptr));
333 + Assert::Equal(gcnew String(L"http://www.microsoft.com/help"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"HelpLink"), nullptr));
334 + Assert::Equal(gcnew String(L"555-555-5555"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"HelpTelephone"), nullptr));
335 + Assert::Equal(gcnew String(L"http://www.microsoft.com/about"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"URLInfoAbout"), nullptr));
336 + Assert::Equal(gcnew String(L"http://www.microsoft.com/update"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"URLUpdateInfo"), nullptr));
337 + Assert::Equal(gcnew String(L"Comments1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Comments"), nullptr));
338 + Assert::Equal(gcnew String(L"Contact1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Contact"), nullptr));
339 + Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"NoModify"), nullptr));
340 + Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"NoRemove"), nullptr));
341 +
342 + //
343 + // uninstall
344 + //
345 +
346 + // write registration
347 + hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER, 0);
348 + TestThrowOnFailure(hr, L"Failed to register bundle.");
349 +
350 + // verify that registration was updated
351 + Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
352 + Assert::Equal(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));
353 +
354 + // delete registration
355 + hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
356 + TestThrowOnFailure(hr, L"Failed to unregister bundle.");
357 +
358 + // verify that registration was removed
359 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
360 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
361 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
362 + }
363 + finally
364 + {
365 + ReleaseStr(sczCurrentProcess);
366 + ReleaseObject(pixeBundle);
367 + UserExperienceUninitialize(&userExperience);
368 + RegistrationUninitialize(&registration);
369 + VariablesUninitialize(&variables);
370 +
371 + Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
372 + if (Directory::Exists(cacheDirectory))
373 + {
374 + Directory::Delete(cacheDirectory, true);
375 + }
376 +
377 + RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
378 + }
379 + }
380 +
381 + [NamedFact]
382 + void ResumeTest()
383 + {
384 + HRESULT hr = S_OK;
385 + IXMLDOMElement* pixeBundle = NULL;
386 + LPWSTR sczCurrentProcess = NULL;
387 + BURN_VARIABLES variables = { };
388 + BURN_USER_EXPERIENCE userExperience = { };
389 + BOOTSTRAPPER_COMMAND command = { };
390 + BURN_REGISTRATION registration = { };
391 + BURN_LOGGING logging = { };
392 + BYTE rgbData[256] = { };
393 + BOOTSTRAPPER_RESUME_TYPE resumeType = BOOTSTRAPPER_RESUME_TYPE_NONE;
394 + BYTE* pbBuffer = NULL;
395 + DWORD cbBuffer = 0;
396 + String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
397 + try
398 + {
399 + for (DWORD i = 0; i < 256; ++i)
400 + {
401 + rgbData[i] = (BYTE)i;
402 + }
403 +
404 + // set mock API's
405 + RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
406 +
407 + Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
408 +
409 + logging.sczPath = L"BurnUnitTest.txt";
410 +
411 + LPCWSTR wzDocument =
412 + L"<Bundle>"
413 + L" <UX>"
414 + L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
415 + L" </UX>"
416 + 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'>"
417 + L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
418 + L" </Registration>"
419 + L"</Bundle>";
420 +
421 + // load XML document
422 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
423 +
424 + hr = VariableInitialize(&variables);
425 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
426 +
427 + hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
428 + TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
429 +
430 + hr = RegistrationParseFromXml(&registration, pixeBundle);
431 + TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
432 +
433 + hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
434 + TestThrowOnFailure(hr, L"Failed to set registration resume command.");
435 +
436 + hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
437 + TestThrowOnFailure(hr, L"Failed to get current process path.");
438 +
439 + // read resume type before session
440 + hr = RegistrationDetectResumeType(&registration, &resumeType);
441 + TestThrowOnFailure(hr, L"Failed to read resume type.");
442 +
443 + Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_NONE, (int)resumeType);
444 +
445 + // begin session
446 + hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
447 + TestThrowOnFailure(hr, L"Failed to register bundle.");
448 +
449 + hr = RegistrationSaveState(&registration, rgbData, sizeof(rgbData));
450 + TestThrowOnFailure(hr, L"Failed to save state.");
451 +
452 + // read interrupted resume type
453 + hr = RegistrationDetectResumeType(&registration, &resumeType);
454 + TestThrowOnFailure(hr, L"Failed to read interrupted resume type.");
455 +
456 + Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED, (int)resumeType);
457 +
458 + // suspend session
459 + hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_SUSPEND, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
460 + TestThrowOnFailure(hr, L"Failed to suspend session.");
461 +
462 + // verify that run key was removed
463 + Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
464 +
465 + // read suspend resume type
466 + hr = RegistrationDetectResumeType(&registration, &resumeType);
467 + TestThrowOnFailure(hr, L"Failed to read suspend resume type.");
468 +
469 + Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_SUSPEND, (int)resumeType);
470 +
471 + // read state back
472 + hr = RegistrationLoadState(&registration, &pbBuffer, &cbBuffer);
473 + TestThrowOnFailure(hr, L"Failed to load state.");
474 +
475 + Assert::Equal((DWORD)sizeof(rgbData), cbBuffer);
476 + Assert::True(0 == memcmp(pbBuffer, rgbData, sizeof(rgbData)));
477 +
478 + // write active resume mode
479 + hr = RegistrationSessionResume(&registration, &variables);
480 + TestThrowOnFailure(hr, L"Failed to write active resume mode.");
481 +
482 + // verify that run key was put back
483 + Assert::NotEqual((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
484 +
485 + // end session
486 + hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
487 + TestThrowOnFailure(hr, L"Failed to unregister bundle.");
488 +
489 + // read resume type after session
490 + hr = RegistrationDetectResumeType(&registration, &resumeType);
491 + TestThrowOnFailure(hr, L"Failed to read resume type.");
492 +
493 + Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_NONE, (int)resumeType);
494 + }
495 + finally
496 + {
497 + ReleaseStr(sczCurrentProcess);
498 + ReleaseObject(pixeBundle);
499 + UserExperienceUninitialize(&userExperience);
500 + RegistrationUninitialize(&registration);
501 + VariablesUninitialize(&variables);
502 +
503 + Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
504 + if (Directory::Exists(cacheDirectory))
505 + {
506 + Directory::Delete(cacheDirectory, true);
507 + }
508 +
509 + RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
510 + }
511 + }
512 +
513 + //BOOTSTRAPPER_RESUME_TYPE_NONE,
514 + //BOOTSTRAPPER_RESUME_TYPE_INVALID, // resume information is present but invalid
515 + //BOOTSTRAPPER_RESUME_TYPE_UNEXPECTED, // relaunched after an unexpected interruption
516 + //BOOTSTRAPPER_RESUME_TYPE_REBOOT_PENDING, // reboot has not taken place yet
517 + //BOOTSTRAPPER_RESUME_TYPE_REBOOT, // relaunched after reboot
518 + //BOOTSTRAPPER_RESUME_TYPE_SUSPEND, // relaunched after suspend
519 + //BOOTSTRAPPER_RESUME_TYPE_ARP, // launched from ARP
520 + };
521 +}
522 +}
523 +}
524 +}
525 +}
526 +
527 +
528 +static LSTATUS APIENTRY RegistrationTest_RegCreateKeyExW(
529 + __in HKEY hKey,
530 + __in LPCWSTR lpSubKey,
531 + __reserved DWORD Reserved,
532 + __in_opt LPWSTR lpClass,
533 + __in DWORD dwOptions,
534 + __in REGSAM samDesired,
535 + __in_opt CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
536 + __out PHKEY phkResult,
537 + __out_opt LPDWORD lpdwDisposition
538 + )
539 +{
540 + LSTATUS ls = ERROR_SUCCESS;
541 + LPCWSTR wzRoot = NULL;
542 + HKEY hkRoot = NULL;
543 +
544 + if (HKEY_LOCAL_MACHINE == hKey)
545 + {
546 + wzRoot = HKLM_PATH;
547 + }
548 + else if (HKEY_CURRENT_USER == hKey)
549 + {
550 + wzRoot = HKCU_PATH;
551 + }
552 + else
553 + {
554 + hkRoot = hKey;
555 + }
556 +
557 + if (wzRoot)
558 + {
559 + ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE, &hkRoot);
560 + if (ERROR_SUCCESS != ls)
561 + {
562 + ExitFunction();
563 + }
564 + }
565 +
566 + ls = ::RegCreateKeyExW(hkRoot, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
567 +
568 +LExit:
569 + ReleaseRegKey(hkRoot);
570 +
571 + return ls;
572 +}
573 +
574 +static LSTATUS APIENTRY RegistrationTest_RegOpenKeyExW(
575 + __in HKEY hKey,
576 + __in_opt LPCWSTR lpSubKey,
577 + __reserved DWORD ulOptions,
578 + __in REGSAM samDesired,
579 + __out PHKEY phkResult
580 + )
581 +{
582 + LSTATUS ls = ERROR_SUCCESS;
583 + LPCWSTR wzRoot = NULL;
584 + HKEY hkRoot = NULL;
585 +
586 + if (HKEY_LOCAL_MACHINE == hKey)
587 + {
588 + wzRoot = HKLM_PATH;
589 + }
590 + else if (HKEY_CURRENT_USER == hKey)
591 + {
592 + wzRoot = HKCU_PATH;
593 + }
594 + else
595 + {
596 + hkRoot = hKey;
597 + }
598 +
599 + if (wzRoot)
600 + {
601 + ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE, &hkRoot);
602 + if (ERROR_SUCCESS != ls)
603 + {
604 + ExitFunction();
605 + }
606 + }
607 +
608 + ls = ::RegOpenKeyExW(hkRoot, lpSubKey, ulOptions, samDesired, phkResult);
609 +
610 +LExit:
611 + ReleaseRegKey(hkRoot);
612 +
613 + return ls;
614 +}
615 +
616 +static LSTATUS APIENTRY RegistrationTest_RegDeleteKeyExW(
617 + __in HKEY hKey,
618 + __in LPCWSTR lpSubKey,
619 + __in REGSAM samDesired,
620 + __reserved DWORD Reserved
621 + )
622 +{
623 + LSTATUS ls = ERROR_SUCCESS;
624 + LPCWSTR wzRoot = NULL;
625 + HKEY hkRoot = NULL;
626 +
627 + if (HKEY_LOCAL_MACHINE == hKey)
628 + {
629 + wzRoot = HKLM_PATH;
630 + }
631 + else if (HKEY_CURRENT_USER == hKey)
632 + {
633 + wzRoot = HKCU_PATH;
634 + }
635 + else
636 + {
637 + hkRoot = hKey;
638 + }
639 +
640 + if (wzRoot)
641 + {
642 + ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE | samDesired, &hkRoot);
643 + if (ERROR_SUCCESS != ls)
644 + {
645 + ExitFunction();
646 + }
647 + }
648 +
649 + ls = ::RegDeleteKeyExW(hkRoot, lpSubKey, samDesired, Reserved);
650 +
651 +LExit:
652 + ReleaseRegKey(hkRoot);
653 +
654 + return ls;
655 +}
src/test/BurnUnitTest/SearchTest.cpp new
+721
@@ -0,0 +1,721 @@
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 +static 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 + );
12 +static INSTALLSTATE WINAPI MsiComponentSearchTest_MsiLocateComponentW(
13 + __in LPCWSTR szComponent,
14 + __out_ecount_opt(*pcchBuf) LPWSTR lpPathBuf,
15 + __inout_opt LPDWORD pcchBuf
16 + );
17 +static 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 + );
23 +static 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 +
32 +using namespace System;
33 +using namespace Xunit;
34 +using namespace Microsoft::Win32;
35 +
36 +namespace Microsoft
37 +{
38 +namespace Tools
39 +{
40 +namespace WindowsInstallerXml
41 +{
42 +namespace Test
43 +{
44 +namespace Bootstrapper
45 +{
46 + public ref class SearchTest : BurnUnitTest
47 + {
48 + public:
49 + [NamedFact]
50 + void DirectorySearchTest()
51 + {
52 + HRESULT hr = S_OK;
53 + IXMLDOMElement* pixeBundle = NULL;
54 + BURN_VARIABLES variables = { };
55 + BURN_SEARCHES searches = { };
56 + try
57 + {
58 + hr = VariableInitialize(&variables);
59 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
60 +
61 + pin_ptr<const WCHAR> wzDirectory1 = PtrToStringChars(this->TestContext->TestDirectory);
62 + pin_ptr<const WCHAR> wzDirectory2 = PtrToStringChars(System::IO::Path::Combine(this->TestContext->TestDirectory, gcnew String(L"none")));
63 +
64 + VariableSetStringHelper(&variables, L"Directory1", wzDirectory1);
65 + VariableSetStringHelper(&variables, L"Directory2", wzDirectory2);
66 +
67 + LPCWSTR wzDocument =
68 + L"<Bundle>"
69 + L" <DirectorySearch Id='Search1' Type='exists' Path='[Directory1]' Variable='Variable1' />"
70 + L" <DirectorySearch Id='Search2' Type='exists' Path='[Directory2]' Variable='Variable2' />"
71 + L"</Bundle>";
72 +
73 + // load XML document
74 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
75 +
76 + hr = SearchesParseFromXml(&searches, pixeBundle);
77 + TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
78 +
79 + // execute searches
80 + hr = SearchesExecute(&searches, &variables);
81 + TestThrowOnFailure(hr, L"Failed to execute searches.");
82 +
83 + // check variable values
84 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable1"));
85 + Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable2"));
86 + }
87 + finally
88 + {
89 + ReleaseObject(pixeBundle);
90 + VariablesUninitialize(&variables);
91 + SearchesUninitialize(&searches);
92 + }
93 + }
94 +
95 + [NamedFact]
96 + void FileSearchTest()
97 + {
98 + HRESULT hr = S_OK;
99 + IXMLDOMElement* pixeBundle = NULL;
100 + BURN_VARIABLES variables = { };
101 + BURN_SEARCHES searches = { };
102 + ULARGE_INTEGER uliVersion = { };
103 + try
104 + {
105 + hr = VariableInitialize(&variables);
106 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
107 +
108 + pin_ptr<const WCHAR> wzFile1 = PtrToStringChars(System::IO::Path::Combine(this->TestContext->TestDirectory, gcnew String(L"none.txt")));
109 + pin_ptr<const WCHAR> wzFile2 = PtrToStringChars(System::Reflection::Assembly::GetExecutingAssembly()->Location);
110 +
111 + hr = FileVersion(wzFile2, &uliVersion.HighPart, &uliVersion.LowPart);
112 + TestThrowOnFailure(hr, L"Failed to get DLL version.");
113 +
114 + VariableSetStringHelper(&variables, L"File1", wzFile1);
115 + VariableSetStringHelper(&variables, L"File2", wzFile2);
116 +
117 + LPCWSTR wzDocument =
118 + L"<Bundle>"
119 + L" <FileSearch Id='Search1' Type='exists' Path='[File1]' Variable='Variable1' />"
120 + L" <FileSearch Id='Search2' Type='exists' Path='[File2]' Variable='Variable2' />"
121 + L" <FileSearch Id='Search3' Type='version' Path='[File2]' Variable='Variable3' />"
122 + L"</Bundle>";
123 +
124 + // load XML document
125 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
126 +
127 + hr = SearchesParseFromXml(&searches, pixeBundle);
128 + TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
129 +
130 + // execute searches
131 + hr = SearchesExecute(&searches, &variables);
132 + TestThrowOnFailure(hr, L"Failed to execute searches.");
133 +
134 + // check variable values
135 + Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable1"));
136 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable2"));
137 + Assert::Equal(uliVersion.QuadPart, VariableGetVersionHelper(&variables, L"Variable3"));
138 + }
139 + finally
140 + {
141 + ReleaseObject(pixeBundle);
142 + VariablesUninitialize(&variables);
143 + SearchesUninitialize(&searches);
144 + }
145 + }
146 +
147 + [NamedFact]
148 + void RegistrySearchTest()
149 + {
150 + HRESULT hr = S_OK;
151 + IXMLDOMElement* pixeBundle = NULL;
152 + BURN_VARIABLES variables = { };
153 + BURN_SEARCHES searches = { };
154 + HKEY hkey32 = NULL;
155 + HKEY hkey64 = NULL;
156 + BOOL f64bitMachine = (nullptr != Environment::GetEnvironmentVariable("ProgramFiles(x86)"));
157 +
158 + try
159 + {
160 + hr = VariableInitialize(&variables);
161 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
162 +
163 + 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);
164 + 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);
165 + Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value"), gcnew String(L"DWord"), 1, RegistryValueKind::DWord);
166 + Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value"), gcnew String(L"QWord"), 1ll, RegistryValueKind::QWord);
167 + 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);
168 + 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);
169 + Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\String"), nullptr, gcnew String(L"String1"), RegistryValueKind::String);
170 + Registry::SetValue(gcnew String(L"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Numeric"), nullptr, 1ll, RegistryValueKind::DWord);
171 +
172 + if (f64bitMachine)
173 + {
174 + hr = RegCreate(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness\\", KEY_WRITE | KEY_WOW64_32KEY, &hkey32);
175 + Assert::True(SUCCEEDED(hr));
176 +
177 + hr = RegCreate(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness\\", KEY_WRITE | KEY_WOW64_64KEY, &hkey64);
178 + Assert::True(SUCCEEDED(hr));
179 +
180 + hr = RegWriteString(hkey64, L"TestStringSpecificToBitness", L"64-bit");
181 + Assert::True(SUCCEEDED(hr));
182 +
183 + hr = RegWriteString(hkey32, L"TestStringSpecificToBitness", L"32-bit");
184 + Assert::True(SUCCEEDED(hr));
185 + }
186 +
187 + VariableSetStringHelper(&variables, L"MyKey", L"SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value");
188 + VariableSetStringHelper(&variables, L"MyValue", L"String");
189 +
190 + LPCWSTR wzDocument =
191 + L"<Bundle>"
192 + L" <RegistrySearch Id='Search1' Type='exists' Root='HKLM' Key='SOFTWARE\\Microsoft' Variable='Variable1' />"
193 + L" <RegistrySearch Id='Search2' Type='exists' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\None' Variable='Variable2' />"
194 + L" <RegistrySearch Id='Search3' Type='exists' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='None' Variable='Variable3' />"
195 + L" <RegistrySearch Id='Search4' Type='exists' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='String' Variable='Variable4' />"
196 + L" <RegistrySearch Id='Search5' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='String' Variable='Variable5' VariableType='string' />"
197 + L" <RegistrySearch Id='Search6' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='String' Variable='Variable6' VariableType='string' ExpandEnvironment='no' />"
198 + L" <RegistrySearch Id='Search7' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='String' Variable='Variable7' VariableType='string' ExpandEnvironment='yes' />"
199 + L" <RegistrySearch Id='Search8' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='StringExpand' Variable='Variable8' VariableType='string' />"
200 + L" <RegistrySearch Id='Search9' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='StringExpand' Variable='Variable9' VariableType='string' ExpandEnvironment='no' />"
201 + L" <RegistrySearch Id='Search10' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='StringExpand' Variable='Variable10' VariableType='string' ExpandEnvironment='yes' />"
202 + L" <RegistrySearch Id='Search11' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='DWord' Variable='Variable11' VariableType='numeric' />"
203 + L" <RegistrySearch Id='Search12' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='QWord' Variable='Variable12' VariableType='numeric' />"
204 + L" <RegistrySearch Id='Search13' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='VersionString' Variable='Variable13' VariableType='version' />"
205 + L" <RegistrySearch Id='Search14' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value' Value='VersionQWord' Variable='Variable14' VariableType='version' />"
206 + L" <RegistrySearch Id='Search15' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\String' Variable='Variable15' VariableType='string' />"
207 + L" <RegistrySearch Id='Search16' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Numeric' Variable='Variable16' VariableType='numeric' />"
208 + L" <RegistrySearch Id='Search17' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\None' Variable='Variable17' VariableType='numeric' />"
209 + L" <RegistrySearch Id='Search18' Type='value' Root='HKCU' Key='SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Numeric' Value='None' Variable='Variable18' VariableType='numeric' />"
210 + L" <RegistrySearch Id='Search19' Type='exists' Root='HKCU' Key='[MyKey]' Value='[MyValue]' Variable='Variable19' />"
211 + L" <RegistrySearch Id='Search20' Type='value' Root='HKCU' Key='[MyKey]' Value='[MyValue]' Variable='Variable20' VariableType='string' />"
212 + L" <RegistrySearch Id='Search21' Type='value' Root='HKCU' Key='SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness' Value='TestStringSpecificToBitness' Variable='Variable21' VariableType='string' Win64='no' />"
213 + L" <RegistrySearch Id='Search22' Type='value' Root='HKCU' Key='SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness' Value='TestStringSpecificToBitness' Variable='Variable22' VariableType='string' Win64='yes' />"
214 + L" <RegistrySearch Id='Search23' Type='exists' Root='HKU' Key='.DEFAULT\\Environment' Variable='Variable23' />"
215 + L" <RegistrySearch Id='Search23' Type='exists' Root='HKU' Key='.DEFAULT\\System\\NetworkServiceSidSubkeyDoesNotExist' Variable='Variable24' />"
216 + L" <RegistrySearch Id='Search24' Type='value' Root='HKCR' Key='.msi' Variable='Variable25' VariableType='string' />"
217 + L"</Bundle>";
218 +
219 + // load XML document
220 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
221 +
222 + hr = SearchesParseFromXml(&searches, pixeBundle);
223 + TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
224 +
225 + // execute searches
226 + hr = SearchesExecute(&searches, &variables);
227 + TestThrowOnFailure(hr, L"Failed to execute searches.");
228 +
229 + // check variable values
230 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable1"));
231 + Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable2"));
232 + Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable3"));
233 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable4"));
234 + Assert::Equal(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable5"));
235 + Assert::Equal(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable6"));
236 + Assert::Equal(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable7"));
237 + Assert::Equal(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable8"));
238 + Assert::Equal(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable9"));
239 + Assert::NotEqual(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable10"));
240 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable11"));
241 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable12"));
242 + Assert::Equal(MAKEQWORDVERSION(1,1,1,1), VariableGetVersionHelper(&variables, L"Variable13"));
243 + Assert::Equal(MAKEQWORDVERSION(1,1,1,1), VariableGetVersionHelper(&variables, L"Variable14"));
244 + Assert::Equal(gcnew String(L"String1"), VariableGetStringHelper(&variables, L"Variable15"));
245 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable16"));
246 + Assert::False(VariableExistsHelper(&variables, L"Variable17"));
247 + Assert::False(VariableExistsHelper(&variables, L"Variable18"));
248 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable19"));
249 + Assert::Equal(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable20"));
250 + if (f64bitMachine)
251 + {
252 + Assert::Equal(gcnew String(L"32-bit"), VariableGetStringHelper(&variables, L"Variable21"));
253 + Assert::Equal(gcnew String(L"64-bit"), VariableGetStringHelper(&variables, L"Variable22"));
254 + }
255 +
256 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable23"));
257 + Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable24"));
258 + Assert::Equal(gcnew String(L"Msi.Package"), VariableGetStringHelper(&variables, L"Variable25"));
259 + }
260 + finally
261 + {
262 + ReleaseRegKey(hkey32);
263 + ReleaseRegKey(hkey64);
264 + ReleaseObject(pixeBundle);
265 + VariablesUninitialize(&variables);
266 + SearchesUninitialize(&searches);
267 +
268 + Registry::CurrentUser->DeleteSubKeyTree(gcnew String(L"SOFTWARE\\Microsoft\\WiX_Burn_UnitTest"));
269 + if (f64bitMachine)
270 + {
271 + RegDelete(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness", REG_KEY_32BIT, FALSE);
272 + RegDelete(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest", REG_KEY_32BIT, FALSE);
273 + RegDelete(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest\\Bitness", REG_KEY_64BIT, FALSE);
274 + RegDelete(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\WiX_Burn_UnitTest", REG_KEY_64BIT, FALSE);
275 + }
276 + }
277 + }
278 +
279 + [NamedFact]
280 + void MsiComponentSearchTest()
281 + {
282 + HRESULT hr = S_OK;
283 + IXMLDOMElement* pixeBundle = NULL;
284 + BURN_VARIABLES variables = { };
285 + BURN_SEARCHES searches = { };
286 + try
287 + {
288 + hr = VariableInitialize(&variables);
289 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
290 +
291 + // set mock API's
292 + WiuFunctionOverride(NULL, MsiComponentSearchTest_MsiGetComponentPathW, MsiComponentSearchTest_MsiLocateComponentW, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
293 +
294 + LPCWSTR wzDocument =
295 + L"<Bundle>"
296 + L" <MsiComponentSearch Id='Search1' Type='state' ComponentId='{BAD00000-1000-0000-0000-000000000000}' Variable='Variable1' />"
297 + L" <MsiComponentSearch Id='Search2' Type='state' ProductCode='{BAD00000-0000-0000-0000-000000000000}' ComponentId='{BAD00000-1000-0000-0000-000000000000}' Variable='Variable2' />"
298 + L" <MsiComponentSearch Id='Search3' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{BAD00000-1000-0000-0000-000000000000}' Variable='Variable3' />"
299 + L" <MsiComponentSearch Id='Search4' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-1000-0000-000000000000}' Variable='Variable4' />"
300 + L" <MsiComponentSearch Id='Search5' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-2000-0000-000000000000}' Variable='Variable5' />"
301 + L" <MsiComponentSearch Id='Search6' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-3000-0000-000000000000}' Variable='Variable6' />"
302 + L" <MsiComponentSearch Id='Search7' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-4000-0000-000000000000}' Variable='Variable7' />"
303 + L" <MsiComponentSearch Id='Search8' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-5000-0000-000000000000}' Variable='Variable8' />"
304 + L" <MsiComponentSearch Id='Search9' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-6000-0000-000000000000}' Variable='Variable9' />" // todo: value key path
305 + L" <MsiComponentSearch Id='Search10' Type='state' ComponentId='{600D0000-1000-1000-0000-000000000000}' Variable='Variable10' />"
306 + L" <MsiComponentSearch Id='Search11' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-1000-0000-000000000000}' Variable='Variable11' />"
307 + L" <MsiComponentSearch Id='Search12' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-2000-0000-000000000000}' Variable='Variable12' />"
308 + L" <MsiComponentSearch Id='Search13' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-3000-0000-000000000000}' Variable='Variable13' />"
309 + L" <MsiComponentSearch Id='Search14' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-4000-0000-000000000000}' Variable='Variable14' />"
310 + L" <MsiComponentSearch Id='Search15' Type='directory' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-1000-0000-000000000000}' Variable='Variable15' />"
311 + L" <MsiComponentSearch Id='Search16' Type='directory' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-2000-0000-000000000000}' Variable='Variable16' />"
312 + L" <MsiComponentSearch Id='Search17' Type='directory' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-3000-0000-000000000000}' Variable='Variable17' />"
313 + L" <MsiComponentSearch Id='Search18' Type='directory' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-4000-0000-000000000000}' Variable='Variable18' />"
314 + L" <MsiComponentSearch Id='Search19' Type='keyPath' ProductCode='{600D0000-0000-0000-0000-000000000000}' ComponentId='{600D0000-1000-7000-0000-000000000000}' Variable='Variable19' />"
315 + L"</Bundle>";
316 +
317 + // load XML document
318 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
319 +
320 + hr = SearchesParseFromXml(&searches, pixeBundle);
321 + TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
322 +
323 + // execute searches
324 + hr = SearchesExecute(&searches, &variables);
325 + TestThrowOnFailure(hr, L"Failed to execute searches.");
326 +
327 + // check variable values
328 + Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable1"));
329 + Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable2"));
330 + Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable3"));
331 + Assert::Equal(gcnew String(L"C:\\directory\\file1.txt"), VariableGetStringHelper(&variables, L"Variable4"));
332 + Assert::Equal(gcnew String(L"C:\\directory\\file2.txt"), VariableGetStringHelper(&variables, L"Variable5"));
333 + Assert::Equal(gcnew String(L"C:\\directory\\file3.txt"), VariableGetStringHelper(&variables, L"Variable6"));
334 + Assert::Equal(gcnew String(L"C:\\directory\\file4.txt"), VariableGetStringHelper(&variables, L"Variable7"));
335 + Assert::Equal(gcnew String(L"02:\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\"), VariableGetStringHelper(&variables, L"Variable8"));
336 + Assert::Equal(gcnew String(L"02:\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value"), VariableGetStringHelper(&variables, L"Variable9"));
337 + Assert::Equal(3ll, VariableGetNumericHelper(&variables, L"Variable10"));
338 + Assert::Equal(3ll, VariableGetNumericHelper(&variables, L"Variable11"));
339 + Assert::Equal(4ll, VariableGetNumericHelper(&variables, L"Variable12"));
340 + Assert::Equal(4ll, VariableGetNumericHelper(&variables, L"Variable13"));
341 + Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable14"));
342 + Assert::Equal(gcnew String(L"C:\\directory\\"), VariableGetStringHelper(&variables, L"Variable15"));
343 + Assert::Equal(gcnew String(L"C:\\directory\\"), VariableGetStringHelper(&variables, L"Variable16"));
344 + Assert::Equal(gcnew String(L"C:\\directory\\"), VariableGetStringHelper(&variables, L"Variable17"));
345 + Assert::Equal(gcnew String(L"C:\\directory\\"), VariableGetStringHelper(&variables, L"Variable18"));
346 + Assert::Equal(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"));
347 + }
348 + finally
349 + {
350 + ReleaseObject(pixeBundle);
351 + VariablesUninitialize(&variables);
352 + SearchesUninitialize(&searches);
353 + }
354 + }
355 +
356 + [NamedFact]
357 + void MsiProductSearchTest()
358 + {
359 + HRESULT hr = S_OK;
360 + IXMLDOMElement* pixeBundle = NULL;
361 + BURN_VARIABLES variables = { };
362 + BURN_SEARCHES searches = { };
363 + try
364 + {
365 + hr = VariableInitialize(&variables);
366 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
367 +
368 + // set mock API's
369 + WiuFunctionOverride(NULL, NULL, NULL, NULL, MsiProductSearchTest_MsiGetProductInfoW, MsiProductSearchTest_MsiGetProductInfoExW, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
370 +
371 + LPCWSTR wzDocument =
372 + L"<Bundle>"
373 + L" <MsiProductSearch Id='Search1' Type='state' ProductCode='{BAD00000-0000-0000-0000-000000000000}' Variable='Variable1' />"
374 + L" <MsiProductSearch Id='Search2' Type='version' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable2' />"
375 + L" <MsiProductSearch Id='Search3' Type='language' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable3' />"
376 + L" <MsiProductSearch Id='Search4' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable4' />"
377 + L" <MsiProductSearch Id='Search5' Type='assignment' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable5' />"
378 + L" <MsiProductSearch Id='Search6' Type='version' ProductCode='{600D0000-1000-0000-0000-000000000000}' Variable='Variable6' />"
379 + L"</Bundle>";
380 +
381 + // load XML document
382 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
383 +
384 + hr = SearchesParseFromXml(&searches, pixeBundle);
385 + TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
386 +
387 + // execute searches
388 + hr = SearchesExecute(&searches, &variables);
389 + TestThrowOnFailure(hr, L"Failed to execute searches.");
390 +
391 + // check variable values
392 + Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable1"));
393 + Assert::Equal(MAKEQWORDVERSION(1,0,0,0), VariableGetVersionHelper(&variables, L"Variable2"));
394 + Assert::Equal(1033ll, VariableGetNumericHelper(&variables, L"Variable3"));
395 + Assert::Equal(5ll, VariableGetNumericHelper(&variables, L"Variable4"));
396 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable5"));
397 + Assert::Equal(MAKEQWORDVERSION(1,0,0,0), VariableGetVersionHelper(&variables, L"Variable6"));
398 + }
399 + finally
400 + {
401 + ReleaseObject(pixeBundle);
402 + VariablesUninitialize(&variables);
403 + SearchesUninitialize(&searches);
404 + }
405 + }
406 +
407 + [NamedFact]
408 + void MsiFeatureSearchTest()
409 + {
410 + HRESULT hr = S_OK;
411 + IXMLDOMElement* pixeBundle = NULL;
412 + BURN_VARIABLES variables = { };
413 + BURN_SEARCHES searches = { };
414 + try
415 + {
416 + LPCWSTR wzDocument =
417 + L"<Bundle>"
418 + L" <MsiFeatureSearch Id='Search1' Type='state' ProductCode='{BAD00000-0000-0000-0000-000000000000}' FeatureId='' Variable='Variable1' />"
419 + L"</Bundle>";
420 +
421 + hr = VariableInitialize(&variables);
422 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
423 +
424 + // load XML document
425 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
426 +
427 + hr = SearchesParseFromXml(&searches, pixeBundle);
428 + TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
429 +
430 + // execute searches
431 + hr = SearchesExecute(&searches, &variables);
432 + TestThrowOnFailure(hr, L"Failed to execute searches.");
433 + }
434 + finally
435 + {
436 + ReleaseObject(pixeBundle);
437 + VariablesUninitialize(&variables);
438 + SearchesUninitialize(&searches);
439 + }
440 + }
441 +
442 + [NamedFact]
443 + void ConditionalSearchTest()
444 + {
445 + HRESULT hr = S_OK;
446 + IXMLDOMElement* pixeBundle = NULL;
447 + BURN_VARIABLES variables = { };
448 + BURN_SEARCHES searches = { };
449 + try
450 + {
451 + LPCWSTR wzDocument =
452 + L"<Bundle>"
453 + L" <RegistrySearch Id='Search1' Type='exists' Root='HKLM' Key='SOFTWARE\\Microsoft' Variable='Variable1' Condition='0' />"
454 + L" <RegistrySearch Id='Search2' Type='exists' Root='HKLM' Key='SOFTWARE\\Microsoft' Variable='Variable2' Condition='1' />"
455 + L" <RegistrySearch Id='Search3' Type='exists' Root='HKLM' Key='SOFTWARE\\Microsoft' Variable='Variable3' Condition='=' />"
456 + L"</Bundle>";
457 +
458 + hr = VariableInitialize(&variables);
459 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
460 +
461 + // load XML document
462 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
463 +
464 + hr = SearchesParseFromXml(&searches, pixeBundle);
465 + TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
466 +
467 + // execute searches
468 + hr = SearchesExecute(&searches, &variables);
469 + TestThrowOnFailure(hr, L"Failed to execute searches.");
470 +
471 + // check variable values
472 + Assert::False(VariableExistsHelper(&variables, L"Variable1"));
473 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable2"));
474 + Assert::False(VariableExistsHelper(&variables, L"Variable3"));
475 + }
476 + finally
477 + {
478 + ReleaseObject(pixeBundle);
479 + VariablesUninitialize(&variables);
480 + SearchesUninitialize(&searches);
481 + }
482 + }
483 + [NamedFact]
484 + void NoSearchesTest()
485 + {
486 + HRESULT hr = S_OK;
487 + IXMLDOMElement* pixeBundle = NULL;
488 + BURN_VARIABLES variables = { };
489 + BURN_SEARCHES searches = { };
490 + try
491 + {
492 + LPCWSTR wzDocument =
493 + L"<Bundle>"
494 + L"</Bundle>";
495 +
496 + hr = VariableInitialize(&variables);
497 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
498 +
499 + // load XML document
500 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
501 +
502 + hr = SearchesParseFromXml(&searches, pixeBundle);
503 + TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
504 +
505 + // execute searches
506 + hr = SearchesExecute(&searches, &variables);
507 + TestThrowOnFailure(hr, L"Failed to execute searches.");
508 + }
509 + finally
510 + {
511 + ReleaseObject(pixeBundle);
512 + VariablesUninitialize(&variables);
513 + SearchesUninitialize(&searches);
514 + }
515 + }
516 + };
517 +}
518 +}
519 +}
520 +}
521 +}
522 +
523 +
524 +static INSTALLSTATE WINAPI MsiComponentSearchTest_MsiGetComponentPathW(
525 + __in LPCWSTR szProduct,
526 + __in LPCWSTR szComponent,
527 + __out_ecount_opt(*pcchBuf) LPWSTR lpPathBuf,
528 + __inout_opt LPDWORD pcchBuf
529 + )
530 +{
531 + INSTALLSTATE is = INSTALLSTATE_INVALIDARG;
532 + String^ product = gcnew String(szProduct);
533 +
534 + if (String::Equals(product, gcnew String(L"{BAD00000-0000-0000-0000-000000000000}")))
535 + {
536 + is = INSTALLSTATE_UNKNOWN;
537 + }
538 + else if (String::Equals(product, gcnew String(L"{600D0000-0000-0000-0000-000000000000}")))
539 + {
540 + is = MsiComponentSearchTest_MsiLocateComponentW(szComponent, lpPathBuf, pcchBuf);
541 + }
542 +
543 + return is;
544 +}
545 +
546 +static INSTALLSTATE WINAPI MsiComponentSearchTest_MsiLocateComponentW(
547 + __in LPCWSTR szComponent,
548 + __out_ecount_opt(*pcchBuf) LPWSTR lpPathBuf,
549 + __inout_opt LPDWORD pcchBuf
550 + )
551 +{
552 + HRESULT hr = S_OK;
553 + INSTALLSTATE is = INSTALLSTATE_INVALIDARG;
554 + String^ component = gcnew String(szComponent);
555 + LPCWSTR wzValue = NULL;
556 +
557 + if (String::Equals(component, gcnew String(L"{BAD00000-1000-0000-0000-000000000000}")))
558 + {
559 + is = INSTALLSTATE_UNKNOWN;
560 + }
561 + else if (String::Equals(component, gcnew String(L"{600D0000-1000-1000-0000-000000000000}")))
562 + {
563 + wzValue = L"C:\\directory\\file1.txt";
564 + is = INSTALLSTATE_LOCAL;
565 + }
566 + else if (String::Equals(component, gcnew String(L"{600D0000-1000-2000-0000-000000000000}")))
567 + {
568 + wzValue = L"C:\\directory\\file2.txt";
569 + is = INSTALLSTATE_SOURCE;
570 + }
571 + else if (String::Equals(component, gcnew String(L"{600D0000-1000-3000-0000-000000000000}")))
572 + {
573 + wzValue = L"C:\\directory\\file3.txt";
574 + is = INSTALLSTATE_SOURCEABSENT;
575 + }
576 + else if (String::Equals(component, gcnew String(L"{600D0000-1000-4000-0000-000000000000}")))
577 + {
578 + wzValue = L"C:\\directory\\file4.txt";
579 + is = INSTALLSTATE_ABSENT;
580 + }
581 + else if (String::Equals(component, gcnew String(L"{600D0000-1000-5000-0000-000000000000}")))
582 + {
583 + wzValue = L"02:\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\";
584 + is = INSTALLSTATE_LOCAL;
585 + }
586 + else if (String::Equals(component, gcnew String(L"{600D0000-1000-6000-0000-000000000000}")))
587 + {
588 + wzValue = L"02:\\SOFTWARE\\Microsoft\\WiX_Burn_UnitTest\\Value";
589 + is = INSTALLSTATE_LOCAL;
590 + }
591 + else if (String::Equals(component, gcnew String(L"{600D0000-1000-7000-0000-000000000000}")))
592 + {
593 + 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";
594 + is = INSTALLSTATE_ABSENT;
595 + }
596 +
597 + if (wzValue && lpPathBuf)
598 + {
599 + hr = ::StringCchCopyW(lpPathBuf, *pcchBuf, wzValue);
600 + if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
601 + {
602 + *pcchBuf = lstrlenW(wzValue);
603 + is = INSTALLSTATE_MOREDATA;
604 + }
605 + else if (FAILED(hr))
606 + {
607 + is = INSTALLSTATE_INVALIDARG;
608 + }
609 + }
610 +
611 + return is;
612 +}
613 +
614 +static UINT WINAPI MsiProductSearchTest_MsiGetProductInfoW(
615 + __in LPCWSTR szProductCode,
616 + __in LPCWSTR szProperty,
617 + __out_ecount_opt(*pcchValue) LPWSTR szValue,
618 + __inout_opt LPDWORD pcchValue
619 + )
620 +{
621 + if (String::Equals(gcnew String(szProductCode), gcnew String(L"{600D0000-0000-0000-0000-000000000000}")) &&
622 + String::Equals(gcnew String(szProperty), gcnew String(INSTALLPROPERTY_PRODUCTSTATE)))
623 + {
624 + // force call to WiuGetProductInfoEx
625 + return ERROR_UNKNOWN_PROPERTY;
626 + }
627 +
628 + UINT er = MsiProductSearchTest_MsiGetProductInfoExW(szProductCode, NULL, MSIINSTALLCONTEXT_MACHINE, szProperty, szValue, pcchValue);
629 + return er;
630 +}
631 +
632 +static UINT WINAPI MsiProductSearchTest_MsiGetProductInfoExW(
633 + __in LPCWSTR szProductCode,
634 + __in_opt LPCWSTR /*szUserSid*/,
635 + __in MSIINSTALLCONTEXT dwContext,
636 + __in LPCWSTR szProperty,
637 + __out_ecount_opt(*pcchValue) LPWSTR szValue,
638 + __inout_opt LPDWORD pcchValue
639 + )
640 +{
641 + HRESULT hr = S_OK;
642 + DWORD er = ERROR_FUNCTION_FAILED;
643 + LPCWSTR wzValue = NULL;
644 +
645 + String^ productCode = gcnew String(szProductCode);
646 + String^ _property = gcnew String(szProperty);
647 + switch (dwContext)
648 + {
649 + case MSIINSTALLCONTEXT_USERMANAGED:
650 + er = ERROR_UNKNOWN_PRODUCT;
651 + break;
652 + case MSIINSTALLCONTEXT_USERUNMANAGED:
653 + if (String::Equals(productCode, gcnew String(L"{600D0000-0000-0000-0000-000000000000}")))
654 + {
655 + if (String::Equals(_property, gcnew String(INSTALLPROPERTY_PRODUCTSTATE)))
656 + {
657 + wzValue = L"5";
658 + }
659 + }
660 + break;
661 + case MSIINSTALLCONTEXT_MACHINE:
662 + if (String::Equals(productCode, gcnew String(L"{BAD00000-0000-0000-0000-000000000000}")))
663 + {
664 + er = ERROR_UNKNOWN_PRODUCT;
665 + }
666 + else if (String::Equals(productCode, gcnew String(L"{600D0000-0000-0000-0000-000000000000}")))
667 + {
668 + if (String::Equals(_property, gcnew String(INSTALLPROPERTY_VERSIONSTRING)))
669 + {
670 + wzValue = L"1.0.0.0";
671 + }
672 + else if (String::Equals(_property, gcnew String(INSTALLPROPERTY_LANGUAGE)))
673 + {
674 + wzValue = L"1033";
675 + }
676 + else if (String::Equals(_property, gcnew String(INSTALLPROPERTY_ASSIGNMENTTYPE)))
677 + {
678 + wzValue = L"1";
679 + }
680 + else if (String::Equals(_property, gcnew String(INSTALLPROPERTY_PRODUCTSTATE)))
681 + {
682 + // try again in per-user context
683 + er = ERROR_UNKNOWN_PRODUCT;
684 + }
685 + }
686 + else if (String::Equals(productCode, gcnew String(L"{600D0000-1000-0000-0000-000000000000}")))
687 + {
688 + static BOOL fFlipp = FALSE;
689 + if (fFlipp)
690 + {
691 + if (String::Equals(_property, gcnew String(INSTALLPROPERTY_VERSIONSTRING)))
692 + {
693 + wzValue = L"1.0.0.0";
694 + }
695 + }
696 + else
697 + {
698 + *pcchValue = MAX_PATH * 2;
699 + er = ERROR_MORE_DATA;
700 + }
701 + fFlipp = !fFlipp;
702 + }
703 + break;
704 + }
705 +
706 + if (wzValue)
707 + {
708 + hr = ::StringCchCopyW(szValue, *pcchValue, wzValue);
709 + if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
710 + {
711 + *pcchValue = lstrlenW(wzValue);
712 + er = ERROR_MORE_DATA;
713 + }
714 + else if (SUCCEEDED(hr))
715 + {
716 + er = ERROR_SUCCESS;
717 + }
718 + }
719 +
720 + return er;
721 +}
src/test/BurnUnitTest/VariableHelpers.cpp new
+199
@@ -0,0 +1,199 @@
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 +using namespace System;
7 +using namespace Xunit;
8 +
9 +
10 +namespace Microsoft
11 +{
12 +namespace Tools
13 +{
14 +namespace WindowsInstallerXml
15 +{
16 +namespace Test
17 +{
18 +namespace Bootstrapper
19 +{
20 + void VariableSetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LPCWSTR wzValue)
21 + {
22 + HRESULT hr = S_OK;
23 +
24 + hr = VariableSetString(pVariables, wzVariable, wzValue, FALSE);
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, DWORD64 qwValue)
37 + {
38 + HRESULT hr = S_OK;
39 +
40 + hr = VariableSetVersion(pVariables, wzVariable, qwValue, FALSE);
41 + TestThrowOnFailure2(hr, L"Failed to set %s to: 0x%016I64x", wzVariable, qwValue);
42 + }
43 +
44 + String^ VariableGetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
45 + {
46 + HRESULT hr = S_OK;
47 + LPWSTR scz = NULL;
48 + try
49 + {
50 + hr = VariableGetString(pVariables, wzVariable, &scz);
51 + TestThrowOnFailure1(hr, L"Failed to get: %s", wzVariable);
52 +
53 + return gcnew String(scz);
54 + }
55 + finally
56 + {
57 + ReleaseStr(scz);
58 + }
59 + }
60 +
61 + __int64 VariableGetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
62 + {
63 + HRESULT hr = S_OK;
64 + LONGLONG llValue = 0;
65 +
66 + hr = VariableGetNumeric(pVariables, wzVariable, &llValue);
67 + TestThrowOnFailure1(hr, L"Failed to get: %s", wzVariable);
68 +
69 + return llValue;
70 + }
71 +
72 + unsigned __int64 VariableGetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
73 + {
74 + HRESULT hr = S_OK;
75 + DWORD64 qwValue = 0;
76 +
77 + hr = VariableGetVersion(pVariables, wzVariable, &qwValue);
78 + TestThrowOnFailure1(hr, L"Failed to get: %s", wzVariable);
79 +
80 + return qwValue;
81 + }
82 +
83 + String^ VariableGetFormattedHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
84 + {
85 + HRESULT hr = S_OK;
86 + LPWSTR scz = NULL;
87 + try
88 + {
89 + hr = VariableGetFormatted(pVariables, wzVariable, &scz);
90 + TestThrowOnFailure1(hr, L"Failed to get formatted: %s", wzVariable);
91 +
92 + return gcnew String(scz);
93 + }
94 + finally
95 + {
96 + ReleaseStr(scz);
97 + }
98 + }
99 +
100 + String^ VariableFormatStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzIn)
101 + {
102 + HRESULT hr = S_OK;
103 + LPWSTR scz = NULL;
104 + try
105 + {
106 + hr = VariableFormatString(pVariables, wzIn, &scz, NULL);
107 + TestThrowOnFailure1(hr, L"Failed to format string: '%s'", wzIn);
108 +
109 + return gcnew String(scz);
110 + }
111 + finally
112 + {
113 + ReleaseStr(scz);
114 + }
115 + }
116 +
117 + String^ VariableEscapeStringHelper(LPCWSTR wzIn)
118 + {
119 + HRESULT hr = S_OK;
120 + LPWSTR scz = NULL;
121 + try
122 + {
123 + hr = VariableEscapeString(wzIn, &scz);
124 + TestThrowOnFailure1(hr, L"Failed to escape string: '%s'", wzIn);
125 +
126 + return gcnew String(scz);
127 + }
128 + finally
129 + {
130 + ReleaseStr(scz);
131 + }
132 + }
133 +
134 + bool EvaluateConditionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzCondition)
135 + {
136 + HRESULT hr = S_OK;
137 + BOOL f = FALSE;
138 +
139 + hr = ConditionEvaluate(pVariables, wzCondition, &f);
140 + TestThrowOnFailure1(hr, L"Failed to evaluate condition: '%s'", wzCondition);
141 +
142 + return f ? true : false;
143 + }
144 +
145 + bool EvaluateFailureConditionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzCondition)
146 + {
147 + HRESULT hr = S_OK;
148 + BOOL f = FALSE;
149 +
150 + hr = ConditionEvaluate(pVariables, wzCondition, &f);
151 + return E_INVALIDDATA == hr ? true : false;
152 + }
153 +
154 + bool VariableExistsHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
155 + {
156 + HRESULT hr = S_OK;
157 + BURN_VARIANT value = { };
158 +
159 + try
160 + {
161 + hr = VariableGetVariant(pVariables, wzVariable, &value);
162 + if (E_NOTFOUND == hr || value.Type == BURN_VARIANT_TYPE_NONE)
163 + {
164 + return false;
165 + }
166 + else
167 + {
168 + TestThrowOnFailure1(hr, L"Failed to find variable: '%s'", wzVariable);
169 + return true;
170 + }
171 + }
172 + finally
173 + {
174 + BVariantUninitialize(&value);
175 + }
176 + }
177 +
178 + int VariableGetTypeHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
179 + {
180 + HRESULT hr = S_OK;
181 + BURN_VARIANT value = { };
182 +
183 + try
184 + {
185 + hr = VariableGetVariant(pVariables, wzVariable, &value);
186 + TestThrowOnFailure1(hr, L"Failed to find variable: '%s'", wzVariable);
187 +
188 + return (int)value.Type;
189 + }
190 + finally
191 + {
192 + BVariantUninitialize(&value);
193 + }
194 + }
195 +}
196 +}
197 +}
198 +}
199 +}
src/test/BurnUnitTest/VariableHelpers.h new
+36
@@ -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 +
5 +namespace Microsoft
6 +{
7 +namespace Tools
8 +{
9 +namespace WindowsInstallerXml
10 +{
11 +namespace Test
12 +{
13 +namespace Bootstrapper
14 +{
15 +
16 +
17 +void VariableSetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LPCWSTR wzValue);
18 +void VariableSetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LONGLONG llValue);
19 +void VariableSetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, DWORD64 qwValue);
20 +System::String^ VariableGetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
21 +__int64 VariableGetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
22 +unsigned __int64 VariableGetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
23 +System::String^ VariableGetFormattedHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
24 +System::String^ VariableFormatStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzIn);
25 +System::String^ VariableEscapeStringHelper(LPCWSTR wzIn);
26 +bool EvaluateConditionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzCondition);
27 +bool EvaluateFailureConditionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzCondition);
28 +bool VariableExistsHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
29 +int VariableGetTypeHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
30 +
31 +
32 +}
33 +}
34 +}
35 +}
36 +}
src/test/BurnUnitTest/VariableTest.cpp new
+480
@@ -0,0 +1,480 @@
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 +
7 +namespace Microsoft
8 +{
9 +namespace Tools
10 +{
11 +namespace WindowsInstallerXml
12 +{
13 +namespace Test
14 +{
15 +namespace Bootstrapper
16 +{
17 + using namespace System;
18 + using namespace Xunit;
19 +
20 + public ref class VariableTest : BurnUnitTest
21 + {
22 + public:
23 + [NamedFact]
24 + void VariablesBasicTest()
25 + {
26 + HRESULT hr = S_OK;
27 + BURN_VARIABLES variables = { };
28 + try
29 + {
30 + hr = VariableInitialize(&variables);
31 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
32 +
33 + // set variables
34 + VariableSetStringHelper(&variables, L"PROP1", L"VAL1");
35 + VariableSetNumericHelper(&variables, L"PROP2", 2);
36 + VariableSetStringHelper(&variables, L"PROP5", L"VAL5");
37 + VariableSetStringHelper(&variables, L"PROP3", L"VAL3");
38 + VariableSetStringHelper(&variables, L"PROP4", L"VAL4");
39 + VariableSetStringHelper(&variables, L"PROP6", L"VAL6");
40 + VariableSetStringHelper(&variables, L"PROP7", L"7");
41 + VariableSetVersionHelper(&variables, L"PROP8", MAKEQWORDVERSION(1,1,0,0));
42 +
43 + // set overwritten variables
44 + VariableSetStringHelper(&variables, L"OVERWRITTEN_STRING", L"ORIGINAL");
45 + VariableSetNumericHelper(&variables, L"OVERWRITTEN_STRING", 42);
46 +
47 + VariableSetNumericHelper(&variables, L"OVERWRITTEN_NUMBER", 5);
48 + VariableSetStringHelper(&variables, L"OVERWRITTEN_NUMBER", L"NEW");
49 +
50 + // get and verify variable values
51 + Assert::Equal(gcnew String(L"VAL1"), VariableGetStringHelper(&variables, L"PROP1"));
52 + Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"PROP2"));
53 + Assert::Equal(gcnew String(L"2"), VariableGetStringHelper(&variables, L"PROP2"));
54 + Assert::Equal(gcnew String(L"VAL3"), VariableGetStringHelper(&variables, L"PROP3"));
55 + Assert::Equal(gcnew String(L"VAL4"), VariableGetStringHelper(&variables, L"PROP4"));
56 + Assert::Equal(gcnew String(L"VAL5"), VariableGetStringHelper(&variables, L"PROP5"));
57 + Assert::Equal(gcnew String(L"VAL6"), VariableGetStringHelper(&variables, L"PROP6"));
58 + Assert::Equal(7ll, VariableGetNumericHelper(&variables, L"PROP7"));
59 + Assert::Equal(MAKEQWORDVERSION(1,1,0,0), VariableGetVersionHelper(&variables, L"PROP8"));
60 + Assert::Equal(gcnew String(L"1.1.0.0"), VariableGetStringHelper(&variables, L"PROP8"));
61 +
62 + Assert::Equal(42ll, VariableGetNumericHelper(&variables, L"OVERWRITTEN_STRING"));
63 + Assert::Equal(gcnew String(L"NEW"), VariableGetStringHelper(&variables, L"OVERWRITTEN_NUMBER"));
64 + }
65 + finally
66 + {
67 + VariablesUninitialize(&variables);
68 + }
69 + }
70 +
71 + [NamedFact]
72 + void VariablesParseXmlTest()
73 + {
74 + HRESULT hr = S_OK;
75 + IXMLDOMElement* pixeBundle = NULL;
76 + BURN_VARIABLES variables = { };
77 + try
78 + {
79 + LPCWSTR wzDocument =
80 + L"<Bundle>"
81 + L" <Variable Id='Var1' Type='numeric' Value='1' Hidden='no' Persisted='no' />"
82 + L" <Variable Id='Var2' Type='string' Value='String value.' Hidden='no' Persisted='no' />"
83 + L" <Variable Id='Var3' Type='version' Value='1.2.3.4' Hidden='no' Persisted='no' />"
84 + L" <Variable Id='Var4' Hidden='no' Persisted='no' />"
85 + L" <Variable Id='Var5' Type='string' Value='' Hidden='no' Persisted='no' />"
86 + L"</Bundle>";
87 +
88 + hr = VariableInitialize(&variables);
89 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
90 +
91 + // load XML document
92 + LoadBundleXmlHelper(wzDocument, &pixeBundle);
93 +
94 + hr = VariablesParseFromXml(&variables, pixeBundle);
95 + TestThrowOnFailure(hr, L"Failed to parse searches from XML.");
96 +
97 + // get and verify variable values
98 + Assert::Equal((int)BURN_VARIANT_TYPE_NUMERIC, VariableGetTypeHelper(&variables, L"Var1"));
99 + Assert::Equal((int)BURN_VARIANT_TYPE_STRING, VariableGetTypeHelper(&variables, L"Var2"));
100 + Assert::Equal((int)BURN_VARIANT_TYPE_VERSION, VariableGetTypeHelper(&variables, L"Var3"));
101 + Assert::Equal((int)BURN_VARIANT_TYPE_NONE, VariableGetTypeHelper(&variables, L"Var4"));
102 +
103 + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Var1"));
104 + Assert::Equal(gcnew String(L"String value."), VariableGetStringHelper(&variables, L"Var2"));
105 + Assert::Equal(MAKEQWORDVERSION(1,2,3,4), VariableGetVersionHelper(&variables, L"Var3"));
106 + }
107 + finally
108 + {
109 + ReleaseObject(pixeBundle);
110 + VariablesUninitialize(&variables);
111 + }
112 + }
113 +
114 + [NamedFact]
115 + void VariablesFormatTest()
116 + {
117 + HRESULT hr = S_OK;
118 + BURN_VARIABLES variables = { };
119 + LPWSTR scz = NULL;
120 + DWORD cch = 0;
121 + try
122 + {
123 + hr = VariableInitialize(&variables);
124 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
125 +
126 + // set variables
127 + VariableSetStringHelper(&variables, L"PROP1", L"VAL1");
128 + VariableSetStringHelper(&variables, L"PROP2", L"VAL2");
129 + VariableSetNumericHelper(&variables, L"PROP3", 3);
130 +
131 + // test string formatting
132 + Assert::Equal(gcnew String(L"NOPROP"), VariableFormatStringHelper(&variables, L"NOPROP"));
133 + Assert::Equal(gcnew String(L"VAL1"), VariableFormatStringHelper(&variables, L"[PROP1]"));
134 + Assert::Equal(gcnew String(L" VAL1 "), VariableFormatStringHelper(&variables, L" [PROP1] "));
135 + Assert::Equal(gcnew String(L"PRE VAL1"), VariableFormatStringHelper(&variables, L"PRE [PROP1]"));
136 + Assert::Equal(gcnew String(L"VAL1 POST"), VariableFormatStringHelper(&variables, L"[PROP1] POST"));
137 + Assert::Equal(gcnew String(L"PRE VAL1 POST"), VariableFormatStringHelper(&variables, L"PRE [PROP1] POST"));
138 + Assert::Equal(gcnew String(L"VAL1 MID VAL2"), VariableFormatStringHelper(&variables, L"[PROP1] MID [PROP2]"));
139 + Assert::Equal(gcnew String(L""), VariableFormatStringHelper(&variables, L"[NONE]"));
140 + Assert::Equal(gcnew String(L""), VariableFormatStringHelper(&variables, L"[prop1]"));
141 + Assert::Equal(gcnew String(L"["), VariableFormatStringHelper(&variables, L"[\\[]"));
142 + Assert::Equal(gcnew String(L"]"), VariableFormatStringHelper(&variables, L"[\\]]"));
143 + Assert::Equal(gcnew String(L"[]"), VariableFormatStringHelper(&variables, L"[]"));
144 + Assert::Equal(gcnew String(L"[NONE"), VariableFormatStringHelper(&variables, L"[NONE"));
145 + Assert::Equal(gcnew String(L"VAL2"), VariableGetFormattedHelper(&variables, L"PROP2"));
146 + Assert::Equal(gcnew String(L"3"), VariableGetFormattedHelper(&variables, L"PROP3"));
147 +
148 + hr = VariableFormatString(&variables, L"PRE [PROP1] POST", &scz, &cch);
149 + TestThrowOnFailure(hr, L"Failed to format string");
150 +
151 + Assert::Equal((DWORD)lstrlenW(scz), cch);
152 +
153 + hr = VariableFormatString(&variables, L"PRE [PROP1] POST", NULL, &cch);
154 + TestThrowOnFailure(hr, L"Failed to format string");
155 +
156 + Assert::Equal((DWORD)lstrlenW(scz), cch);
157 + }
158 + finally
159 + {
160 + VariablesUninitialize(&variables);
161 + ReleaseStr(scz);
162 + }
163 + }
164 +
165 + [NamedFact]
166 + void VariablesEscapeTest()
167 + {
168 + // test string escaping
169 + Assert::Equal(gcnew String(L"[\\[]"), VariableEscapeStringHelper(L"["));
170 + Assert::Equal(gcnew String(L"[\\]]"), VariableEscapeStringHelper(L"]"));
171 + Assert::Equal(gcnew String(L" [\\[]TEXT[\\]] "), VariableEscapeStringHelper(L" [TEXT] "));
172 + }
173 +
174 + [NamedFact]
175 + void VariablesConditionTest()
176 + {
177 + HRESULT hr = S_OK;
178 + BURN_VARIABLES variables = { };
179 + try
180 + {
181 + hr = VariableInitialize(&variables);
182 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
183 +
184 + // set variables
185 + VariableSetStringHelper(&variables, L"PROP1", L"VAL1");
186 + VariableSetStringHelper(&variables, L"PROP2", L"VAL2");
187 + VariableSetStringHelper(&variables, L"PROP3", L"VAL3");
188 + VariableSetStringHelper(&variables, L"PROP4", L"BEGIN MID END");
189 + VariableSetNumericHelper(&variables, L"PROP5", 5);
190 + VariableSetNumericHelper(&variables, L"PROP6", 6);
191 + VariableSetStringHelper(&variables, L"PROP7", L"");
192 + VariableSetNumericHelper(&variables, L"PROP8", 0);
193 + VariableSetStringHelper(&variables, L"_PROP9", L"VAL9");
194 + VariableSetNumericHelper(&variables, L"PROP10", -10);
195 + VariableSetNumericHelper(&variables, L"PROP11", 9223372036854775807ll);
196 + VariableSetNumericHelper(&variables, L"PROP12", -9223372036854775808ll);
197 + VariableSetNumericHelper(&variables, L"PROP13", 0x00010000);
198 + VariableSetNumericHelper(&variables, L"PROP14", 0x00000001);
199 + VariableSetNumericHelper(&variables, L"PROP15", 0x00010001);
200 + VariableSetVersionHelper(&variables, L"PROP16", MAKEQWORDVERSION(0,0,0,0));
201 + VariableSetVersionHelper(&variables, L"PROP17", MAKEQWORDVERSION(1,0,0,0));
202 + VariableSetVersionHelper(&variables, L"PROP18", MAKEQWORDVERSION(1,1,0,0));
203 + VariableSetVersionHelper(&variables, L"PROP19", MAKEQWORDVERSION(1,1,1,0));
204 + VariableSetVersionHelper(&variables, L"PROP20", MAKEQWORDVERSION(1,1,1,1));
205 + VariableSetNumericHelper(&variables, L"vPROP21", 1);
206 + VariableSetVersionHelper(&variables, L"PROP22", MAKEQWORDVERSION(65535,65535,65535,65535));
207 + VariableSetStringHelper(&variables, L"PROP23", L"1.1.1");
208 +
209 + // test conditions
210 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1"));
211 + Assert::True(EvaluateConditionHelper(&variables, L"PROP5"));
212 + Assert::False(EvaluateConditionHelper(&variables, L"PROP7"));
213 + Assert::False(EvaluateConditionHelper(&variables, L"PROP8"));
214 + Assert::True(EvaluateConditionHelper(&variables, L"_PROP9"));
215 + Assert::False(EvaluateConditionHelper(&variables, L"PROP16"));
216 + Assert::True(EvaluateConditionHelper(&variables, L"PROP17"));
217 +
218 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\""));
219 + Assert::False(EvaluateConditionHelper(&variables, L"NONE = \"NOT\""));
220 + Assert::False(EvaluateConditionHelper(&variables, L"PROP1 <> \"VAL1\""));
221 + Assert::True(EvaluateConditionHelper(&variables, L"NONE <> \"NOT\""));
222 +
223 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 ~= \"val1\""));
224 + Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"val1\""));
225 + Assert::False(EvaluateConditionHelper(&variables, L"PROP1 ~<> \"val1\""));
226 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 <> \"val1\""));
227 +
228 + Assert::True(EvaluateConditionHelper(&variables, L"PROP5 = 5"));
229 + Assert::False(EvaluateConditionHelper(&variables, L"PROP5 = 0"));
230 + Assert::False(EvaluateConditionHelper(&variables, L"PROP5 <> 5"));
231 + Assert::True(EvaluateConditionHelper(&variables, L"PROP5 <> 0"));
232 +
233 + Assert::True(EvaluateConditionHelper(&variables, L"PROP10 = -10"));
234 + Assert::False(EvaluateConditionHelper(&variables, L"PROP10 <> -10"));
235 +
236 + Assert::True(EvaluateConditionHelper(&variables, L"PROP17 = v1"));
237 + Assert::False(EvaluateConditionHelper(&variables, L"PROP17 = v0"));
238 + Assert::False(EvaluateConditionHelper(&variables, L"PROP17 <> v1"));
239 + Assert::True(EvaluateConditionHelper(&variables, L"PROP17 <> v0"));
240 +
241 + Assert::True(EvaluateConditionHelper(&variables, L"PROP16 = v0"));
242 + Assert::True(EvaluateConditionHelper(&variables, L"PROP17 = v1"));
243 + Assert::True(EvaluateConditionHelper(&variables, L"PROP18 = v1.1"));
244 + Assert::True(EvaluateConditionHelper(&variables, L"PROP19 = v1.1.1"));
245 + Assert::True(EvaluateConditionHelper(&variables, L"PROP20 = v1.1.1.1"));
246 + Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP20 = v1.1.1.1.0"));
247 + Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP20 = v1.1.1.1.1"));
248 + Assert::True(EvaluateConditionHelper(&variables, L"vPROP21 = 1"));
249 + Assert::True(EvaluateConditionHelper(&variables, L"PROP23 = v1.1.1"));
250 + Assert::True(EvaluateConditionHelper(&variables, L"v1.1.1 = PROP23"));
251 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 <> v1.1.1"));
252 + Assert::True(EvaluateConditionHelper(&variables, L"v1.1.1 <> PROP1"));
253 +
254 + Assert::False(EvaluateConditionHelper(&variables, L"PROP11 = 9223372036854775806"));
255 + Assert::True(EvaluateConditionHelper(&variables, L"PROP11 = 9223372036854775807"));
256 + Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP11 = 9223372036854775808"));
257 + Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP11 = 92233720368547758070000"));
258 +
259 + Assert::False(EvaluateConditionHelper(&variables, L"PROP12 = -9223372036854775807"));
260 + Assert::True(EvaluateConditionHelper(&variables, L"PROP12 = -9223372036854775808"));
261 + Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP12 = -9223372036854775809"));
262 + Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP12 = -92233720368547758080000"));
263 +
264 + Assert::True(EvaluateConditionHelper(&variables, L"PROP22 = v65535.65535.65535.65535"));
265 + Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP22 = v65536.65535.65535.65535"));
266 + Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP22 = v65535.655350000.65535.65535"));
267 +
268 + Assert::True(EvaluateConditionHelper(&variables, L"PROP5 < 6"));
269 + Assert::False(EvaluateConditionHelper(&variables, L"PROP5 < 5"));
270 + Assert::True(EvaluateConditionHelper(&variables, L"PROP5 > 4"));
271 + Assert::False(EvaluateConditionHelper(&variables, L"PROP5 > 5"));
272 + Assert::True(EvaluateConditionHelper(&variables, L"PROP5 <= 6"));
273 + Assert::True(EvaluateConditionHelper(&variables, L"PROP5 <= 5"));
274 + Assert::False(EvaluateConditionHelper(&variables, L"PROP5 <= 4"));
275 + Assert::True(EvaluateConditionHelper(&variables, L"PROP5 >= 4"));
276 + Assert::True(EvaluateConditionHelper(&variables, L"PROP5 >= 5"));
277 + Assert::False(EvaluateConditionHelper(&variables, L"PROP5 >= 6"));
278 +
279 + Assert::True(EvaluateConditionHelper(&variables, L"PROP4 << \"BEGIN\""));
280 + Assert::False(EvaluateConditionHelper(&variables, L"PROP4 << \"END\""));
281 + Assert::True(EvaluateConditionHelper(&variables, L"PROP4 >> \"END\""));
282 + Assert::False(EvaluateConditionHelper(&variables, L"PROP4 >> \"BEGIN\""));
283 + Assert::True(EvaluateConditionHelper(&variables, L"PROP4 >< \"MID\""));
284 + Assert::False(EvaluateConditionHelper(&variables, L"PROP4 >< \"NONE\""));
285 +
286 + Assert::True(EvaluateConditionHelper(&variables, L"PROP16 < v1.1"));
287 + Assert::False(EvaluateConditionHelper(&variables, L"PROP16 < v0"));
288 + Assert::True(EvaluateConditionHelper(&variables, L"PROP17 > v0.12"));
289 + Assert::False(EvaluateConditionHelper(&variables, L"PROP17 > v1"));
290 + Assert::True(EvaluateConditionHelper(&variables, L"PROP18 >= v1.0"));
291 + Assert::True(EvaluateConditionHelper(&variables, L"PROP18 >= v1.1"));
292 + Assert::False(EvaluateConditionHelper(&variables, L"PROP18 >= v2.1"));
293 + Assert::True(EvaluateConditionHelper(&variables, L"PROP19 <= v1.1234.1"));
294 + Assert::True(EvaluateConditionHelper(&variables, L"PROP19 <= v1.1.1"));
295 + Assert::False(EvaluateConditionHelper(&variables, L"PROP19 <= v1.0.123"));
296 +
297 + Assert::True(EvaluateConditionHelper(&variables, L"PROP6 = \"6\""));
298 + Assert::True(EvaluateConditionHelper(&variables, L"\"6\" = PROP6"));
299 + Assert::False(EvaluateConditionHelper(&variables, L"PROP6 = \"ABC\""));
300 + Assert::False(EvaluateConditionHelper(&variables, L"\"ABC\" = PROP6"));
301 + Assert::False(EvaluateConditionHelper(&variables, L"\"ABC\" = PROP6"));
302 +
303 + Assert::True(EvaluateConditionHelper(&variables, L"PROP13 << 1"));
304 + Assert::False(EvaluateConditionHelper(&variables, L"PROP13 << 0"));
305 + Assert::True(EvaluateConditionHelper(&variables, L"PROP14 >> 1"));
306 + Assert::False(EvaluateConditionHelper(&variables, L"PROP14 >> 0"));
307 + Assert::True(EvaluateConditionHelper(&variables, L"PROP15 >< 65537"));
308 + Assert::False(EvaluateConditionHelper(&variables, L"PROP15 >< 0"));
309 +
310 + Assert::False(EvaluateConditionHelper(&variables, L"NOT PROP1"));
311 + Assert::True(EvaluateConditionHelper(&variables, L"NOT (PROP1 <> \"VAL1\")"));
312 +
313 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND PROP2 = \"VAL2\""));
314 + Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
315 + Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"NOT\" AND PROP2 = \"VAL2\""));
316 + Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"NOT\" AND PROP2 = \"NOT\""));
317 +
318 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" OR PROP2 = \"VAL2\""));
319 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" OR PROP2 = \"NOT\""));
320 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"NOT\" OR PROP2 = \"VAL2\""));
321 + Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"NOT\" OR PROP2 = \"NOT\""));
322 +
323 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND PROP2 = \"VAL2\" OR PROP3 = \"NOT\""));
324 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\" OR PROP3 = \"VAL3\""));
325 + Assert::False(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\" OR PROP3 = \"NOT\""));
326 + Assert::True(EvaluateConditionHelper(&variables, L"PROP1 = \"VAL1\" AND (PROP2 = \"NOT\" OR PROP3 = \"VAL3\")"));
327 + Assert::True(EvaluateConditionHelper(&variables, L"(PROP1 = \"VAL1\" AND PROP2 = \"VAL2\") OR PROP3 = \"NOT\""));
328 +
329 + Assert::True(EvaluateConditionHelper(&variables, L"PROP3 = \"NOT\" OR PROP1 = \"VAL1\" AND PROP2 = \"VAL2\""));
330 + Assert::True(EvaluateConditionHelper(&variables, L"PROP3 = \"VAL3\" OR PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
331 + Assert::False(EvaluateConditionHelper(&variables, L"PROP3 = \"NOT\" OR PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
332 + Assert::True(EvaluateConditionHelper(&variables, L"(PROP3 = \"NOT\" OR PROP1 = \"VAL1\") AND PROP2 = \"VAL2\""));
333 + Assert::True(EvaluateConditionHelper(&variables, L"PROP3 = \"NOT\" OR (PROP1 = \"VAL1\" AND PROP2 = \"VAL2\")"));
334 +
335 + Assert::True(EvaluateFailureConditionHelper(&variables, L"="));
336 + Assert::True(EvaluateFailureConditionHelper(&variables, L"(PROP1"));
337 + Assert::True(EvaluateFailureConditionHelper(&variables, L"(PROP1 = \""));
338 + Assert::True(EvaluateFailureConditionHelper(&variables, L"1A"));
339 + Assert::True(EvaluateFailureConditionHelper(&variables, L"*"));
340 +
341 + Assert::True(EvaluateFailureConditionHelper(&variables, L"1 == 1"));
342 + }
343 + finally
344 + {
345 + VariablesUninitialize(&variables);
346 + }
347 + }
348 +
349 + [NamedFact]
350 + void VariablesSerializationTest()
351 + {
352 + HRESULT hr = S_OK;
353 + BYTE* pbBuffer = NULL;
354 + SIZE_T cbBuffer = 0;
355 + SIZE_T iBuffer = 0;
356 + BURN_VARIABLES variables1 = { };
357 + BURN_VARIABLES variables2 = { };
358 + try
359 + {
360 + // serialize
361 + hr = VariableInitialize(&variables1);
362 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
363 +
364 + VariableSetStringHelper(&variables1, L"PROP1", L"VAL1");
365 + VariableSetNumericHelper(&variables1, L"PROP2", 2);
366 + VariableSetVersionHelper(&variables1, L"PROP3", MAKEQWORDVERSION(1,1,1,1));
367 + VariableSetStringHelper(&variables1, L"PROP4", L"VAL4");
368 +
369 + hr = VariableSerialize(&variables1, FALSE, &pbBuffer, &cbBuffer);
370 + TestThrowOnFailure(hr, L"Failed to serialize variables.");
371 +
372 + // deserialize
373 + hr = VariableInitialize(&variables2);
374 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
375 +
376 + hr = VariableDeserialize(&variables2, FALSE, pbBuffer, cbBuffer, &iBuffer);
377 + TestThrowOnFailure(hr, L"Failed to deserialize variables.");
378 +
379 + Assert::Equal(gcnew String(L"VAL1"), VariableGetStringHelper(&variables2, L"PROP1"));
380 + Assert::Equal(2ll, VariableGetNumericHelper(&variables2, L"PROP2"));
381 + Assert::Equal(MAKEQWORDVERSION(1,1,1,1), VariableGetVersionHelper(&variables2, L"PROP3"));
382 + Assert::Equal(gcnew String(L"VAL4"), VariableGetStringHelper(&variables2, L"PROP4"));
383 + }
384 + finally
385 + {
386 + ReleaseBuffer(pbBuffer);
387 + VariablesUninitialize(&variables1);
388 + VariablesUninitialize(&variables2);
389 + }
390 + }
391 +
392 + [NamedFact]
393 + void VariablesBuiltInTest()
394 + {
395 + HRESULT hr = S_OK;
396 + BURN_VARIABLES variables = { };
397 + try
398 + {
399 + hr = VariableInitialize(&variables);
400 + TestThrowOnFailure(hr, L"Failed to initialize variables.");
401 +
402 + // VersionMsi
403 + Assert::True(EvaluateConditionHelper(&variables, L"VersionMsi >= v1.1"));
404 +
405 + // VersionNT
406 + Assert::True(EvaluateConditionHelper(&variables, L"VersionNT <> v0.0.0.0"));
407 +
408 + // VersionNT64
409 + if (nullptr == Environment::GetEnvironmentVariable("ProgramFiles(x86)"))
410 + {
411 + Assert::False(EvaluateConditionHelper(&variables, L"VersionNT64"));
412 + }
413 + else
414 + {
415 + Assert::True(EvaluateConditionHelper(&variables, L"VersionNT64"));
416 + }
417 +
418 + // attempt to set a built-in property
419 + hr = VariableSetString(&variables, L"VersionNT", L"VAL", FALSE);
420 + Assert::Equal(E_INVALIDARG, hr);
421 + Assert::False(EvaluateConditionHelper(&variables, L"VersionNT = \"VAL\""));
422 +
423 + VariableGetNumericHelper(&variables, L"NTProductType");
424 + VariableGetNumericHelper(&variables, L"NTSuiteBackOffice");
425 + VariableGetNumericHelper(&variables, L"NTSuiteDataCenter");
426 + VariableGetNumericHelper(&variables, L"NTSuiteEnterprise");
427 + VariableGetNumericHelper(&variables, L"NTSuitePersonal");
428 + VariableGetNumericHelper(&variables, L"NTSuiteSmallBusiness");
429 + VariableGetNumericHelper(&variables, L"NTSuiteSmallBusinessRestricted");
430 + VariableGetNumericHelper(&variables, L"NTSuiteWebServer");
431 + VariableGetNumericHelper(&variables, L"CompatibilityMode");
432 + VariableGetNumericHelper(&variables, L"Privileged");
433 + VariableGetNumericHelper(&variables, L"SystemLanguageID");
434 + VariableGetNumericHelper(&variables, L"TerminalServer");
435 + VariableGetNumericHelper(&variables, L"UserUILanguageID");
436 + VariableGetNumericHelper(&variables, L"UserLanguageID");
437 +
438 + // known folders
439 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::ApplicationData) + "\\", VariableGetStringHelper(&variables, L"AppDataFolder"));
440 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::CommonApplicationData) + "\\", VariableGetStringHelper(&variables, L"CommonAppDataFolder"));
441 +
442 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::ProgramFiles) + "\\", VariableGetStringHelper(&variables, L"ProgramFilesFolder"));
443 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::DesktopDirectory) + "\\", VariableGetStringHelper(&variables, L"DesktopFolder"));
444 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::Favorites) + "\\", VariableGetStringHelper(&variables, L"FavoritesFolder"));
445 + VariableGetStringHelper(&variables, L"FontsFolder");
446 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData) + "\\", VariableGetStringHelper(&variables, L"LocalAppDataFolder"));
447 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::Personal) + "\\", VariableGetStringHelper(&variables, L"PersonalFolder"));
448 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::Programs) + "\\", VariableGetStringHelper(&variables, L"ProgramMenuFolder"));
449 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::SendTo) + "\\", VariableGetStringHelper(&variables, L"SendToFolder"));
450 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::StartMenu) + "\\", VariableGetStringHelper(&variables, L"StartMenuFolder"));
451 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::Startup) + "\\", VariableGetStringHelper(&variables, L"StartupFolder"));
452 + VariableGetStringHelper(&variables, L"SystemFolder");
453 + VariableGetStringHelper(&variables, L"WindowsFolder");
454 + VariableGetStringHelper(&variables, L"WindowsVolume");
455 +
456 + Assert::Equal(System::IO::Path::GetTempPath(), System::IO::Path::GetFullPath(VariableGetStringHelper(&variables, L"TempFolder")));
457 +
458 + VariableGetStringHelper(&variables, L"AdminToolsFolder");
459 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::CommonProgramFiles) + "\\", VariableGetStringHelper(&variables, L"CommonFilesFolder"));
460 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::MyPictures) + "\\", VariableGetStringHelper(&variables, L"MyPicturesFolder"));
461 + Assert::Equal(Environment::GetFolderPath(Environment::SpecialFolder::Templates) + "\\", VariableGetStringHelper(&variables, L"TemplateFolder"));
462 +
463 + if (Environment::Is64BitOperatingSystem)
464 + {
465 + VariableGetStringHelper(&variables, L"ProgramFiles64Folder");
466 + VariableGetStringHelper(&variables, L"CommonFiles64Folder");
467 + VariableGetStringHelper(&variables, L"System64Folder");
468 + }
469 + }
470 + finally
471 + {
472 + VariablesUninitialize(&variables);
473 + }
474 + }
475 + };
476 +}
477 +}
478 +}
479 +}
480 +}
src/test/BurnUnitTest/precomp.cpp new
+3
@@ -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"
src/test/BurnUnitTest/precomp.h new
+78
@@ -0,0 +1,78 @@
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 <cryputil.h>
17 +#include <dlutil.h>
18 +#include <buffutil.h>
19 +#include <dirutil.h>
20 +#include <fileutil.h>
21 +#include <logutil.h>
22 +#include <memutil.h>
23 +#include <pathutil.h>
24 +#include <regutil.h>
25 +#include <resrutil.h>
26 +#include <shelutil.h>
27 +#include <strutil.h>
28 +#include <wiutil.h>
29 +#include <xmlutil.h>
30 +#include <dictutil.h>
31 +#include <deputil.h>
32 +
33 +#include <wixver.h>
34 +
35 +#include "BootstrapperEngine.h"
36 +#include "BootstrapperApplication.h"
37 +
38 +#include "platform.h"
39 +#include "variant.h"
40 +#include "variable.h"
41 +#include "condition.h"
42 +#include "search.h"
43 +#include "section.h"
44 +#include "approvedexe.h"
45 +#include "container.h"
46 +#include "catalog.h"
47 +#include "payload.h"
48 +#include "cabextract.h"
49 +#include "userexperience.h"
50 +#include "package.h"
51 +#include "update.h"
52 +#include "pseudobundle.h"
53 +#include "registration.h"
54 +#include "plan.h"
55 +#include "pipe.h"
56 +#include "logging.h"
57 +#include "core.h"
58 +#include "cache.h"
59 +#include "apply.h"
60 +#include "exeengine.h"
61 +#include "msiengine.h"
62 +#include "mspengine.h"
63 +#include "msuengine.h"
64 +#include "dependency.h"
65 +#include "elevation.h"
66 +#include "embedded.h"
67 +#include "manifest.h"
68 +#include "splashscreen.h"
69 +#include "bitsengine.h"
70 +
71 +#pragma managed
72 +#include <vcclr.h>
73 +
74 +#include "BurnTestException.h"
75 +#include "BurnTestFixture.h"
76 +#include "BurnUnitTest.h"
77 +#include "VariableHelpers.h"
78 +#include "ManifestHelpers.h"