From 584213c5ffeca09b3fe24bd5e92f73fd057ac642 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Fri, 3 Jun 2022 17:49:15 -0500 Subject: Add RegReadUnexpandedString to get an unexpanded REG_EXPAND_SZ value. --- src/libs/dutil/test/DUtilUnitTest/RegUtilTest.cpp | 679 ++++++++++++++++++++++ 1 file changed, 679 insertions(+) create mode 100644 src/libs/dutil/test/DUtilUnitTest/RegUtilTest.cpp (limited to 'src/libs/dutil/test/DUtilUnitTest/RegUtilTest.cpp') diff --git a/src/libs/dutil/test/DUtilUnitTest/RegUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/RegUtilTest.cpp new file mode 100644 index 00000000..575e3238 --- /dev/null +++ b/src/libs/dutil/test/DUtilUnitTest/RegUtilTest.cpp @@ -0,0 +1,679 @@ +// 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. + +#include "precomp.h" + +using namespace System; +using namespace System::Collections::Generic; +using namespace System::Runtime::InteropServices; +using namespace Xunit; +using namespace WixBuildTools::TestSupport; + +LPCWSTR wzBaseRegKey = L"Software\\RegUtilTest\\"; +LPWSTR rgwzMultiValue[2] = { L"First", L"Second" }; +LPWSTR rgwzEmptyMultiValue[2] = { L"", L"" }; + +HKEY hkBase; + +namespace DutilTests +{ + public ref class RegUtil : IDisposable + { + private: + + void CreateBaseKey() + { + HRESULT hr = RegCreate(HKEY_CURRENT_USER, wzBaseRegKey, KEY_ALL_ACCESS, &hkBase); + NativeAssert::Succeeded(hr, "Failed to create base key."); + } + + public: + RegUtil() + { + HRESULT hr = RegInitialize(); + NativeAssert::Succeeded(hr, "RegInitialize failed."); + } + + ~RegUtil() + { + RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + if (hkBase) + { + RegDelete(hkBase, NULL, REG_KEY_DEFAULT, TRUE); + } + + ReleaseRegKey(hkBase); + + RegUninitialize(); + } + + [Fact] + void RegUtilStringValueTest() + { + this->StringValueTest(); + } + + [Fact] + void RegUtilStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->StringValueTest(); + } + + void StringValueTest() + { + HRESULT hr = S_OK; + LPWSTR sczValue = NULL; + LPCWSTR wzValue = L"Value"; + + try + { + this->CreateBaseKey(); + + hr = RegWriteString(hkBase, L"String", wzValue); + NativeAssert::Succeeded(hr, "Failed to write string value."); + + hr = RegReadString(hkBase, L"String", &sczValue); + NativeAssert::Succeeded(hr, "Failed to read string value."); + NativeAssert::StringEqual(wzValue, sczValue); + + ReleaseNullStr(sczValue); + hr = StrAllocString(&sczValue, L"e", 0); + NativeAssert::Succeeded(hr, "Failed to reallocate string value."); + + hr = RegReadString(hkBase, L"String", &sczValue); + NativeAssert::Succeeded(hr, "Failed to read string value."); + NativeAssert::StringEqual(wzValue, sczValue); + } + finally + { + ReleaseStr(sczValue); + } + } + + [Fact] + void RegUtilPartialStringValueTest() + { + this->PartialStringValueTest(); + } + + [Fact] + void RegUtilPartialStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->PartialStringValueTest(); + } + + void PartialStringValueTest() + { + HRESULT hr = S_OK; + LPWSTR sczValue = NULL; + LPCWSTR wzValue = L"Value"; + BOOL fNeedsExpansion = FALSE; + + try + { + this->CreateBaseKey(); + + // Use API directly to write non-null terminated string. + hr = HRESULT_FROM_WIN32(::RegSetValueExW(hkBase, L"PartialString", 0, REG_SZ, reinterpret_cast(wzValue), 4 * sizeof(WCHAR))); + NativeAssert::Succeeded(hr, "Failed to write partial string value."); + + hr = RegReadString(hkBase, L"PartialString", &sczValue); + NativeAssert::Succeeded(hr, "Failed to read partial string value."); + NativeAssert::StringEqual(L"Valu", sczValue); + + hr = RegReadUnexpandedString(hkBase, L"PartialString", &fNeedsExpansion, &sczValue); + NativeAssert::Succeeded(hr, "Failed to read partial unexpanded string value."); + NativeAssert::StringEqual(L"Valu", sczValue); + Assert::False(fNeedsExpansion); + } + finally + { + ReleaseStr(sczValue); + } + } + + [Fact] + void RegUtilEmptyStringValueTest() + { + this->EmptyStringValueTest(); + } + + [Fact] + void RegUtilEmptyStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->EmptyStringValueTest(); + } + + void EmptyStringValueTest() + { + HRESULT hr = S_OK; + LPWSTR sczValue = NULL; + + try + { + this->CreateBaseKey(); + + // Use API directly to write non-null terminated string. + hr = HRESULT_FROM_WIN32(::RegSetValueExW(hkBase, L"EmptyString", 0, REG_SZ, reinterpret_cast(L""), 0)); + NativeAssert::Succeeded(hr, "Failed to write partial string value."); + + hr = RegReadString(hkBase, L"EmptyString", &sczValue); + NativeAssert::Succeeded(hr, "Failed to read partial string value."); + NativeAssert::StringEqual(L"", sczValue); + } + finally + { + ReleaseStr(sczValue); + } + } + + [Fact] + void RegUtilExpandStringValueTest() + { + this->ExpandStringValueTest(); + } + + [Fact] + void RegUtilExpandStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->ExpandStringValueTest(); + } + + void ExpandStringValueTest() + { + HRESULT hr = S_OK; + LPWSTR sczValue = NULL; + LPCWSTR wzValue = L"Value_%USERNAME%"; + String^ expandedValue = Environment::ExpandEnvironmentVariables(gcnew String(wzValue)); + + try + { + this->CreateBaseKey(); + + hr = RegWriteExpandString(hkBase, L"ExpandString", wzValue); + NativeAssert::Succeeded(hr, "Failed to write expand string value."); + + hr = RegReadString(hkBase, L"ExpandString", &sczValue); + NativeAssert::Succeeded(hr, "Failed to read expand string value."); + WixAssert::StringEqual(expandedValue, gcnew String(sczValue), false); + } + finally + { + ReleaseStr(sczValue); + } + } + + [Fact] + void RegUtilNotExpandStringValueTest() + { + this->NotExpandStringValueTest(); + } + + [Fact] + void RegUtilNotExpandStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->NotExpandStringValueTest(); + } + + void NotExpandStringValueTest() + { + HRESULT hr = S_OK; + LPWSTR sczValue = NULL; + BOOL fNeedsExpansion = FALSE; + LPCWSTR wzValue = L"Value_%USERNAME%"; + + try + { + this->CreateBaseKey(); + + hr = RegWriteExpandString(hkBase, L"NotExpandString", wzValue); + NativeAssert::Succeeded(hr, "Failed to write expand string value."); + + hr = RegReadUnexpandedString(hkBase, L"NotExpandString", &fNeedsExpansion, &sczValue); + NativeAssert::Succeeded(hr, "Failed to read expand string value."); + NativeAssert::StringEqual(wzValue, sczValue); + Assert::True(fNeedsExpansion); + } + finally + { + ReleaseStr(sczValue); + } + } + + [Fact] + void RegUtilMultiStringValueTest() + { + this->MultiStringValueTest(); + } + + [Fact] + void RegUtilMultiStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->MultiStringValueTest(); + } + + void MultiStringValueTest() + { + HRESULT hr = S_OK; + LPWSTR* rgsczStrings = NULL; + DWORD cStrings = 0; + + try + { + this->CreateBaseKey(); + + hr = RegWriteStringArray(hkBase, L"MultiString", rgwzMultiValue, 2); + NativeAssert::Succeeded(hr, "Failed to write multi string value."); + + hr = RegReadStringArray(hkBase, L"MultiString", &rgsczStrings, &cStrings); + NativeAssert::Succeeded(hr, "Failed to read multi string value."); + Assert::Equal(2, cStrings); + NativeAssert::StringEqual(L"First", rgsczStrings[0]); + NativeAssert::StringEqual(L"Second", rgsczStrings[1]); + } + finally + { + ReleaseStrArray(rgsczStrings, cStrings); + } + } + + [Fact] + void RegUtilPartialMultiStringValueTest() + { + this->PartialMultiStringValueTest(); + } + + [Fact] + void RegUtilPartialMultiStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->PartialMultiStringValueTest(); + } + + void PartialMultiStringValueTest() + { + HRESULT hr = S_OK; + LPWSTR* rgsczStrings = NULL; + DWORD cStrings = 0; + + try + { + this->CreateBaseKey(); + + // Use API directly to write non-double-null terminated string. + hr = HRESULT_FROM_WIN32(::RegSetValueExW(hkBase, L"PartialMultiString", 0, REG_MULTI_SZ, reinterpret_cast(L"First\0Second"), 13 * sizeof(WCHAR))); + NativeAssert::Succeeded(hr, "Failed to write partial multi string value."); + + hr = RegReadStringArray(hkBase, L"PartialMultiString", &rgsczStrings, &cStrings); + NativeAssert::Succeeded(hr, "Failed to read partial multi string value."); + Assert::Equal(2, cStrings); + NativeAssert::StringEqual(L"First", rgsczStrings[0]); + NativeAssert::StringEqual(L"Second", rgsczStrings[1]); + } + finally + { + ReleaseStrArray(rgsczStrings, cStrings); + } + } + + [Fact] + void RegUtilEmptyMultiStringValueTest() + { + this->EmptyMultiStringValueTest(); + } + + [Fact] + void RegUtilEmptyMultiStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->EmptyMultiStringValueTest(); + } + + void EmptyMultiStringValueTest() + { + HRESULT hr = S_OK; + LPWSTR* rgsczStrings = NULL; + DWORD cStrings = 0; + + try + { + this->CreateBaseKey(); + + hr = RegWriteStringArray(hkBase, L"EmptyMultiString", rgwzMultiValue, 0); + NativeAssert::Succeeded(hr, "Failed to write empty multi string value."); + + hr = RegReadStringArray(hkBase, L"EmptyMultiString", &rgsczStrings, &cStrings); + NativeAssert::Succeeded(hr, "Failed to read empty multi string value."); + Assert::Equal(0, cStrings); + } + finally + { + ReleaseStrArray(rgsczStrings, cStrings); + } + } + + [Fact] + void RegUtilOneEmptyMultiStringValueTest() + { + this->OneEmptyMultiStringValueTest(); + } + + [Fact] + void RegUtilOneEmptyMultiStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->OneEmptyMultiStringValueTest(); + } + + void OneEmptyMultiStringValueTest() + { + HRESULT hr = S_OK; + LPWSTR* rgsczStrings = NULL; + DWORD cStrings = 0; + + try + { + this->CreateBaseKey(); + + hr = RegWriteStringArray(hkBase, L"OneEmptyMultiString", rgwzEmptyMultiValue, 1); + NativeAssert::Succeeded(hr, "Failed to write one empty multi string value."); + + hr = RegReadStringArray(hkBase, L"OneEmptyMultiString", &rgsczStrings, &cStrings); + NativeAssert::Succeeded(hr, "Failed to read one empty multi string value."); + Assert::Equal(0, cStrings); + } + finally + { + ReleaseStrArray(rgsczStrings, cStrings); + } + } + + [Fact] + void RegUtilTwoEmptyMultiStringValueTest() + { + this->TwoEmptyMultiStringValueTest(); + } + + [Fact] + void RegUtilTwoEmptyMultiStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->TwoEmptyMultiStringValueTest(); + } + + void TwoEmptyMultiStringValueTest() + { + HRESULT hr = S_OK; + LPWSTR* rgsczStrings = NULL; + DWORD cStrings = 0; + + try + { + this->CreateBaseKey(); + + hr = RegWriteStringArray(hkBase, L"OneEmptyMultiString", rgwzEmptyMultiValue, 2); + NativeAssert::Succeeded(hr, "Failed to write one empty multi string value."); + + hr = RegReadStringArray(hkBase, L"OneEmptyMultiString", &rgsczStrings, &cStrings); + NativeAssert::Succeeded(hr, "Failed to read one empty multi string value."); + Assert::Equal(2, cStrings); + NativeAssert::StringEqual(L"", rgsczStrings[0]); + NativeAssert::StringEqual(L"", rgsczStrings[1]); + } + finally + { + ReleaseStrArray(rgsczStrings, cStrings); + } + } + + [Fact] + void RegUtilOnePartialEmptyMultiStringValueTest() + { + this->OnePartialEmptyMultiStringValueTest(); + } + + [Fact] + void RegUtilOnePartialEmptyMultiStringValueFallbackTest() + { + RegFunctionForceFallback(); + this->OnePartialEmptyMultiStringValueTest(); + } + + void OnePartialEmptyMultiStringValueTest() + { + HRESULT hr = S_OK; + LPWSTR* rgsczStrings = NULL; + DWORD cStrings = 0; + + try + { + this->CreateBaseKey(); + + // Use API directly to write non-double-null terminated string. + hr = HRESULT_FROM_WIN32(::RegSetValueExW(hkBase, L"OnePartialEmptyMultiString", 0, REG_MULTI_SZ, reinterpret_cast(L""), 1 * sizeof(WCHAR))); + NativeAssert::Succeeded(hr, "Failed to write partial empty multi string value."); + + hr = RegReadStringArray(hkBase, L"OnePartialEmptyMultiString", &rgsczStrings, &cStrings); + NativeAssert::Succeeded(hr, "Failed to read partial empty multi string value."); + Assert::Equal(0, cStrings); + } + finally + { + ReleaseStrArray(rgsczStrings, cStrings); + } + } + + [Fact] + void RegUtilBinaryValueTest() + { + this->BinaryValueTest(); + } + + [Fact] + void RegUtilBinaryValueFallbackTest() + { + RegFunctionForceFallback(); + this->BinaryValueTest(); + } + + void BinaryValueTest() + { + HRESULT hr = S_OK; + BYTE pbSource[4] = { 1, 2, 3, 4 }; + BYTE* pbBuffer = NULL; + SIZE_T cbBuffer = 0; + + try + { + this->CreateBaseKey(); + + hr = RegWriteBinary(hkBase, L"Binary", pbSource, 4); + NativeAssert::Succeeded(hr, "Failed to write binary value."); + + hr = RegReadBinary(hkBase, L"Binary", &pbBuffer, &cbBuffer); + NativeAssert::Succeeded(hr, "Failed to read binary value."); + Assert::Equal(4, cbBuffer); + Assert::Equal(1, pbBuffer[0]); + Assert::Equal(2, pbBuffer[1]); + Assert::Equal(3, pbBuffer[2]); + Assert::Equal(4, pbBuffer[3]); + } + finally + { + ReleaseMem(pbBuffer); + } + } + + [Fact] + void RegUtilEmptyBinaryValueTest() + { + this->EmptyBinaryValueTest(); + } + + [Fact] + void RegUtilEmptyBinaryValueFallbackTest() + { + RegFunctionForceFallback(); + this->EmptyBinaryValueTest(); + } + + void EmptyBinaryValueTest() + { + HRESULT hr = S_OK; + BYTE* pbBuffer = NULL; + SIZE_T cbBuffer = 0; + + try + { + this->CreateBaseKey(); + + hr = RegWriteBinary(hkBase, L"Binary", NULL, 0); + NativeAssert::Succeeded(hr, "Failed to write binary value."); + + hr = RegReadBinary(hkBase, L"Binary", &pbBuffer, &cbBuffer); + NativeAssert::Succeeded(hr, "Failed to read binary value."); + Assert::Equal(0, cbBuffer); + } + finally + { + ReleaseMem(pbBuffer); + } + } + + [Fact] + void RegUtilQwordVersionValueTest() + { + this->QwordVersionValueTest(); + } + + [Fact] + void RegUtilQwordVersionValueFallbackTest() + { + RegFunctionForceFallback(); + this->QwordVersionValueTest(); + } + + void QwordVersionValueTest() + { + HRESULT hr = S_OK; + DWORD64 qwVersion = FILEMAKEVERSION(1, 2, 3, 4); + DWORD64 qwValue = 0; + + this->CreateBaseKey(); + + hr = RegWriteQword(hkBase, L"QwordVersion", qwVersion); + NativeAssert::Succeeded(hr, "Failed to write qword version value."); + + hr = RegReadVersion(hkBase, L"QwordVersion", &qwValue); + NativeAssert::Succeeded(hr, "Failed to read qword version value."); + Assert::Equal(qwVersion, qwValue); + } + + [Fact] + void RegUtilStringVersionValueTest() + { + this->StringVersionValueTest(); + } + + [Fact] + void RegUtilStringVersionValueFallbackTest() + { + RegFunctionForceFallback(); + this->StringVersionValueTest(); + } + + void StringVersionValueTest() + { + HRESULT hr = S_OK; + LPCWSTR wzVersion = L"65535.65535.65535.65535"; + DWORD64 qwValue = 0; + + this->CreateBaseKey(); + + hr = RegWriteString(hkBase, L"StringVersion", wzVersion); + NativeAssert::Succeeded(hr, "Failed to write string version value."); + + hr = RegReadVersion(hkBase, L"StringVersion", &qwValue); + NativeAssert::Succeeded(hr, "Failed to read string version value."); + Assert::Equal(MAXDWORD64, qwValue); + } + + [Fact] + void RegUtilQwordWixVersionValueTest() + { + this->QwordWixVersionValueTest(); + } + + [Fact] + void RegUtilQwordWixVersionValueFallbackTest() + { + RegFunctionForceFallback(); + this->QwordWixVersionValueTest(); + } + + void QwordWixVersionValueTest() + { + HRESULT hr = S_OK; + DWORD64 qwVersion = FILEMAKEVERSION(1, 2, 3, 4); + VERUTIL_VERSION* pVersion = NULL; + + try + { + this->CreateBaseKey(); + + hr = RegWriteQword(hkBase, L"QwordWixVersion", qwVersion); + NativeAssert::Succeeded(hr, "Failed to write qword wix version value."); + + hr = RegReadWixVersion(hkBase, L"QwordWixVersion", &pVersion); + NativeAssert::Succeeded(hr, "Failed to read qword wix version value."); + NativeAssert::StringEqual(L"1.2.3.4", pVersion->sczVersion); + } + finally + { + ReleaseVerutilVersion(pVersion); + } + } + + [Fact] + void RegUtilStringWixVersionValueTest() + { + this->StringWixVersionValueTest(); + } + + [Fact] + void RegUtilStringWixVersionValueFallbackTest() + { + RegFunctionForceFallback(); + this->StringWixVersionValueTest(); + } + + void StringWixVersionValueTest() + { + HRESULT hr = S_OK; + LPCWSTR wzVersion = L"65535.65535.65535.65535-abc+def"; + VERUTIL_VERSION* pVersion = NULL; + + try + { + this->CreateBaseKey(); + + hr = RegWriteString(hkBase, L"StringWixVersion", wzVersion); + NativeAssert::Succeeded(hr, "Failed to write string wix version value."); + + hr = RegReadWixVersion(hkBase, L"StringWixVersion", &pVersion); + NativeAssert::Succeeded(hr, "Failed to read string wix version value."); + NativeAssert::StringEqual(wzVersion, pVersion->sczVersion); + } + finally + { + ReleaseVerutilVersion(pVersion); + } + } + }; +} -- cgit v1.2.3-55-g6feb