@joebigelow / wix / commits / 9c4b5559

Import DUtilUnitTest from old wix4 repo.

Sean Hall committed Jul 11, 2020 at 21:11 UTC 9c4b5559ccb55491fe68b0096d1be0496fd6fcc7
25 files changed +3794
src/test/DUtilUnitTest/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 Dutil unit tests")];
10 +[assembly: AssemblyDescriptionAttribute("Dutil unit tests")];
11 +[assembly: AssemblyCultureAttribute("")];
12 +[assembly: ComVisible(false)];
src/test/DUtilUnitTest/CondUtilTest.cpp new
+190
@@ -0,0 +1,190 @@
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 DutilTests
6 +{
7 + using namespace System;
8 + using namespace Xunit;
9 + using namespace WixTest;
10 +
11 + public ref class CondUtil
12 + {
13 + public:
14 + [NamedFact(Skip = "condutil Not Implemented Yet.")]
15 + void CondEvaluateTest()
16 + {
17 + HRESULT hr = S_OK;
18 + VARIABLES_HANDLE pVariables = NULL;
19 +
20 + try
21 + {
22 + hr = VarCreate(&pVariables);
23 + NativeAssert::Succeeded(hr, "Failed to initialize variables.");
24 +
25 + // set variables
26 + VarSetStringHelper(pVariables, L"PROP1", L"VAL1");
27 + VarSetStringHelper(pVariables, L"PROP2", L"VAL2");
28 + VarSetStringHelper(pVariables, L"PROP3", L"VAL3");
29 + VarSetStringHelper(pVariables, L"PROP4", L"BEGIN MID END");
30 + VarSetNumericHelper(pVariables, L"PROP5", 5);
31 + VarSetNumericHelper(pVariables, L"PROP6", 6);
32 + VarSetStringHelper(pVariables, L"PROP7", L"");
33 + VarSetNumericHelper(pVariables, L"PROP8", 0);
34 + VarSetStringHelper(pVariables, L"_PROP9", L"VAL9");
35 + VarSetNumericHelper(pVariables, L"PROP10", -10);
36 + VarSetNumericHelper(pVariables, L"PROP11", 9223372036854775807ll);
37 + VarSetNumericHelper(pVariables, L"PROP12", -9223372036854775808ll);
38 + VarSetNumericHelper(pVariables, L"PROP13", 0x00010000);
39 + VarSetNumericHelper(pVariables, L"PROP14", 0x00000001);
40 + VarSetNumericHelper(pVariables, L"PROP15", 0x00010001);
41 + VarSetVersionHelper(pVariables, L"PROP16", MAKEQWORDVERSION(0, 0, 0, 0));
42 + VarSetVersionHelper(pVariables, L"PROP17", MAKEQWORDVERSION(1, 0, 0, 0));
43 + VarSetVersionHelper(pVariables, L"PROP18", MAKEQWORDVERSION(1, 1, 0, 0));
44 + VarSetVersionHelper(pVariables, L"PROP19", MAKEQWORDVERSION(1, 1, 1, 0));
45 + VarSetVersionHelper(pVariables, L"PROP20", MAKEQWORDVERSION(1, 1, 1, 1));
46 + VarSetNumericHelper(pVariables, L"vPROP21", 1);
47 + VarSetVersionHelper(pVariables, L"PROP22", MAKEQWORDVERSION(65535, 65535, 65535, 65535));
48 + VarSetStringHelper(pVariables, L"PROP23", L"1.1.1");
49 +
50 + // test conditions
51 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1"));
52 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5"));
53 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP7"));
54 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP8"));
55 + Assert::True(EvaluateConditionHelper(pVariables, L"_PROP9"));
56 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP16"));
57 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP17"));
58 +
59 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\""));
60 + Assert::False(EvaluateConditionHelper(pVariables, L"NONE = \"NOT\""));
61 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 <> \"VAL1\""));
62 + Assert::True(EvaluateConditionHelper(pVariables, L"NONE <> \"NOT\""));
63 +
64 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 ~= \"val1\""));
65 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"val1\""));
66 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 ~<> \"val1\""));
67 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 <> \"val1\""));
68 +
69 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 = 5"));
70 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 = 0"));
71 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 <> 5"));
72 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 <> 0"));
73 +
74 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP10 = -10"));
75 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP10 <> -10"));
76 +
77 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP17 = v1"));
78 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP17 = v0"));
79 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP17 <> v1"));
80 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP17 <> v0"));
81 +
82 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP16 = v0"));
83 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP17 = v1"));
84 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP18 = v1.1"));
85 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP19 = v1.1.1"));
86 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP20 = v1.1.1.1"));
87 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP20 = v1.1.1.1.0"));
88 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP20 = v1.1.1.1.1"));
89 + Assert::True(EvaluateConditionHelper(pVariables, L"vPROP21 = 1"));
90 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP23 = v1.1.1"));
91 + Assert::True(EvaluateConditionHelper(pVariables, L"v1.1.1 = PROP23"));
92 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 <> v1.1.1"));
93 + Assert::True(EvaluateConditionHelper(pVariables, L"v1.1.1 <> PROP1"));
94 +
95 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP11 = 9223372036854775806"));
96 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP11 = 9223372036854775807"));
97 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP11 = 9223372036854775808"));
98 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP11 = 92233720368547758070000"));
99 +
100 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP12 = -9223372036854775807"));
101 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP12 = -9223372036854775808"));
102 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP12 = -9223372036854775809"));
103 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP12 = -92233720368547758080000"));
104 +
105 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP22 = v65535.65535.65535.65535"));
106 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP22 = v65536.65535.65535.65535"));
107 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP22 = v65535.655350000.65535.65535"));
108 +
109 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 < 6"));
110 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 < 5"));
111 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 > 4"));
112 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 > 5"));
113 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 <= 6"));
114 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 <= 5"));
115 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 <= 4"));
116 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 >= 4"));
117 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 >= 5"));
118 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 >= 6"));
119 +
120 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP4 << \"BEGIN\""));
121 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP4 << \"END\""));
122 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP4 >> \"END\""));
123 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP4 >> \"BEGIN\""));
124 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP4 >< \"MID\""));
125 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP4 >< \"NONE\""));
126 +
127 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP16 < v1.1"));
128 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP16 < v0"));
129 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP17 > v0.12"));
130 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP17 > v1"));
131 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP18 >= v1.0"));
132 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP18 >= v1.1"));
133 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP18 >= v2.1"));
134 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP19 <= v1.1234.1"));
135 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP19 <= v1.1.1"));
136 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP19 <= v1.0.123"));
137 +
138 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP6 = \"6\""));
139 + Assert::True(EvaluateConditionHelper(pVariables, L"\"6\" = PROP6"));
140 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP6 = \"ABC\""));
141 + Assert::False(EvaluateConditionHelper(pVariables, L"\"ABC\" = PROP6"));
142 + Assert::False(EvaluateConditionHelper(pVariables, L"\"ABC\" = PROP6"));
143 +
144 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP13 << 1"));
145 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP13 << 0"));
146 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP14 >> 1"));
147 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP14 >> 0"));
148 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP15 >< 65537"));
149 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP15 >< 0"));
150 +
151 + Assert::False(EvaluateConditionHelper(pVariables, L"NOT PROP1"));
152 + Assert::True(EvaluateConditionHelper(pVariables, L"NOT (PROP1 <> \"VAL1\")"));
153 +
154 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND PROP2 = \"VAL2\""));
155 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
156 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"NOT\" AND PROP2 = \"VAL2\""));
157 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"NOT\" AND PROP2 = \"NOT\""));
158 +
159 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" OR PROP2 = \"VAL2\""));
160 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" OR PROP2 = \"NOT\""));
161 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"NOT\" OR PROP2 = \"VAL2\""));
162 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"NOT\" OR PROP2 = \"NOT\""));
163 +
164 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND PROP2 = \"VAL2\" OR PROP3 = \"NOT\""));
165 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\" OR PROP3 = \"VAL3\""));
166 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\" OR PROP3 = \"NOT\""));
167 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND (PROP2 = \"NOT\" OR PROP3 = \"VAL3\")"));
168 + Assert::True(EvaluateConditionHelper(pVariables, L"(PROP1 = \"VAL1\" AND PROP2 = \"VAL2\") OR PROP3 = \"NOT\""));
169 +
170 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP3 = \"NOT\" OR PROP1 = \"VAL1\" AND PROP2 = \"VAL2\""));
171 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP3 = \"VAL3\" OR PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
172 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP3 = \"NOT\" OR PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
173 + Assert::True(EvaluateConditionHelper(pVariables, L"(PROP3 = \"NOT\" OR PROP1 = \"VAL1\") AND PROP2 = \"VAL2\""));
174 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP3 = \"NOT\" OR (PROP1 = \"VAL1\" AND PROP2 = \"VAL2\")"));
175 +
176 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"="));
177 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"(PROP1"));
178 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"(PROP1 = \""));
179 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"1A"));
180 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"*"));
181 +
182 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"1 == 1"));
183 + }
184 + finally
185 + {
186 + ReleaseVariables(pVariables);
187 + }
188 + }
189 + };
190 +}
src/test/DUtilUnitTest/DUtilUnitTest.vcxproj new
+73
@@ -0,0 +1,73 @@
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>{AB7EE608-E5FB-42A5-831F-0DEEEA141223}</ProjectGuid>
19 + <RootNamespace>DUtilUnitTests</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</ProjectAdditionalIncludeDirectories>
28 + <ProjectAdditionalLinkLibraries>rpcrt4.lib;dutil.lib;Mpr.lib;Ws2_32.lib;urlmon.lib;wininet.lib</ProjectAdditionalLinkLibraries>
29 + </PropertyGroup>
30 + <ItemGroup>
31 + <ClCompile Include="AssemblyInfo.cpp" />
32 + <ClCompile Include="CondUtilTest.cpp" />
33 + <ClCompile Include="DictUtilTest.cpp" />
34 + <ClCompile Include="DirUtilTests.cpp" />
35 + <ClCompile Include="FileUtilTest.cpp" />
36 + <ClCompile Include="GuidUtilTest.cpp" />
37 + <ClCompile Include="IniUtilTest.cpp" />
38 + <ClCompile Include="MemUtilTest.cpp" />
39 + <ClCompile Include="MonUtilTest.cpp" />
40 + <ClCompile Include="PathUtilTest.cpp" />
41 + <ClCompile Include="SceUtilTest.cpp" Condition=" Exists('$(SqlCESdkIncludePath)') " />
42 + <ClCompile Include="StrUtilTest.cpp" />
43 + <ClCompile Include="UriUtilTest.cpp" />
44 + <ClCompile Include="VarHelpers.cpp" />
45 + <ClCompile Include="VarUtilTest.cpp" />
46 + </ItemGroup>
47 + <ItemGroup>
48 + <ClInclude Include="precomp.h" />
49 + <ClInclude Include="error.h" />
50 + <ClInclude Include="VarHelpers.h" />
51 + </ItemGroup>
52 + <ItemGroup>
53 + <ResourceCompile Include="UnitTest.rc" />
54 + </ItemGroup>
55 + <ItemGroup>
56 + <Reference Include="System" />
57 + <Reference Include="xunit">
58 + <HintPath>$(XunitPath)\xunit.dll</HintPath>
59 + </Reference>
60 + </ItemGroup>
61 + <ItemGroup>
62 + <ProjectReference Include="..\..\..\..\src\libs\dutil\dutil.vcxproj" />
63 + <ProjectReference Include="..\..\WixCppCliTestTools\WixCppCliTestTools.vcxproj">
64 + <Project>{95BABD97-FBDB-453A-AF8A-FA031A07B599}</Project>
65 + <Name>WixCppCliTestTools</Name>
66 + </ProjectReference>
67 + <ProjectReference Include="..\..\WixTestTools\WixTestTools.csproj">
68 + <Project>{55CB1042-647B-4347-9876-3EA607AF8DCE}</Project>
69 + <Name>WixTestTools</Name>
70 + </ProjectReference>
71 + </ItemGroup>
72 + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
73 +</Project>
src/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters new
+77
@@ -0,0 +1,77 @@
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;mfcribbon-ms</Extensions>
15 + </Filter>
16 + </ItemGroup>
17 + <ItemGroup>
18 + <ClCompile Include="AssemblyInfo.cpp">
19 + <Filter>Source Files</Filter>
20 + </ClCompile>
21 + <ClCompile Include="CondUtilTest.cpp">
22 + <Filter>Source Files</Filter>
23 + </ClCompile>
24 + <ClCompile Include="DictUtilTest.cpp">
25 + <Filter>Source Files</Filter>
26 + </ClCompile>
27 + <ClCompile Include="DirUtilTests.cpp">
28 + <Filter>Source Files</Filter>
29 + </ClCompile>
30 + <ClCompile Include="FileUtilTest.cpp">
31 + <Filter>Source Files</Filter>
32 + </ClCompile>
33 + <ClCompile Include="GuidUtilTest.cpp">
34 + <Filter>Source Files</Filter>
35 + </ClCompile>
36 + <ClCompile Include="IniUtilTest.cpp">
37 + <Filter>Source Files</Filter>
38 + </ClCompile>
39 + <ClCompile Include="MemUtilTest.cpp">
40 + <Filter>Source Files</Filter>
41 + </ClCompile>
42 + <ClCompile Include="MonUtilTest.cpp">
43 + <Filter>Source Files</Filter>
44 + </ClCompile>
45 + <ClCompile Include="PathUtilTest.cpp">
46 + <Filter>Source Files</Filter>
47 + </ClCompile>
48 + <ClCompile Include="StrUtilTest.cpp">
49 + <Filter>Source Files</Filter>
50 + </ClCompile>
51 + <ClCompile Include="UriUtilTest.cpp">
52 + <Filter>Source Files</Filter>
53 + </ClCompile>
54 + <ClCompile Include="VarHelpers.cpp">
55 + <Filter>Source Files</Filter>
56 + </ClCompile>
57 + <ClCompile Include="VarUtilTest.cpp">
58 + <Filter>Source Files</Filter>
59 + </ClCompile>
60 + </ItemGroup>
61 + <ItemGroup>
62 + <ResourceCompile Include="UnitTest.rc">
63 + <Filter>Resource Files</Filter>
64 + </ResourceCompile>
65 + </ItemGroup>
66 + <ItemGroup>
67 + <ClInclude Include="precomp.h">
68 + <Filter>Header Files</Filter>
69 + </ClInclude>
70 + <ClInclude Include="error.h">
71 + <Filter>Header Files</Filter>
72 + </ClInclude>
73 + <ClInclude Include="VarHelpers.h">
74 + <Filter>Header Files</Filter>
75 + </ClInclude>
76 + </ItemGroup>
77 +</Project>
\ No newline at end of file
src/test/DUtilUnitTest/DictUtilTest.cpp new
+187
@@ -0,0 +1,187 @@
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;
6 +using namespace Xunit;
7 +using namespace WixTest;
8 +
9 +const DWORD numIterations = 100000;
10 +
11 +namespace DutilTests
12 +{
13 + struct Value
14 + {
15 + DWORD dwNum;
16 + LPWSTR sczKey;
17 + };
18 +
19 + public ref class DictUtil
20 + {
21 + public:
22 + [Fact]
23 + void DictUtilTest()
24 + {
25 + EmbeddedKeyTestHelper(DICT_FLAG_NONE, numIterations);
26 +
27 + EmbeddedKeyTestHelper(DICT_FLAG_CASEINSENSITIVE, numIterations);
28 +
29 + StringListTestHelper(DICT_FLAG_NONE, numIterations);
30 +
31 + StringListTestHelper(DICT_FLAG_CASEINSENSITIVE, numIterations);
32 + }
33 +
34 + private:
35 + void EmbeddedKeyTestHelper(DICT_FLAG dfFlags, DWORD dwNumIterations)
36 + {
37 + HRESULT hr = S_OK;
38 + Value *rgValues = NULL;
39 + Value *valueFound = NULL;
40 + DWORD cValues = 0;
41 + LPWSTR sczExpectedKey = NULL;
42 + STRINGDICT_HANDLE sdValues = NULL;
43 +
44 + try
45 + {
46 + hr = DictCreateWithEmbeddedKey(&sdValues, 0, (void **)&rgValues, offsetof(Value, sczKey), dfFlags);
47 + NativeAssert::Succeeded(hr, "Failed to create dictionary of values");
48 +
49 + for (DWORD i = 0; i < dwNumIterations; ++i)
50 + {
51 + cValues++;
52 +
53 + hr = MemEnsureArraySize((void **)&rgValues, cValues, sizeof(Value), 5);
54 + NativeAssert::Succeeded(hr, "Failed to grow value array");
55 +
56 + hr = StrAllocFormatted(&rgValues[i].sczKey, L"%u_a_%u", i, i);
57 + NativeAssert::Succeeded(hr, "Failed to allocate key for value {0}", i);
58 +
59 + hr = DictAddValue(sdValues, rgValues + i);
60 + NativeAssert::Succeeded(hr, "Failed to add item {0} to dict", i);
61 + }
62 +
63 + for (DWORD i = 0; i < dwNumIterations; ++i)
64 + {
65 + hr = StrAllocFormatted(&sczExpectedKey, L"%u_a_%u", i, i);
66 + NativeAssert::Succeeded(hr, "Failed to allocate expected key {0}", i);
67 +
68 + hr = DictGetValue(sdValues, sczExpectedKey, (void **)&valueFound);
69 + NativeAssert::Succeeded(hr, "Failed to find value {0}", sczExpectedKey);
70 +
71 + NativeAssert::StringEqual(sczExpectedKey, valueFound->sczKey);
72 +
73 + hr = StrAllocFormatted(&sczExpectedKey, L"%u_A_%u", i, i);
74 + NativeAssert::Succeeded(hr, "Failed to allocate uppercase expected key {0}", i);
75 +
76 + hr = DictGetValue(sdValues, sczExpectedKey, (void **)&valueFound);
77 +
78 + if (dfFlags & DICT_FLAG_CASEINSENSITIVE)
79 + {
80 + NativeAssert::Succeeded(hr, "Failed to find value {0}", sczExpectedKey);
81 +
82 + NativeAssert::StringEqual(sczExpectedKey, valueFound->sczKey, TRUE);
83 + }
84 + else
85 + {
86 + if (E_NOTFOUND != hr)
87 + {
88 + hr = E_FAIL;
89 + ExitOnFailure(hr, "This embedded key is case sensitive, but it seemed to have found something case using case insensitivity!: %ls", sczExpectedKey);
90 + }
91 + }
92 +
93 + hr = StrAllocFormatted(&sczExpectedKey, L"%u_b_%u", i, i);
94 + NativeAssert::Succeeded(hr, "Failed to allocate unexpected key {0}", i);
95 +
96 + hr = DictGetValue(sdValues, sczExpectedKey, (void **)&valueFound);
97 + if (E_NOTFOUND != hr)
98 + {
99 + hr = E_FAIL;
100 + ExitOnFailure(hr, "Item shouldn't have been found in dictionary: %ls", sczExpectedKey);
101 + }
102 + }
103 + }
104 + finally
105 + {
106 + for (DWORD i = 0; i < cValues; ++i)
107 + {
108 + ReleaseStr(rgValues[i].sczKey);
109 + }
110 + ReleaseMem(rgValues);
111 + ReleaseStr(sczExpectedKey);
112 + ReleaseDict(sdValues);
113 + }
114 +
115 + LExit:
116 + return;
117 + }
118 +
119 + void StringListTestHelper(DICT_FLAG dfFlags, DWORD dwNumIterations)
120 + {
121 + HRESULT hr = S_OK;
122 + LPWSTR sczKey = NULL;
123 + LPWSTR sczExpectedKey = NULL;
124 + STRINGDICT_HANDLE sdValues = NULL;
125 +
126 + try
127 + {
128 + hr = DictCreateStringList(&sdValues, 0, dfFlags);
129 + NativeAssert::Succeeded(hr, "Failed to create dictionary of keys");
130 +
131 + for (DWORD i = 0; i < dwNumIterations; ++i)
132 + {
133 + hr = StrAllocFormatted(&sczKey, L"%u_a_%u", i, i);
134 + NativeAssert::Succeeded(hr, "Failed to allocate key for value {0}", i);
135 +
136 + hr = DictAddKey(sdValues, sczKey);
137 + NativeAssert::Succeeded(hr, "Failed to add key {0} to dict", i);
138 + }
139 +
140 + for (DWORD i = 0; i < dwNumIterations; ++i)
141 + {
142 + hr = StrAllocFormatted(&sczExpectedKey, L"%u_a_%u", i, i);
143 + NativeAssert::Succeeded(hr, "Failed to allocate expected key {0}", i);
144 +
145 + hr = DictKeyExists(sdValues, sczExpectedKey);
146 + NativeAssert::Succeeded(hr, "Failed to find value {0}", sczExpectedKey);
147 +
148 + hr = StrAllocFormatted(&sczExpectedKey, L"%u_A_%u", i, i);
149 + NativeAssert::Succeeded(hr, "Failed to allocate uppercase expected key {0}", i);
150 +
151 + hr = DictKeyExists(sdValues, sczExpectedKey);
152 + if (dfFlags & DICT_FLAG_CASEINSENSITIVE)
153 + {
154 + NativeAssert::Succeeded(hr, "Failed to find value {0}", sczExpectedKey);
155 + }
156 + else
157 + {
158 + if (E_NOTFOUND != hr)
159 + {
160 + hr = E_FAIL;
161 + ExitOnFailure(hr, "This stringlist dict is case sensitive, but it seemed to have found something case using case insensitivity!: %ls", sczExpectedKey);
162 + }
163 + }
164 +
165 + hr = StrAllocFormatted(&sczExpectedKey, L"%u_b_%u", i, i);
166 + NativeAssert::Succeeded(hr, "Failed to allocate unexpected key {0}", i);
167 +
168 + hr = DictKeyExists(sdValues, sczExpectedKey);
169 + if (E_NOTFOUND != hr)
170 + {
171 + hr = E_FAIL;
172 + ExitOnFailure(hr, "Item shouldn't have been found in dictionary: %ls", sczExpectedKey);
173 + }
174 + }
175 + }
176 + finally
177 + {
178 + ReleaseStr(sczKey);
179 + ReleaseStr(sczExpectedKey);
180 + ReleaseDict(sdValues);
181 + }
182 +
183 + LExit:
184 + return;
185 + }
186 + };
187 +}
src/test/DUtilUnitTest/DirUtilTests.cpp new
+70
@@ -0,0 +1,70 @@
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;
6 +using namespace Xunit;
7 +using namespace WixTest;
8 +
9 +namespace DutilTests
10 +{
11 + public ref class DirUtil
12 + {
13 + public:
14 + [Fact]
15 + void DirUtilTest()
16 + {
17 + HRESULT hr = S_OK;
18 + LPWSTR sczCurrentDir = NULL;
19 + LPWSTR sczGuid = NULL;
20 + LPWSTR sczFolder = NULL;
21 + LPWSTR sczSubFolder = NULL;
22 +
23 + try
24 + {
25 + hr = GuidCreate(&sczGuid);
26 + NativeAssert::Succeeded(hr, "Failed to create guid.");
27 +
28 + hr = DirGetCurrent(&sczCurrentDir);
29 + NativeAssert::Succeeded(hr, "Failed to get current directory.");
30 +
31 + hr = PathConcat(sczCurrentDir, sczGuid, &sczFolder);
32 + NativeAssert::Succeeded(hr, "Failed to combine current directory: '{0}' with Guid: '{1}'", sczCurrentDir, sczGuid);
33 +
34 + BOOL fExists = DirExists(sczFolder, NULL);
35 + Assert::False(fExists);
36 +
37 + hr = PathConcat(sczFolder, L"foo", &sczSubFolder);
38 + NativeAssert::Succeeded(hr, "Failed to combine folder: '%ls' with subfolder: 'foo'", sczFolder);
39 +
40 + hr = DirEnsureExists(sczSubFolder, NULL);
41 + NativeAssert::Succeeded(hr, "Failed to create multiple directories: %ls", sczSubFolder);
42 +
43 + // Test failure to delete non-empty folder.
44 + hr = DirEnsureDelete(sczFolder, FALSE, FALSE);
45 + Assert::Equal(HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY), hr);
46 +
47 + hr = DirEnsureDelete(sczSubFolder, FALSE, FALSE);
48 + NativeAssert::Succeeded(hr, "Failed to delete single directory: %ls", sczSubFolder);
49 +
50 + // Put the directory back and we'll test deleting tree.
51 + hr = DirEnsureExists(sczSubFolder, NULL);
52 + NativeAssert::Succeeded(hr, "Failed to create single directory: %ls", sczSubFolder);
53 +
54 + hr = DirEnsureDelete(sczFolder, FALSE, TRUE);
55 + NativeAssert::Succeeded(hr, "Failed to delete directory tree: %ls", sczFolder);
56 +
57 + // Finally, try to create "C:\" which would normally fail, but we want success
58 + hr = DirEnsureExists(L"C:\\", NULL);
59 + NativeAssert::Succeeded(hr, "Failed to create C:\\");
60 + }
61 + finally
62 + {
63 + ReleaseStr(sczSubFolder);
64 + ReleaseStr(sczFolder);
65 + ReleaseStr(sczGuid);
66 + ReleaseStr(sczCurrentDir);
67 + }
68 + }
69 + };
70 +}
src/test/DUtilUnitTest/FileUtilTest.cpp new
+118
@@ -0,0 +1,118 @@
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;
6 +using namespace Xunit;
7 +using namespace WixTest;
8 +
9 +namespace DutilTests
10 +{
11 + public ref class FileUtil
12 + {
13 + public:
14 + [Fact(Skip="Skipped until we have a good way to reference ANSI.txt.")]
15 + void FileUtilTest()
16 + {
17 + HRESULT hr = S_OK;
18 + LPWSTR sczTempDir = NULL;
19 + LPWSTR sczFileDir = NULL;
20 +
21 + try
22 + {
23 + hr = PathExpand(&sczTempDir, L"%TEMP%\\FileUtilTest\\", PATH_EXPAND_ENVIRONMENT);
24 + NativeAssert::Succeeded(hr, "Failed to get temp dir");
25 +
26 + hr = PathExpand(&sczFileDir, L"%WIX_ROOT%\\examples\\data\\TextEncodings\\", PATH_EXPAND_ENVIRONMENT);
27 + NativeAssert::Succeeded(hr, "Failed to get path to encodings file dir");
28 +
29 + hr = DirEnsureExists(sczTempDir, NULL);
30 + NativeAssert::Succeeded(hr, "Failed to ensure directory exists: {0}", sczTempDir);
31 +
32 + TestFile(sczFileDir, sczTempDir, L"ANSI.txt", 32, FILE_ENCODING_UTF8);
33 + // Big endian not supported today!
34 + //TestFile(sczFileDir, L"UnicodeBENoBOM.txt", 34);
35 + //TestFile(sczFileDir, L"UnicodeBEWithBOM.txt", 34);
36 + TestFile(sczFileDir, sczTempDir, L"UnicodeLENoBOM.txt", 34, FILE_ENCODING_UTF16);
37 + TestFile(sczFileDir, sczTempDir, L"UnicodeLEWithBOM.txt", 34, FILE_ENCODING_UTF16_WITH_BOM);
38 + TestFile(sczFileDir, sczTempDir, L"UTF8WithSignature.txt", 34, FILE_ENCODING_UTF8_WITH_BOM);
39 +
40 + hr = DirEnsureDelete(sczTempDir, TRUE, TRUE);
41 + }
42 + finally
43 + {
44 + ReleaseStr(sczTempDir);
45 + ReleaseStr(sczFileDir);
46 + }
47 + }
48 +
49 + private:
50 + void TestFile(LPWSTR wzDir, LPCWSTR wzTempDir, LPWSTR wzFileName, DWORD dwExpectedStringLength, FILE_ENCODING feExpectedEncoding)
51 + {
52 + HRESULT hr = S_OK;
53 + LPWSTR sczFullPath = NULL;
54 + LPWSTR sczContents = NULL;
55 + LPWSTR sczOutputPath = NULL;
56 + FILE_ENCODING feEncodingFound = FILE_ENCODING_UNSPECIFIED;
57 + BYTE *pbFile1 = NULL;
58 + DWORD cbFile1 = 0;
59 + BYTE *pbFile2 = NULL;
60 + DWORD cbFile2 = 0;
61 +
62 + try
63 + {
64 + hr = PathConcat(wzDir, wzFileName, &sczFullPath);
65 + NativeAssert::Succeeded(hr, "Failed to create path to test file: {0}", sczFullPath);
66 +
67 + hr = FileToString(sczFullPath, &sczContents, &feEncodingFound);
68 + hr = E_FAIL;
69 + NativeAssert::Succeeded(hr, "Failed to read text from file: {0}", sczFullPath);
70 +
71 + if (!sczContents)
72 + {
73 + hr = E_FAIL;
74 + NativeAssert::Succeeded(hr, "FileToString() returned NULL for file: {0}", sczFullPath);
75 + }
76 +
77 + if ((DWORD)lstrlenW(sczContents) != dwExpectedStringLength)
78 + {
79 + hr = E_FAIL;
80 + ExitOnFailure(hr, "FileToString() returned wrong size for file: %ls (expected size %u, found size %u)", sczFullPath, dwExpectedStringLength, lstrlenW(sczContents));
81 + }
82 +
83 + if (feEncodingFound != feExpectedEncoding)
84 + {
85 + hr = E_FAIL;
86 + ExitOnFailure(hr, "FileToString() returned unexpected encoding type for file: %ls (expected type %u, found type %u)", sczFullPath, feExpectedEncoding, feEncodingFound);
87 + }
88 +
89 + hr = PathConcat(wzTempDir, wzFileName, &sczOutputPath);
90 + NativeAssert::Succeeded(hr, "Failed to get output path");
91 +
92 + hr = FileFromString(sczOutputPath, 0, sczContents, feExpectedEncoding);
93 + NativeAssert::Succeeded(hr, "Failed to write contents of file back out to disk");
94 +
95 + hr = FileRead(&pbFile1, &cbFile1, sczFullPath);
96 + NativeAssert::Succeeded(hr, "Failed to read input file as binary");
97 +
98 + hr = FileRead(&pbFile2, &cbFile2, sczOutputPath);
99 + NativeAssert::Succeeded(hr, "Failed to read output file as binary");
100 +
101 + if (cbFile1 != cbFile2 || 0 != memcmp(pbFile1, pbFile2, cbFile1))
102 + {
103 + hr = E_FAIL;
104 + ExitOnFailure(hr, "Outputted file doesn't match input file: \"%ls\" and \"%ls\"", sczFullPath, sczOutputPath);
105 + }
106 + }
107 + finally
108 + {
109 + ReleaseStr(sczOutputPath);
110 + ReleaseStr(sczFullPath);
111 + ReleaseStr(sczContents);
112 + }
113 +
114 + LExit:
115 + return;
116 + }
117 + };
118 +}
src/test/DUtilUnitTest/GuidUtilTest.cpp new
+60
@@ -0,0 +1,60 @@
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;
6 +using namespace Xunit;
7 +using namespace WixTest;
8 +
9 +namespace DutilTests
10 +{
11 + public ref class GuidUtil
12 + {
13 + public:
14 + [Fact]
15 + void GuidCreateTest()
16 + {
17 + HRESULT hr = S_OK;
18 + WCHAR wzGuid1[GUID_STRING_LENGTH];
19 + WCHAR wzGuid2[GUID_STRING_LENGTH];
20 +
21 + hr = GuidFixedCreate(wzGuid1);
22 + NativeAssert::Succeeded(hr, "Failed to create first guid.");
23 + Guid firstGuid = Guid::Parse(gcnew String(wzGuid1));
24 +
25 + hr = GuidFixedCreate(wzGuid2);
26 + NativeAssert::Succeeded(hr, "Failed to create second guid.");
27 + Guid secondGuid = Guid::Parse(gcnew String(wzGuid2));
28 +
29 + NativeAssert::NotStringEqual(wzGuid1, wzGuid2);
30 + NativeAssert::NotEqual(firstGuid, secondGuid);
31 + }
32 +
33 + [Fact]
34 + void GuidCreateSczTest()
35 + {
36 + HRESULT hr = S_OK;
37 + LPWSTR sczGuid1 = NULL;
38 + LPWSTR sczGuid2 = NULL;
39 +
40 + try
41 + {
42 + hr = GuidCreate(&sczGuid1);
43 + NativeAssert::Succeeded(hr, "Failed to create first guid.");
44 + Guid firstGuid = Guid::Parse(gcnew String(sczGuid1));
45 +
46 + hr = GuidCreate(&sczGuid2);
47 + NativeAssert::Succeeded(hr, "Failed to create second guid.");
48 + Guid secondGuid = Guid::Parse(gcnew String(sczGuid2));
49 +
50 + NativeAssert::NotStringEqual(sczGuid1, sczGuid2);
51 + NativeAssert::NotEqual(firstGuid, secondGuid);
52 + }
53 + finally
54 + {
55 + ReleaseStr(sczGuid1);
56 + ReleaseStr(sczGuid2);
57 + }
58 + }
59 + };
60 +}
src/test/DUtilUnitTest/IniUtilTest.cpp new
+342
@@ -0,0 +1,342 @@
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;
6 +using namespace Xunit;
7 +using namespace WixTest;
8 +
9 +typedef HRESULT (__clrcall *IniFormatParameters)(
10 + INI_HANDLE
11 + );
12 +
13 +namespace DutilTests
14 +{
15 + public ref class IniUtil
16 + {
17 + public:
18 + [Fact]
19 + void IniUtilTest()
20 + {
21 + HRESULT hr = S_OK;
22 + LPWSTR sczTempIniFilePath = NULL;
23 + LPWSTR sczTempIniFileDir = NULL;
24 + LPWSTR wzIniContents = L" PlainValue = \t Blah \r\n;CommentHere\r\n[Section1]\r\n ;Another Comment With = Equal Sign\r\nSection1ValueA=Foo\r\n\r\nSection1ValueB=Bar\r\n[Section2]\r\nSection2ValueA=Cha\r\nArray[0]=Arr\r\n";
25 + LPWSTR wzScriptContents = L"setf ~PlainValue Blah\r\n;CommentHere\r\n\r\nsetf ~Section1\\Section1ValueA Foo\r\n\r\nsetf ~Section1\\Section1ValueB Bar\r\nsetf ~Section2\\Section2ValueA Cha\r\nsetf ~Section2\\Array[0] Arr\r\n";
26 +
27 + try
28 + {
29 + hr = PathExpand(&sczTempIniFilePath, L"%TEMP%\\IniUtilTest\\Test.ini", PATH_EXPAND_ENVIRONMENT);
30 + NativeAssert::Succeeded(hr, "Failed to get path to temp INI file");
31 +
32 + hr = PathGetDirectory(sczTempIniFilePath, &sczTempIniFileDir);
33 + NativeAssert::Succeeded(hr, "Failed to get directory to temp INI file");
34 +
35 + hr = DirEnsureDelete(sczTempIniFileDir, TRUE, TRUE);
36 + if (E_PATHNOTFOUND == hr)
37 + {
38 + hr = S_OK;
39 + }
40 + NativeAssert::Succeeded(hr, "Failed to delete IniUtilTest directory: {0}", sczTempIniFileDir);
41 +
42 + hr = DirEnsureExists(sczTempIniFileDir, NULL);
43 + NativeAssert::Succeeded(hr, "Failed to ensure temp directory exists: {0}", sczTempIniFileDir);
44 +
45 + // Tests parsing, then modifying a regular INI file
46 + TestReadThenWrite(sczTempIniFilePath, StandardIniFormat, wzIniContents);
47 +
48 + // Tests programmatically creating from scratch, then parsing an INI file
49 + TestWriteThenRead(sczTempIniFilePath, StandardIniFormat);
50 +
51 + // Tests parsing, then modifying a regular INI file
52 + TestReadThenWrite(sczTempIniFilePath, ScriptFormat, wzScriptContents);
53 +
54 + // Tests programmatically creating from scratch, then parsing an INI file
55 + TestWriteThenRead(sczTempIniFilePath, ScriptFormat);
56 + }
57 + finally
58 + {
59 + ReleaseStr(sczTempIniFilePath);
60 + ReleaseStr(sczTempIniFileDir);
61 + }
62 + }
63 +
64 + private:
65 + void AssertValue(INI_HANDLE iniHandle, LPCWSTR wzValueName, LPCWSTR wzValue)
66 + {
67 + HRESULT hr = S_OK;
68 + LPWSTR sczValue = NULL;
69 +
70 + try
71 + {
72 + hr = IniGetValue(iniHandle, wzValueName, &sczValue);
73 + NativeAssert::Succeeded(hr, "Failed to get ini value: {0}", wzValueName);
74 +
75 + if (0 != wcscmp(sczValue, wzValue))
76 + {
77 + hr = E_FAIL;
78 + ExitOnFailure(hr, "Expected to find value in INI: '%ls'='%ls' - but found value '%ls' instead", wzValueName, wzValue, sczValue);
79 + }
80 + }
81 + finally
82 + {
83 + ReleaseStr(sczValue);
84 + }
85 +
86 + LExit:
87 + return;
88 + }
89 +
90 + void AssertNoValue(INI_HANDLE iniHandle, LPCWSTR wzValueName)
91 + {
92 + HRESULT hr = S_OK;
93 + LPWSTR sczValue = NULL;
94 +
95 + try
96 + {
97 + hr = IniGetValue(iniHandle, wzValueName, &sczValue);
98 + if (E_NOTFOUND != hr)
99 + {
100 + if (SUCCEEDED(hr))
101 + {
102 + hr = E_FAIL;
103 + }
104 + ExitOnFailure(hr, "INI value shouldn't have been found: %ls", wzValueName);
105 + }
106 + }
107 + finally
108 + {
109 + ReleaseStr(sczValue);
110 + }
111 +
112 + LExit:
113 + return;
114 + }
115 +
116 + static HRESULT StandardIniFormat(__inout INI_HANDLE iniHandle)
117 + {
118 + HRESULT hr = S_OK;
119 +
120 + hr = IniSetOpenTag(iniHandle, L"[", L"]");
121 + NativeAssert::Succeeded(hr, "Failed to set open tag settings on ini handle");
122 +
123 + hr = IniSetValueStyle(iniHandle, NULL, L"=");
124 + NativeAssert::Succeeded(hr, "Failed to set value separator setting on ini handle");
125 +
126 + hr = IniSetCommentStyle(iniHandle, L";");
127 + NativeAssert::Succeeded(hr, "Failed to set comment style setting on ini handle");
128 +
129 + return hr;
130 + }
131 +
132 + static HRESULT ScriptFormat(__inout INI_HANDLE iniHandle)
133 + {
134 + HRESULT hr = S_OK;
135 +
136 + hr = IniSetValueStyle(iniHandle, L"setf ~", L" ");
137 + NativeAssert::Succeeded(hr, "Failed to set value separator setting on ini handle");
138 +
139 + return hr;
140 + }
141 +
142 + void TestReadThenWrite(LPWSTR wzIniFilePath, IniFormatParameters SetFormat, LPCWSTR wzContents)
143 + {
144 + HRESULT hr = S_OK;
145 + INI_HANDLE iniHandle = NULL;
146 + INI_HANDLE iniHandle2 = NULL;
147 + INI_VALUE *rgValues = NULL;
148 + DWORD cValues = 0;
149 +
150 + try
151 + {
152 + hr = FileWrite(wzIniFilePath, 0, reinterpret_cast<LPCBYTE>(wzContents), lstrlenW(wzContents) * sizeof(WCHAR), NULL);
153 + NativeAssert::Succeeded(hr, "Failed to write out INI file");
154 +
155 + hr = IniInitialize(&iniHandle);
156 + NativeAssert::Succeeded(hr, "Failed to initialize INI object");
157 +
158 + hr = SetFormat(iniHandle);
159 + NativeAssert::Succeeded(hr, "Failed to set parameters for INI file");
160 +
161 + hr = IniParse(iniHandle, wzIniFilePath, NULL);
162 + NativeAssert::Succeeded(hr, "Failed to parse INI file");
163 +
164 + hr = IniGetValueList(iniHandle, &rgValues, &cValues);
165 + NativeAssert::Succeeded(hr, "Failed to get list of values in INI");
166 +
167 + NativeAssert::Equal<DWORD>(5, cValues);
168 +
169 + AssertValue(iniHandle, L"PlainValue", L"Blah");
170 + AssertNoValue(iniHandle, L"PlainValue2");
171 + AssertValue(iniHandle, L"Section1\\Section1ValueA", L"Foo");
172 + AssertValue(iniHandle, L"Section1\\Section1ValueB", L"Bar");
173 + AssertValue(iniHandle, L"Section2\\Section2ValueA", L"Cha");
174 + AssertNoValue(iniHandle, L"Section1\\ValueDoesntExist");
175 + AssertValue(iniHandle, L"Section2\\Array[0]", L"Arr");
176 +
177 + hr = IniSetValue(iniHandle, L"PlainValue2", L"Blah2");
178 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
179 +
180 + hr = IniSetValue(iniHandle, L"Section1\\CreatedValue", L"Woo");
181 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
182 +
183 + hr = IniSetValue(iniHandle, L"Section2\\Array[0]", L"Arrmod");
184 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
185 +
186 + hr = IniGetValueList(iniHandle, &rgValues, &cValues);
187 + NativeAssert::Succeeded(hr, "Failed to get list of values in INI");
188 +
189 + NativeAssert::Equal<DWORD>(7, cValues);
190 +
191 + AssertValue(iniHandle, L"PlainValue", L"Blah");
192 + AssertValue(iniHandle, L"PlainValue2", L"Blah2");
193 + AssertValue(iniHandle, L"Section1\\Section1ValueA", L"Foo");
194 + AssertValue(iniHandle, L"Section1\\Section1ValueB", L"Bar");
195 + AssertValue(iniHandle, L"Section2\\Section2ValueA", L"Cha");
196 + AssertNoValue(iniHandle, L"Section1\\ValueDoesntExist");
197 + AssertValue(iniHandle, L"Section1\\CreatedValue", L"Woo");
198 + AssertValue(iniHandle, L"Section2\\Array[0]", L"Arrmod");
199 +
200 + // Try deleting a value as well
201 + hr = IniSetValue(iniHandle, L"Section1\\Section1ValueB", NULL);
202 + NativeAssert::Succeeded(hr, "Failed to kill value in INI");
203 +
204 + hr = IniWriteFile(iniHandle, NULL, FILE_ENCODING_UNSPECIFIED);
205 + NativeAssert::Succeeded(hr, "Failed to write ini file back out to disk");
206 +
207 + ReleaseNullIni(iniHandle);
208 + // Now re-parse the INI we just wrote and make sure it matches the values we expect
209 + hr = IniInitialize(&iniHandle2);
210 + NativeAssert::Succeeded(hr, "Failed to initialize INI object");
211 +
212 + hr = SetFormat(iniHandle2);
213 + NativeAssert::Succeeded(hr, "Failed to set parameters for INI file");
214 +
215 + hr = IniParse(iniHandle2, wzIniFilePath, NULL);
216 + NativeAssert::Succeeded(hr, "Failed to parse INI file");
217 +
218 + hr = IniGetValueList(iniHandle2, &rgValues, &cValues);
219 + NativeAssert::Succeeded(hr, "Failed to get list of values in INI");
220 +
221 + NativeAssert::Equal<DWORD>(6, cValues);
222 +
223 + AssertValue(iniHandle2, L"PlainValue", L"Blah");
224 + AssertValue(iniHandle2, L"PlainValue2", L"Blah2");
225 + AssertValue(iniHandle2, L"Section1\\Section1ValueA", L"Foo");
226 + AssertNoValue(iniHandle2, L"Section1\\Section1ValueB");
227 + AssertValue(iniHandle2, L"Section2\\Section2ValueA", L"Cha");
228 + AssertNoValue(iniHandle2, L"Section1\\ValueDoesntExist");
229 + AssertValue(iniHandle2, L"Section1\\CreatedValue", L"Woo");
230 + AssertValue(iniHandle2, L"Section2\\Array[0]", L"Arrmod");
231 + }
232 + finally
233 + {
234 + ReleaseIni(iniHandle);
235 + ReleaseIni(iniHandle2);
236 + }
237 + }
238 +
239 + void TestWriteThenRead(LPWSTR wzIniFilePath, IniFormatParameters SetFormat)
240 + {
241 + HRESULT hr = S_OK;
242 + INI_HANDLE iniHandle = NULL;
243 + INI_HANDLE iniHandle2 = NULL;
244 + INI_VALUE *rgValues = NULL;
245 + DWORD cValues = 0;
246 +
247 + try
248 + {
249 + hr = FileEnsureDelete(wzIniFilePath);
250 + NativeAssert::Succeeded(hr, "Failed to ensure file is deleted");
251 +
252 + hr = IniInitialize(&iniHandle);
253 + NativeAssert::Succeeded(hr, "Failed to initialize INI object");
254 +
255 + hr = SetFormat(iniHandle);
256 + NativeAssert::Succeeded(hr, "Failed to set parameters for INI file");
257 +
258 + hr = IniGetValueList(iniHandle, &rgValues, &cValues);
259 + NativeAssert::Succeeded(hr, "Failed to get list of values in INI");
260 +
261 + NativeAssert::Equal<DWORD>(0, cValues);
262 +
263 + hr = IniSetValue(iniHandle, L"Value1", L"BlahTypo");
264 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
265 +
266 + hr = IniSetValue(iniHandle, L"Value2", L"Blah2");
267 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
268 +
269 + hr = IniSetValue(iniHandle, L"Section1\\Value1", L"Section1Value1");
270 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
271 +
272 + hr = IniSetValue(iniHandle, L"Section1\\Value2", L"Section1Value2");
273 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
274 +
275 + hr = IniSetValue(iniHandle, L"Section2\\Value1", L"Section2Value1");
276 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
277 +
278 + hr = IniSetValue(iniHandle, L"Section2\\Array[0]", L"Arr");
279 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
280 +
281 + hr = IniSetValue(iniHandle, L"Value3", L"Blah3");
282 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
283 +
284 + hr = IniSetValue(iniHandle, L"Value4", L"Blah4");
285 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
286 +
287 + hr = IniSetValue(iniHandle, L"Value4", NULL);
288 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
289 +
290 + hr = IniSetValue(iniHandle, L"Value1", L"Blah1");
291 + NativeAssert::Succeeded(hr, "Failed to set value in INI");
292 +
293 + hr = IniGetValueList(iniHandle, &rgValues, &cValues);
294 + NativeAssert::Succeeded(hr, "Failed to get list of values in INI");
295 +
296 + NativeAssert::Equal<DWORD>(8, cValues);
297 +
298 + AssertValue(iniHandle, L"Value1", L"Blah1");
299 + AssertValue(iniHandle, L"Value2", L"Blah2");
300 + AssertValue(iniHandle, L"Value3", L"Blah3");
301 + AssertNoValue(iniHandle, L"Value4");
302 + AssertValue(iniHandle, L"Section1\\Value1", L"Section1Value1");
303 + AssertValue(iniHandle, L"Section1\\Value2", L"Section1Value2");
304 + AssertValue(iniHandle, L"Section2\\Value1", L"Section2Value1");
305 + AssertValue(iniHandle, L"Section2\\Array[0]", L"Arr");
306 +
307 + hr = IniWriteFile(iniHandle, wzIniFilePath, FILE_ENCODING_UNSPECIFIED);
308 + NativeAssert::Succeeded(hr, "Failed to write ini file back out to disk");
309 +
310 + ReleaseNullIni(iniHandle);
311 + // Now re-parse the INI we just wrote and make sure it matches the values we expect
312 + hr = IniInitialize(&iniHandle2);
313 + NativeAssert::Succeeded(hr, "Failed to initialize INI object");
314 +
315 + hr = SetFormat(iniHandle2);
316 + NativeAssert::Succeeded(hr, "Failed to set parameters for INI file");
317 +
318 + hr = IniParse(iniHandle2, wzIniFilePath, NULL);
319 + NativeAssert::Succeeded(hr, "Failed to parse INI file");
320 +
321 + hr = IniGetValueList(iniHandle2, &rgValues, &cValues);
322 + NativeAssert::Succeeded(hr, "Failed to get list of values in INI");
323 +
324 + NativeAssert::Equal<DWORD>(7, cValues);
325 +
326 + AssertValue(iniHandle2, L"Value1", L"Blah1");
327 + AssertValue(iniHandle2, L"Value2", L"Blah2");
328 + AssertValue(iniHandle2, L"Value3", L"Blah3");
329 + AssertNoValue(iniHandle2, L"Value4");
330 + AssertValue(iniHandle2, L"Section1\\Value1", L"Section1Value1");
331 + AssertValue(iniHandle2, L"Section1\\Value2", L"Section1Value2");
332 + AssertValue(iniHandle2, L"Section2\\Value1", L"Section2Value1");
333 + AssertValue(iniHandle2, L"Section2\\Array[0]", L"Arr");
334 + }
335 + finally
336 + {
337 + ReleaseIni(iniHandle);
338 + ReleaseIni(iniHandle2);
339 + }
340 + }
341 + };
342 +}
src/test/DUtilUnitTest/MemUtilTest.cpp new
+491
@@ -0,0 +1,491 @@
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;
6 +using namespace Xunit;
7 +using namespace WixTest;
8 +
9 +namespace DutilTests
10 +{
11 + struct ArrayValue
12 + {
13 + DWORD dwNum;
14 + void *pvNull1;
15 + LPWSTR sczString;
16 + void *pvNull2;
17 + };
18 +
19 + public ref class MemUtil
20 + {
21 + public:
22 + [Fact]
23 + void MemUtilAppendTest()
24 + {
25 + HRESULT hr = S_OK;
26 + DWORD dwSize;
27 + ArrayValue *rgValues = NULL;
28 + DWORD cValues = 0;
29 +
30 + try
31 + {
32 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues + 1, sizeof(ArrayValue), 5);
33 + NativeAssert::Succeeded(hr, "Failed to grow array size to 1");
34 + ++cValues;
35 + SetItem(rgValues + 0, 0);
36 +
37 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues + 1, sizeof(ArrayValue), 5);
38 + NativeAssert::Succeeded(hr, "Failed to grow array size to 2");
39 + ++cValues;
40 + SetItem(rgValues + 1, 1);
41 +
42 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues + 1, sizeof(ArrayValue), 5);
43 + NativeAssert::Succeeded(hr, "Failed to grow array size to 3");
44 + ++cValues;
45 + SetItem(rgValues + 2, 2);
46 +
47 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues + 1, sizeof(ArrayValue), 5);
48 + NativeAssert::Succeeded(hr, "Failed to grow array size to 4");
49 + ++cValues;
50 + SetItem(rgValues + 3, 3);
51 +
52 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues + 1, sizeof(ArrayValue), 5);
53 + NativeAssert::Succeeded(hr, "Failed to grow array size to 5");
54 + ++cValues;
55 + SetItem(rgValues + 4, 4);
56 +
57 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues + 1, sizeof(ArrayValue), 5);
58 + NativeAssert::Succeeded(hr, "Failed to grow array size to 6");
59 + ++cValues;
60 + SetItem(rgValues + 5, 5);
61 +
62 + // OK, we used growth size 5, so let's try ensuring we have space for 6 (5 + first item) items
63 + // and make sure it doesn't grow since we already have enough space
64 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues, sizeof(ArrayValue), 5);
65 + NativeAssert::Succeeded(hr, "Failed to ensure array size matches what it should already be");
66 + dwSize = MemSize(rgValues);
67 + if (dwSize != 6 * sizeof(ArrayValue))
68 + {
69 + hr = E_FAIL;
70 + ExitOnFailure(hr, "MemEnsureArraySize is growing an array that is already big enough!");
71 + }
72 +
73 + for (DWORD i = 0; i < cValues; ++i)
74 + {
75 + CheckItem(rgValues + i, i);
76 + }
77 +
78 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues + 1, sizeof(ArrayValue), 5);
79 + NativeAssert::Succeeded(hr, "Failed to grow array size to 7");
80 + ++cValues;
81 + SetItem(rgValues + 6, 6);
82 +
83 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues + 1, sizeof(ArrayValue), 5);
84 + NativeAssert::Succeeded(hr, "Failed to grow array size to 7");
85 + ++cValues;
86 + SetItem(rgValues + 7, 7);
87 +
88 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues + 1, sizeof(ArrayValue), 5);
89 + NativeAssert::Succeeded(hr, "Failed to grow array size to 7");
90 + ++cValues;
91 + SetItem(rgValues + 8, 8);
92 +
93 + for (DWORD i = 0; i < cValues; ++i)
94 + {
95 + CheckItem(rgValues + i, i);
96 + }
97 + }
98 + finally
99 + {
100 + ReleaseMem(rgValues);
101 + }
102 +
103 + LExit:
104 + return;
105 + }
106 +
107 + [Fact]
108 + void MemUtilInsertTest()
109 + {
110 + HRESULT hr = S_OK;
111 + ArrayValue *rgValues = NULL;
112 + DWORD cValues = 0;
113 +
114 + try
115 + {
116 + hr = MemInsertIntoArray(reinterpret_cast<LPVOID*>(&rgValues), 0, 1, cValues + 1, sizeof(ArrayValue), 5);
117 + NativeAssert::Succeeded(hr, "Failed to insert into beginning of empty array");
118 + ++cValues;
119 + CheckNullItem(rgValues + 0);
120 + SetItem(rgValues + 0, 5);
121 +
122 + hr = MemInsertIntoArray(reinterpret_cast<LPVOID*>(&rgValues), 1, 1, cValues + 1, sizeof(ArrayValue), 5);
123 + NativeAssert::Succeeded(hr, "Failed to insert at end of array");
124 + ++cValues;
125 + CheckNullItem(rgValues + 1);
126 + SetItem(rgValues + 1, 6);
127 +
128 + hr = MemInsertIntoArray(reinterpret_cast<LPVOID*>(&rgValues), 0, 1, cValues + 1, sizeof(ArrayValue), 5);
129 + NativeAssert::Succeeded(hr, "Failed to insert into beginning of array");
130 + ++cValues;
131 + CheckNullItem(rgValues + 0);
132 + SetItem(rgValues + 0, 4);
133 +
134 + hr = MemInsertIntoArray(reinterpret_cast<LPVOID*>(&rgValues), 0, 1, cValues + 1, sizeof(ArrayValue), 5);
135 + NativeAssert::Succeeded(hr, "Failed to insert into beginning of array");
136 + ++cValues;
137 + CheckNullItem(rgValues + 0);
138 + SetItem(rgValues + 0, 3);
139 +
140 + hr = MemInsertIntoArray(reinterpret_cast<LPVOID*>(&rgValues), 0, 1, cValues + 1, sizeof(ArrayValue), 5);
141 + NativeAssert::Succeeded(hr, "Failed to insert into beginning of array");
142 + ++cValues;
143 + CheckNullItem(rgValues + 0);
144 + SetItem(rgValues + 0, 1);
145 +
146 + hr = MemInsertIntoArray(reinterpret_cast<LPVOID*>(&rgValues), 1, 1, cValues + 1, sizeof(ArrayValue), 5);
147 + NativeAssert::Succeeded(hr, "Failed to insert into beginning of array");
148 + ++cValues;
149 + CheckNullItem(rgValues + 1);
150 + SetItem(rgValues + 1, 2);
151 +
152 + hr = MemInsertIntoArray(reinterpret_cast<LPVOID*>(&rgValues), 0, 1, cValues + 1, sizeof(ArrayValue), 5);
153 + NativeAssert::Succeeded(hr, "Failed to insert into beginning of array");
154 + ++cValues;
155 + CheckNullItem(rgValues + 0);
156 + SetItem(rgValues + 0, 0);
157 +
158 + for (DWORD i = 0; i < cValues; ++i)
159 + {
160 + CheckItem(rgValues + i, i);
161 + }
162 +
163 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), cValues + 1, sizeof(ArrayValue), 5);
164 + NativeAssert::Succeeded(hr, "Failed to grow array size to 7");
165 + ++cValues;
166 + CheckNullItem(rgValues + 7);
167 + SetItem(rgValues + 7, 7);
168 +
169 + hr = MemInsertIntoArray(reinterpret_cast<LPVOID*>(&rgValues), 8, 1, cValues + 1, sizeof(ArrayValue), 5);
170 + NativeAssert::Succeeded(hr, "Failed to insert into beginning of array");
171 + ++cValues;
172 + CheckNullItem(rgValues + 8);
173 + SetItem(rgValues + 8, 8);
174 +
175 + for (DWORD i = 0; i < cValues; ++i)
176 + {
177 + CheckItem(rgValues + i, i);
178 + }
179 + }
180 + finally
181 + {
182 + ReleaseMem(rgValues);
183 + }
184 + }
185 +
186 + [Fact]
187 + void MemUtilRemovePreserveOrderTest()
188 + {
189 + HRESULT hr = S_OK;
190 + ArrayValue *rgValues = NULL;
191 + DWORD cValues = 0;
192 +
193 + try
194 + {
195 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), 10, sizeof(ArrayValue), 10);
196 + NativeAssert::Succeeded(hr, "Failed to grow array size to 10");
197 +
198 + cValues = 10;
199 + for (DWORD i = 0; i < cValues; ++i)
200 + {
201 + SetItem(rgValues + i, i);
202 + }
203 +
204 + // Remove last item
205 + MemRemoveFromArray(rgValues, 9, 1, cValues, sizeof(ArrayValue), TRUE);
206 + --cValues;
207 +
208 + for (DWORD i = 0; i < cValues; ++i)
209 + {
210 + CheckItem(rgValues + i, i);
211 + }
212 +
213 + // Remove last two items
214 + MemRemoveFromArray(rgValues, 7, 2, cValues, sizeof(ArrayValue), TRUE);
215 + cValues -= 2;
216 +
217 + for (DWORD i = 0; i < cValues; ++i)
218 + {
219 + CheckItem(rgValues + i, i);
220 + }
221 +
222 + // Remove first item
223 + MemRemoveFromArray(rgValues, 0, 1, cValues, sizeof(ArrayValue), TRUE);
224 + --cValues;
225 +
226 + for (DWORD i = 0; i < cValues; ++i)
227 + {
228 + CheckItem(rgValues + i, i + 1);
229 + }
230 +
231 +
232 + // Remove first two items
233 + MemRemoveFromArray(rgValues, 0, 2, cValues, sizeof(ArrayValue), TRUE);
234 + cValues -= 2;
235 +
236 + for (DWORD i = 0; i < cValues; ++i)
237 + {
238 + CheckItem(rgValues + i, i + 3);
239 + }
240 +
241 + // Remove middle two items
242 + MemRemoveFromArray(rgValues, 1, 2, cValues, sizeof(ArrayValue), TRUE);
243 + cValues -= 2;
244 +
245 + CheckItem(rgValues, 3);
246 + CheckItem(rgValues + 1, 6);
247 +
248 + // Remove last 2 items to ensure we don't crash
249 + MemRemoveFromArray(rgValues, 0, 2, cValues, sizeof(ArrayValue), TRUE);
250 + cValues -= 2;
251 + }
252 + finally
253 + {
254 + ReleaseMem(rgValues);
255 + }
256 + }
257 +
258 + [Fact]
259 + void MemUtilRemoveFastTest()
260 + {
261 + HRESULT hr = S_OK;
262 + ArrayValue *rgValues = NULL;
263 + DWORD cValues = 0;
264 +
265 + try
266 + {
267 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), 10, sizeof(ArrayValue), 10);
268 + NativeAssert::Succeeded(hr, "Failed to grow array size to 10");
269 +
270 + cValues = 10;
271 + for (DWORD i = 0; i < cValues; ++i)
272 + {
273 + SetItem(rgValues + i, i);
274 + }
275 +
276 + // Remove last item
277 + MemRemoveFromArray(rgValues, 9, 1, cValues, sizeof(ArrayValue), FALSE);
278 + --cValues;
279 +
280 + for (DWORD i = 0; i < cValues; ++i)
281 + {
282 + CheckItem(rgValues + i, i);
283 + }
284 +
285 + // Remove last two items
286 + MemRemoveFromArray(rgValues, 7, 2, cValues, sizeof(ArrayValue), FALSE);
287 + cValues -= 2;
288 +
289 + for (DWORD i = 0; i < cValues; ++i)
290 + {
291 + CheckItem(rgValues + i, i);
292 + }
293 +
294 + // Remove first item
295 + MemRemoveFromArray(rgValues, 0, 1, cValues, sizeof(ArrayValue), FALSE);
296 + --cValues;
297 +
298 + CheckItem(rgValues, 6);
299 + CheckItem(rgValues + 1, 1);
300 + CheckItem(rgValues + 2, 2);
301 + CheckItem(rgValues + 3, 3);
302 + CheckItem(rgValues + 4, 4);
303 + CheckItem(rgValues + 5, 5);
304 +
305 + // Remove first two items
306 + MemRemoveFromArray(rgValues, 0, 2, cValues, sizeof(ArrayValue), FALSE);
307 + cValues -= 2;
308 +
309 + CheckItem(rgValues, 4);
310 + CheckItem(rgValues + 1, 5);
311 + CheckItem(rgValues + 2, 2);
312 + CheckItem(rgValues + 3, 3);
313 +
314 +
315 + // Remove middle two items
316 + MemRemoveFromArray(rgValues, 1, 2, cValues, sizeof(ArrayValue), FALSE);
317 + cValues -= 2;
318 +
319 + CheckItem(rgValues, 4);
320 + CheckItem(rgValues + 1, 3);
321 +
322 + // Remove last 2 items to ensure we don't crash
323 + MemRemoveFromArray(rgValues, 0, 2, cValues, sizeof(ArrayValue), FALSE);
324 + cValues -= 2;
325 + }
326 + finally
327 + {
328 + ReleaseMem(rgValues);
329 + }
330 + }
331 +
332 + [Fact]
333 + void MemUtilSwapTest()
334 + {
335 + HRESULT hr = S_OK;
336 + ArrayValue *rgValues = NULL;
337 + DWORD cValues = 0;
338 +
339 + try
340 + {
341 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&rgValues), 10, sizeof(ArrayValue), 10);
342 + NativeAssert::Succeeded(hr, "Failed to grow array size to 10");
343 +
344 + cValues = 10;
345 + for (DWORD i = 0; i < cValues; ++i)
346 + {
347 + SetItem(rgValues + i, i);
348 + }
349 +
350 + // Swap first two
351 + MemArraySwapItems(rgValues, 0, 1, sizeof(ArrayValue));
352 + --cValues;
353 +
354 + CheckItem(rgValues, 1);
355 + CheckItem(rgValues + 1, 0);
356 + for (DWORD i = 2; i < cValues; ++i)
357 + {
358 + CheckItem(rgValues + i, i);
359 + }
360 +
361 + // Swap them back
362 + MemArraySwapItems(rgValues, 0, 1, sizeof(ArrayValue));
363 + --cValues;
364 +
365 + for (DWORD i = 0; i < cValues; ++i)
366 + {
367 + CheckItem(rgValues + i, i);
368 + }
369 +
370 + // Swap first and last items (index 0 and 9)
371 + MemArraySwapItems(rgValues, 0, 9, sizeof(ArrayValue));
372 + --cValues;
373 +
374 + CheckItem(rgValues, 9);
375 + CheckItem(rgValues + 9, 0);
376 + for (DWORD i = 1; i < cValues - 1; ++i)
377 + {
378 + CheckItem(rgValues + i, i);
379 + }
380 +
381 + // Swap index 1 and 8
382 + MemArraySwapItems(rgValues, 1, 8, sizeof(ArrayValue));
383 + --cValues;
384 +
385 + CheckItem(rgValues, 9);
386 + CheckItem(rgValues + 1, 8);
387 + CheckItem(rgValues + 8, 1);
388 + CheckItem(rgValues + 9, 0);
389 + for (DWORD i = 2; i < cValues - 2; ++i)
390 + {
391 + CheckItem(rgValues + i, i);
392 + }
393 +
394 + // Swap index 2 and 7
395 + MemArraySwapItems(rgValues, 2, 7, sizeof(ArrayValue));
396 + --cValues;
397 +
398 + CheckItem(rgValues, 9);
399 + CheckItem(rgValues + 1, 8);
400 + CheckItem(rgValues + 2, 7);
401 + CheckItem(rgValues + 7, 2);
402 + CheckItem(rgValues + 8, 1);
403 + CheckItem(rgValues + 9, 0);
404 + for (DWORD i = 3; i < cValues - 3; ++i)
405 + {
406 + CheckItem(rgValues + i, i);
407 + }
408 +
409 + // Swap index 0 and 1
410 + MemArraySwapItems(rgValues, 0, 1, sizeof(ArrayValue));
411 + --cValues;
412 +
413 + CheckItem(rgValues, 8);
414 + CheckItem(rgValues + 1, 9);
415 + CheckItem(rgValues + 2, 7);
416 + CheckItem(rgValues + 7, 2);
417 + CheckItem(rgValues + 8, 1);
418 + CheckItem(rgValues + 9, 0);
419 + for (DWORD i = 3; i < cValues - 3; ++i)
420 + {
421 + CheckItem(rgValues + i, i);
422 + }
423 + }
424 + finally
425 + {
426 + ReleaseMem(rgValues);
427 + }
428 + }
429 +
430 + private:
431 + void SetItem(ArrayValue *pValue, DWORD dwValue)
432 + {
433 + HRESULT hr = S_OK;
434 + pValue->dwNum = dwValue;
435 +
436 + hr = StrAllocFormatted(&pValue->sczString, L"%u", dwValue);
437 + NativeAssert::Succeeded(hr, "Failed to allocate string");
438 + }
439 +
440 + void CheckItem(ArrayValue *pValue, DWORD dwValue)
441 + {
442 + HRESULT hr = S_OK;
443 + LPWSTR sczTemp = NULL;
444 +
445 + try
446 + {
447 + NativeAssert::Equal(dwValue, pValue->dwNum);
448 +
449 + hr = StrAllocFormatted(&sczTemp, L"%u", dwValue);
450 + NativeAssert::Succeeded(hr, "Failed to allocate temp string");
451 +
452 + NativeAssert::StringEqual(sczTemp, pValue->sczString, TRUE);
453 +
454 + if (pValue->pvNull1 || pValue->pvNull2)
455 + {
456 + hr = E_FAIL;
457 + ExitOnFailure(hr, "One of the expected NULL values wasn't NULL!");
458 + }
459 + }
460 + finally
461 + {
462 + ReleaseStr(sczTemp);
463 + }
464 +
465 + LExit:
466 + return;
467 + }
468 +
469 + void CheckNullItem(ArrayValue *pValue)
470 + {
471 + HRESULT hr = S_OK;
472 +
473 + NativeAssert::Equal<DWORD>(0, pValue->dwNum);
474 +
475 + if (pValue->sczString)
476 + {
477 + hr = E_FAIL;
478 + ExitOnFailure(hr, "Item found isn't NULL!");
479 + }
480 +
481 + if (pValue->pvNull1 || pValue->pvNull2)
482 + {
483 + hr = E_FAIL;
484 + ExitOnFailure(hr, "One of the expected NULL values wasn't NULL!");
485 + }
486 +
487 + LExit:
488 + return;
489 + }
490 + };
491 +}
src/test/DUtilUnitTest/MonUtilTest.cpp new
+487
@@ -0,0 +1,487 @@
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 RemoveDirectory
5 +
6 +using namespace System;
7 +using namespace System::Collections::Generic;
8 +using namespace System::Runtime::InteropServices;
9 +using namespace Xunit;
10 +using namespace WixTest;
11 +
12 +namespace DutilTests
13 +{
14 + const int PREWAIT = 20;
15 + const int POSTWAIT = 480;
16 + const int FULLWAIT = 500;
17 + const int SILENCEPERIOD = 100;
18 +
19 + struct RegKey
20 + {
21 + HRESULT hr;
22 + HKEY hkRoot;
23 + LPCWSTR wzSubKey;
24 + REG_KEY_BITNESS kbKeyBitness;
25 + BOOL fRecursive;
26 + };
27 + struct Directory
28 + {
29 + HRESULT hr;
30 + LPCWSTR wzPath;
31 + BOOL fRecursive;
32 + };
33 + struct Results
34 + {
35 + RegKey *rgRegKeys;
36 + DWORD cRegKeys;
37 + Directory *rgDirectories;
38 + DWORD cDirectories;
39 + };
40 +
41 + public delegate void MonGeneralDelegate(HRESULT, LPVOID);
42 +
43 + public delegate void MonDriveStatusDelegate(WCHAR, BOOL, LPVOID);
44 +
45 + public delegate void MonDirectoryDelegate(HRESULT, LPCWSTR, BOOL, LPVOID, LPVOID);
46 +
47 + public delegate void MonRegKeyDelegate(HRESULT, HKEY, LPCWSTR, REG_KEY_BITNESS, BOOL, LPVOID, LPVOID);
48 +
49 + static void MonGeneral(
50 + __in HRESULT /*hrResult*/,
51 + __in_opt LPVOID /*pvContext*/
52 + )
53 + {
54 + Assert::True(false);
55 + }
56 +
57 + static void MonDriveStatus(
58 + __in WCHAR /*chDrive*/,
59 + __in BOOL /*fArriving*/,
60 + __in_opt LPVOID /*pvContext*/
61 + )
62 + {
63 + }
64 +
65 + static void MonDirectory(
66 + __in HRESULT hrResult,
67 + __in_z LPCWSTR wzPath,
68 + __in_z BOOL fRecursive,
69 + __in_opt LPVOID pvContext,
70 + __in_opt LPVOID pvDirectoryContext
71 + )
72 + {
73 + Assert::Equal(S_OK, hrResult);
74 + Assert::Equal<DWORD_PTR>(0, reinterpret_cast<DWORD_PTR>(pvDirectoryContext));
75 +
76 + HRESULT hr = S_OK;
77 + Results *pResults = reinterpret_cast<Results *>(pvContext);
78 +
79 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pResults->rgDirectories), pResults->cDirectories + 1, sizeof(Directory), 5);
80 + NativeAssert::ValidReturnCode(hr, S_OK);
81 + ++pResults->cDirectories;
82 +
83 + pResults->rgDirectories[pResults->cDirectories - 1].hr = hrResult;
84 + pResults->rgDirectories[pResults->cDirectories - 1].wzPath = wzPath;
85 + pResults->rgDirectories[pResults->cDirectories - 1].fRecursive = fRecursive;
86 + }
87 +
88 + static void MonRegKey(
89 + __in HRESULT hrResult,
90 + __in HKEY hkRoot,
91 + __in_z LPCWSTR wzSubKey,
92 + __in REG_KEY_BITNESS kbKeyBitness,
93 + __in_z BOOL fRecursive,
94 + __in_opt LPVOID pvContext,
95 + __in_opt LPVOID pvRegKeyContext
96 + )
97 + {
98 + Assert::Equal<HRESULT>(S_OK, hrResult);
99 + Assert::Equal<DWORD_PTR>(0, reinterpret_cast<DWORD_PTR>(pvRegKeyContext));
100 +
101 + HRESULT hr = S_OK;
102 + Results *pResults = reinterpret_cast<Results *>(pvContext);
103 +
104 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pResults->rgRegKeys), pResults->cRegKeys + 1, sizeof(RegKey), 5);
105 + NativeAssert::ValidReturnCode(hr, S_OK);
106 + ++pResults->cRegKeys;
107 +
108 + pResults->rgRegKeys[pResults->cRegKeys - 1].hr = hrResult;
109 + pResults->rgRegKeys[pResults->cRegKeys - 1].hkRoot = hkRoot;
110 + pResults->rgRegKeys[pResults->cRegKeys - 1].wzSubKey = wzSubKey;
111 + pResults->rgRegKeys[pResults->cRegKeys - 1].kbKeyBitness = kbKeyBitness;
112 + pResults->rgRegKeys[pResults->cRegKeys - 1].fRecursive = fRecursive;
113 + }
114 +
115 + public ref class MonUtil
116 + {
117 + public:
118 + void ClearResults(Results *pResults)
119 + {
120 + ReleaseNullMem(pResults->rgDirectories);
121 + pResults->cDirectories = 0;
122 + ReleaseNullMem(pResults->rgRegKeys);
123 + pResults->cRegKeys = 0;
124 + }
125 +
126 + void RemoveDirectory(LPCWSTR wzPath)
127 + {
128 + DWORD dwRetryCount = 0;
129 + const DWORD c_dwMaxRetryCount = 100;
130 + const DWORD c_dwRetryInterval = 50;
131 +
132 + HRESULT hr = DirEnsureDelete(wzPath, TRUE, TRUE);
133 +
134 + // Monitoring a directory opens a handle to that directory, which means delete requests for that directory will succeed
135 + // (and deletion will be "pending" until our monitor handle is closed)
136 + // but deletion of the directory containing that directory cannot complete until the handle is closed. This means DirEnsureDelete()
137 + // can sometimes encounter HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY) failures, which just means it needs to retry a bit later
138 + // (after the waiter thread wakes up, it will release the handle)
139 + while (HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY) == hr && c_dwMaxRetryCount > dwRetryCount)
140 + {
141 + ::Sleep(c_dwRetryInterval);
142 + ++dwRetryCount;
143 + hr = DirEnsureDelete(wzPath, TRUE, TRUE);
144 + }
145 +
146 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE, E_PATHNOTFOUND);
147 + }
148 +
149 + void TestDirectory(MON_HANDLE handle, Results *pResults)
150 + {
151 + HRESULT hr = S_OK;
152 + LPWSTR sczShallowPath = NULL;
153 + LPWSTR sczParentPath = NULL;
154 + LPWSTR sczDeepPath = NULL;
155 + LPWSTR sczChildPath = NULL;
156 + LPWSTR sczChildFilePath = NULL;
157 +
158 + try
159 + {
160 + hr = PathExpand(&sczShallowPath, L"%TEMP%\\MonUtilTest\\", PATH_EXPAND_ENVIRONMENT);
161 + NativeAssert::ValidReturnCode(hr, S_OK);
162 +
163 + hr = PathExpand(&sczParentPath, L"%TEMP%\\MonUtilTest\\sub\\folder\\that\\might\\not\\", PATH_EXPAND_ENVIRONMENT);
164 + NativeAssert::ValidReturnCode(hr, S_OK);
165 +
166 + hr = PathExpand(&sczDeepPath, L"%TEMP%\\MonUtilTest\\sub\\folder\\that\\might\\not\\exist\\", PATH_EXPAND_ENVIRONMENT);
167 + NativeAssert::ValidReturnCode(hr, S_OK);
168 +
169 + hr = PathExpand(&sczChildPath, L"%TEMP%\\MonUtilTest\\sub\\folder\\that\\might\\not\\exist\\some\\sub\\folder\\", PATH_EXPAND_ENVIRONMENT);
170 + NativeAssert::ValidReturnCode(hr, S_OK);
171 +
172 + hr = PathExpand(&sczChildFilePath, L"%TEMP%\\MonUtilTest\\sub\\folder\\that\\might\\not\\exist\\some\\sub\\folder\\file.txt", PATH_EXPAND_ENVIRONMENT);
173 + NativeAssert::ValidReturnCode(hr, S_OK);
174 +
175 + RemoveDirectory(sczShallowPath);
176 +
177 + hr = MonAddDirectory(handle, sczDeepPath, TRUE, SILENCEPERIOD, NULL);
178 + NativeAssert::ValidReturnCode(hr, S_OK);
179 +
180 + hr = DirEnsureExists(sczParentPath, NULL);
181 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
182 + // Make sure creating the parent directory does nothing, even after silence period
183 + ::Sleep(FULLWAIT);
184 + Assert::Equal<DWORD>(0, pResults->cDirectories);
185 +
186 + // Now create the target path, no notification until after the silence period
187 + hr = DirEnsureExists(sczDeepPath, NULL);
188 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
189 + ::Sleep(PREWAIT);
190 + Assert::Equal<DWORD>(0, pResults->cDirectories);
191 +
192 + // Now after the full silence period, it should have triggered
193 + ::Sleep(POSTWAIT);
194 + Assert::Equal<DWORD>(1, pResults->cDirectories);
195 + NativeAssert::ValidReturnCode(pResults->rgDirectories[0].hr, S_OK);
196 +
197 + // Now delete the directory, along with a ton of parents. This verifies MonUtil will keep watching the closest parent that still exists.
198 + RemoveDirectory(sczShallowPath);
199 +
200 + ::Sleep(FULLWAIT);
201 + Assert::Equal<DWORD>(2, pResults->cDirectories);
202 + NativeAssert::ValidReturnCode(pResults->rgDirectories[1].hr, S_OK);
203 +
204 + // Create the parent directory again, still should be nothing even after full silence period
205 + hr = DirEnsureExists(sczParentPath, NULL);
206 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
207 + ::Sleep(FULLWAIT);
208 + Assert::Equal<DWORD>(2, pResults->cDirectories);
209 +
210 + hr = DirEnsureExists(sczChildPath, NULL);
211 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
212 + ::Sleep(PREWAIT);
213 + Assert::Equal<DWORD>(2, pResults->cDirectories);
214 +
215 + ::Sleep(POSTWAIT);
216 + Assert::Equal<DWORD>(3, pResults->cDirectories);
217 + NativeAssert::ValidReturnCode(pResults->rgDirectories[2].hr, S_OK);
218 +
219 + // Write a file to a deep child subfolder, and make sure it's detected
220 + hr = FileFromString(sczChildFilePath, 0, L"contents", FILE_ENCODING_UTF16_WITH_BOM);
221 + NativeAssert::ValidReturnCode(hr, S_OK);
222 + ::Sleep(PREWAIT);
223 + Assert::Equal<DWORD>(3, pResults->cDirectories);
224 +
225 + ::Sleep(POSTWAIT);
226 + Assert::Equal<DWORD>(4, pResults->cDirectories);
227 + NativeAssert::ValidReturnCode(pResults->rgDirectories[2].hr, S_OK);
228 +
229 + RemoveDirectory(sczParentPath);
230 +
231 + ::Sleep(FULLWAIT);
232 + Assert::Equal<DWORD>(5, pResults->cDirectories);
233 + NativeAssert::ValidReturnCode(pResults->rgDirectories[3].hr, S_OK);
234 +
235 + // Now remove the directory from the list of things to monitor, and confirm changes are no longer tracked
236 + hr = MonRemoveDirectory(handle, sczDeepPath, TRUE);
237 + NativeAssert::ValidReturnCode(hr, S_OK);
238 + ::Sleep(PREWAIT);
239 +
240 + hr = DirEnsureExists(sczDeepPath, NULL);
241 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
242 + ::Sleep(FULLWAIT);
243 + Assert::Equal<DWORD>(5, pResults->cDirectories);
244 + NativeAssert::ValidReturnCode(pResults->rgDirectories[3].hr, S_OK);
245 +
246 + // Finally, add it back so we can test multiple things to monitor at once
247 + hr = MonAddDirectory(handle, sczDeepPath, TRUE, SILENCEPERIOD, NULL);
248 + NativeAssert::ValidReturnCode(hr, S_OK);
249 + }
250 + finally
251 + {
252 + ReleaseStr(sczShallowPath);
253 + ReleaseStr(sczDeepPath);
254 + ReleaseStr(sczParentPath);
255 + }
256 + }
257 +
258 + void TestRegKey(MON_HANDLE handle, Results *pResults)
259 + {
260 + HRESULT hr = S_OK;
261 + LPCWSTR wzShallowRegKey = L"Software\\MonUtilTest\\";
262 + LPCWSTR wzParentRegKey = L"Software\\MonUtilTest\\sub\\folder\\that\\might\\not\\";
263 + LPCWSTR wzDeepRegKey = L"Software\\MonUtilTest\\sub\\folder\\that\\might\\not\\exist\\";
264 + LPCWSTR wzChildRegKey = L"Software\\MonUtilTest\\sub\\folder\\that\\might\\not\\exist\\some\\sub\\folder\\";
265 + HKEY hk = NULL;
266 +
267 + try
268 + {
269 + hr = RegDelete(HKEY_CURRENT_USER, wzShallowRegKey, REG_KEY_32BIT, TRUE);
270 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE, E_PATHNOTFOUND);
271 +
272 + hr = MonAddRegKey(handle, HKEY_CURRENT_USER, wzDeepRegKey, REG_KEY_DEFAULT, TRUE, SILENCEPERIOD, NULL);
273 + NativeAssert::ValidReturnCode(hr, S_OK);
274 +
275 + hr = RegCreate(HKEY_CURRENT_USER, wzParentRegKey, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hk);
276 + ReleaseRegKey(hk);
277 + // Make sure creating the parent key does nothing, even after silence period
278 + ::Sleep(FULLWAIT);
279 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
280 + Assert::Equal<DWORD>(0, pResults->cRegKeys);
281 +
282 + // Now create the target path, no notification until after the silence period
283 + hr = RegCreate(HKEY_CURRENT_USER, wzDeepRegKey, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hk);
284 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
285 + ReleaseRegKey(hk);
286 + ::Sleep(PREWAIT);
287 + Assert::Equal<DWORD>(0, pResults->cRegKeys);
288 +
289 + // Now after the full silence period, it should have triggered
290 + ::Sleep(POSTWAIT);
291 + Assert::Equal<DWORD>(1, pResults->cRegKeys);
292 + NativeAssert::ValidReturnCode(pResults->rgRegKeys[0].hr, S_OK);
293 +
294 + // Now delete the directory, along with a ton of parents. This verifies MonUtil will keep watching the closest parent that still exists.
295 + hr = RegDelete(HKEY_CURRENT_USER, wzShallowRegKey, REG_KEY_32BIT, TRUE);
296 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE, E_PATHNOTFOUND);
297 + ::Sleep(PREWAIT);
298 + Assert::Equal<DWORD>(1, pResults->cRegKeys);
299 +
300 + ::Sleep(FULLWAIT);
301 + Assert::Equal<DWORD>(2, pResults->cRegKeys);
302 + NativeAssert::ValidReturnCode(pResults->rgRegKeys[1].hr, S_OK);
303 +
304 + // Create the parent directory again, still should be nothing even after full silence period
305 + hr = RegCreate(HKEY_CURRENT_USER, wzParentRegKey, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hk);
306 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
307 + ReleaseRegKey(hk);
308 + ::Sleep(FULLWAIT);
309 + Assert::Equal<DWORD>(2, pResults->cRegKeys);
310 +
311 + hr = RegCreate(HKEY_CURRENT_USER, wzChildRegKey, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hk);
312 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
313 + ::Sleep(PREWAIT);
314 + Assert::Equal<DWORD>(2, pResults->cRegKeys);
315 +
316 + ::Sleep(FULLWAIT);
317 + Assert::Equal<DWORD>(3, pResults->cRegKeys);
318 + NativeAssert::ValidReturnCode(pResults->rgRegKeys[2].hr, S_OK);
319 +
320 + // Write a registry value to some deep child subkey, and make sure it's detected
321 + hr = RegWriteString(hk, L"valuename", L"testvalue");
322 + NativeAssert::ValidReturnCode(hr, S_OK);
323 + ReleaseRegKey(hk);
324 + ::Sleep(PREWAIT);
325 + Assert::Equal<DWORD>(3, pResults->cRegKeys);
326 +
327 + ::Sleep(FULLWAIT);
328 + Assert::Equal<DWORD>(4, pResults->cRegKeys);
329 + NativeAssert::ValidReturnCode(pResults->rgRegKeys[2].hr, S_OK);
330 +
331 + hr = RegDelete(HKEY_CURRENT_USER, wzDeepRegKey, REG_KEY_32BIT, TRUE);
332 + NativeAssert::ValidReturnCode(hr, S_OK);
333 +
334 + ::Sleep(FULLWAIT);
335 + Assert::Equal<DWORD>(5, pResults->cRegKeys);
336 +
337 + // Now remove the regkey from the list of things to monitor, and confirm changes are no longer tracked
338 + hr = MonRemoveRegKey(handle, HKEY_CURRENT_USER, wzDeepRegKey, REG_KEY_DEFAULT, TRUE);
339 + NativeAssert::ValidReturnCode(hr, S_OK);
340 +
341 + hr = RegCreate(HKEY_CURRENT_USER, wzDeepRegKey, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hk);
342 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
343 + ReleaseRegKey(hk);
344 + ::Sleep(FULLWAIT);
345 + Assert::Equal<DWORD>(5, pResults->cRegKeys);
346 + }
347 + finally
348 + {
349 + ReleaseRegKey(hk);
350 + }
351 + }
352 +
353 + void TestMoreThan64(MON_HANDLE handle, Results *pResults)
354 + {
355 + HRESULT hr = S_OK;
356 + LPWSTR sczBaseDir = NULL;
357 + LPWSTR sczDir = NULL;
358 + LPWSTR sczFile = NULL;
359 +
360 + try
361 + {
362 + hr = PathExpand(&sczBaseDir, L"%TEMP%\\ScalabilityTest\\", PATH_EXPAND_ENVIRONMENT);
363 + NativeAssert::ValidReturnCode(hr, S_OK);
364 +
365 + for (DWORD i = 0; i < 200; ++i)
366 + {
367 + hr = StrAllocFormatted(&sczDir, L"%ls%u\\", sczBaseDir, i);
368 + NativeAssert::ValidReturnCode(hr, S_OK);
369 +
370 + hr = DirEnsureExists(sczDir, NULL);
371 + NativeAssert::ValidReturnCode(hr, S_OK, S_FALSE);
372 +
373 + hr = MonAddDirectory(handle, sczDir, FALSE, SILENCEPERIOD, NULL);
374 + NativeAssert::ValidReturnCode(hr, S_OK);
375 + }
376 +
377 + hr = PathConcat(sczDir, L"file.txt", &sczFile);
378 + NativeAssert::ValidReturnCode(hr, S_OK);
379 +
380 + hr = FileFromString(sczFile, 0, L"contents", FILE_ENCODING_UTF16_WITH_BOM);
381 + NativeAssert::ValidReturnCode(hr, S_OK);
382 +
383 + ::Sleep(FULLWAIT);
384 + Assert::Equal<DWORD>(1, pResults->cDirectories);
385 +
386 + for (DWORD i = 0; i < 199; ++i)
387 + {
388 + hr = StrAllocFormatted(&sczDir, L"%ls%u\\", sczBaseDir, i);
389 + NativeAssert::ValidReturnCode(hr, S_OK);
390 +
391 + hr = MonRemoveDirectory(handle, sczDir, FALSE);
392 + NativeAssert::ValidReturnCode(hr, S_OK);
393 + }
394 + ::Sleep(FULLWAIT);
395 +
396 + hr = FileFromString(sczFile, 0, L"contents2", FILE_ENCODING_UTF16_WITH_BOM);
397 + NativeAssert::ValidReturnCode(hr, S_OK);
398 +
399 + ::Sleep(FULLWAIT);
400 + Assert::Equal<DWORD>(2, pResults->cDirectories);
401 +
402 + for (DWORD i = 0; i < 199; ++i)
403 + {
404 + hr = StrAllocFormatted(&sczDir, L"%ls%u\\", sczBaseDir, i);
405 + NativeAssert::ValidReturnCode(hr, S_OK);
406 +
407 + hr = MonAddDirectory(handle, sczDir, FALSE, SILENCEPERIOD, NULL);
408 + NativeAssert::ValidReturnCode(hr, S_OK);
409 + }
410 + ::Sleep(FULLWAIT);
411 +
412 + hr = FileFromString(sczFile, 0, L"contents3", FILE_ENCODING_UTF16_WITH_BOM);
413 + NativeAssert::ValidReturnCode(hr, S_OK);
414 +
415 + ::Sleep(FULLWAIT);
416 + Assert::Equal<DWORD>(3, pResults->cDirectories);
417 + }
418 + finally
419 + {
420 + ReleaseStr(sczBaseDir);
421 + ReleaseStr(sczDir);
422 + ReleaseStr(sczFile);
423 + }
424 + }
425 +
426 + [Fact]
427 + void MonUtilTest()
428 + {
429 + HRESULT hr = S_OK;
430 + MON_HANDLE handle = NULL;
431 + List<GCHandle>^ gcHandles = gcnew List<GCHandle>();
432 + Results *pResults = (Results *)MemAlloc(sizeof(Results), TRUE);
433 + Assert::True(NULL != pResults);
434 +
435 + try
436 + {
437 + // These ensure the function pointers we send point to this thread's appdomain, which helps with assembly binding when running tests within msbuild
438 + MonGeneralDelegate^ fpMonGeneral = gcnew MonGeneralDelegate(MonGeneral);
439 + GCHandle gchMonGeneral = GCHandle::Alloc(fpMonGeneral);
440 + gcHandles->Add(gchMonGeneral);
441 + IntPtr ipMonGeneral = Marshal::GetFunctionPointerForDelegate(fpMonGeneral);
442 +
443 + MonDriveStatusDelegate^ fpMonDriveStatus = gcnew MonDriveStatusDelegate(MonDriveStatus);
444 + GCHandle gchMonDriveStatus = GCHandle::Alloc(fpMonDriveStatus);
445 + gcHandles->Add(gchMonDriveStatus);
446 + IntPtr ipMonDriveStatus = Marshal::GetFunctionPointerForDelegate(fpMonDriveStatus);
447 +
448 + MonDirectoryDelegate^ fpMonDirectory = gcnew MonDirectoryDelegate(MonDirectory);
449 + GCHandle gchMonDirectory = GCHandle::Alloc(fpMonDirectory);
450 + gcHandles->Add(gchMonDirectory);
451 + IntPtr ipMonDirectory = Marshal::GetFunctionPointerForDelegate(fpMonDirectory);
452 +
453 + MonRegKeyDelegate^ fpMonRegKey = gcnew MonRegKeyDelegate(MonRegKey);
454 + GCHandle gchMonRegKey = GCHandle::Alloc(fpMonRegKey);
455 + gcHandles->Add(gchMonRegKey);
456 + IntPtr ipMonRegKey = Marshal::GetFunctionPointerForDelegate(fpMonRegKey);
457 +
458 + // "Silence period" is 100 ms
459 + hr = MonCreate(&handle, static_cast<PFN_MONGENERAL>(ipMonGeneral.ToPointer()), static_cast<PFN_MONDRIVESTATUS>(ipMonDriveStatus.ToPointer()), static_cast<PFN_MONDIRECTORY>(ipMonDirectory.ToPointer()), static_cast<PFN_MONREGKEY>(ipMonRegKey.ToPointer()), pResults);
460 + NativeAssert::ValidReturnCode(hr, S_OK);
461 +
462 + hr = RegInitialize();
463 + NativeAssert::ValidReturnCode(hr, S_OK);
464 +
465 + TestDirectory(handle, pResults);
466 + ClearResults(pResults);
467 + TestRegKey(handle, pResults);
468 + ClearResults(pResults);
469 + TestMoreThan64(handle, pResults);
470 + ClearResults(pResults);
471 + }
472 + finally
473 + {
474 + ReleaseMon(handle);
475 +
476 + for each (GCHandle gcHandle in gcHandles)
477 + {
478 + gcHandle.Free();
479 + }
480 +
481 + ReleaseMem(pResults->rgDirectories);
482 + ReleaseMem(pResults->rgRegKeys);
483 + ReleaseMem(pResults);
484 + }
485 + }
486 + };
487 +}
src/test/DUtilUnitTest/NativeAssert.h new
+83
@@ -0,0 +1,83 @@
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 WixTest {
6 +
7 + using namespace System;
8 + using namespace System::Collections::Generic;
9 + using namespace System::Linq;
10 + using namespace Xunit;
11 +
12 + public ref class NativeAssert : WixAssert
13 + {
14 + public:
15 + static void NotNull(LPCWSTR wz)
16 + {
17 + if (!wz)
18 + {
19 + Assert::NotNull(nullptr);
20 + }
21 + }
22 +
23 + // For some reason, naming these NotStringEqual methods "NotEqual" breaks Intellisense in files that call any overload of the NotEqual method.
24 + static void NotStringEqual(LPCWSTR expected, LPCWSTR actual)
25 + {
26 + NativeAssert::NotStringEqual(expected, actual, FALSE);
27 + }
28 +
29 + static void NotStringEqual(LPCWSTR expected, LPCWSTR actual, BOOL ignoreCase)
30 + {
31 + IEqualityComparer<String^>^ comparer = ignoreCase ? StringComparer::InvariantCultureIgnoreCase : StringComparer::InvariantCulture;
32 + Assert::NotEqual(NativeAssert::LPWSTRToString(expected), NativeAssert::LPWSTRToString(actual), comparer);
33 + }
34 +
35 + // For some reason, naming these StringEqual methods "Equal" breaks Intellisense in files that call any overload of the Equal method.
36 + static void StringEqual(LPCWSTR expected, LPCWSTR actual)
37 + {
38 + NativeAssert::StringEqual(expected, actual, FALSE);
39 + }
40 +
41 + static void StringEqual(LPCWSTR expected, LPCWSTR actual, BOOL ignoreCase)
42 + {
43 + IEqualityComparer<String^>^ comparer = ignoreCase ? StringComparer::InvariantCultureIgnoreCase : StringComparer::InvariantCulture;
44 + Assert::Equal(NativeAssert::LPWSTRToString(expected), NativeAssert::LPWSTRToString(actual), comparer);
45 + }
46 +
47 + static void Succeeded(HRESULT hr, LPCSTR zFormat, LPCSTR zArg, ... array<LPCSTR>^ zArgs)
48 + {
49 + array<Object^>^ formatArgs = gcnew array<Object^, 1>(zArgs->Length + 1);
50 + formatArgs[0] = NativeAssert::LPSTRToString(zArg);
51 + for (int i = 0; i < zArgs->Length; ++i)
52 + {
53 + formatArgs[i + 1] = NativeAssert::LPSTRToString(zArgs[i]);
54 + }
55 + WixAssert::Succeeded(hr, gcnew String(zFormat), formatArgs);
56 + }
57 +
58 + static void Succeeded(HRESULT hr, LPCSTR zFormat, ... array<LPCWSTR>^ wzArgs)
59 + {
60 + array<Object^>^ formatArgs = gcnew array<Object^, 1>(wzArgs->Length);
61 + for (int i = 0; i < wzArgs->Length; ++i)
62 + {
63 + formatArgs[i] = NativeAssert::LPWSTRToString(wzArgs[i]);
64 + }
65 + WixAssert::Succeeded(hr, gcnew String(zFormat), formatArgs);
66 + }
67 +
68 + static void ValidReturnCode(HRESULT hr, ... array<HRESULT>^ validReturnCodes)
69 + {
70 + Assert::Contains(hr, (IEnumerable<HRESULT>^)validReturnCodes);
71 + }
72 +
73 + private:
74 + static String^ LPSTRToString(LPCSTR z)
75 + {
76 + return z ? gcnew String(z) : nullptr;
77 + }
78 + static String^ LPWSTRToString(LPCWSTR wz)
79 + {
80 + return wz ? gcnew String(wz) : nullptr;
81 + }
82 + };
83 +}
src/test/DUtilUnitTest/PathUtilTest.cpp new
+80
@@ -0,0 +1,80 @@
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;
6 +using namespace Xunit;
7 +using namespace WixTest;
8 +
9 +namespace DutilTests
10 +{
11 + public ref class PathUtil
12 + {
13 + public:
14 + [Fact]
15 + void PathGetHierarchyArrayTest()
16 + {
17 + HRESULT hr = S_OK;
18 + LPWSTR *rgsczPaths = NULL;
19 + UINT cPaths = 0;
20 +
21 + try
22 + {
23 + hr = PathGetHierarchyArray(L"c:\\foo\\bar\\bas\\a.txt", &rgsczPaths, &cPaths);
24 + NativeAssert::Succeeded(hr, "Failed to get parent directories array for regular file path");
25 + Assert::Equal<DWORD>(5, cPaths);
26 + NativeAssert::StringEqual(L"c:\\", rgsczPaths[0]);
27 + NativeAssert::StringEqual(L"c:\\foo\\", rgsczPaths[1]);
28 + NativeAssert::StringEqual(L"c:\\foo\\bar\\", rgsczPaths[2]);
29 + NativeAssert::StringEqual(L"c:\\foo\\bar\\bas\\", rgsczPaths[3]);
30 + NativeAssert::StringEqual(L"c:\\foo\\bar\\bas\\a.txt", rgsczPaths[4]);
31 + ReleaseNullStrArray(rgsczPaths, cPaths);
32 +
33 + hr = PathGetHierarchyArray(L"c:\\foo\\bar\\bas\\", &rgsczPaths, &cPaths);
34 + NativeAssert::Succeeded(hr, "Failed to get parent directories array for regular directory path");
35 + Assert::Equal<DWORD>(4, cPaths);
36 + NativeAssert::StringEqual(L"c:\\", rgsczPaths[0]);
37 + NativeAssert::StringEqual(L"c:\\foo\\", rgsczPaths[1]);
38 + NativeAssert::StringEqual(L"c:\\foo\\bar\\", rgsczPaths[2]);
39 + NativeAssert::StringEqual(L"c:\\foo\\bar\\bas\\", rgsczPaths[3]);
40 + ReleaseNullStrArray(rgsczPaths, cPaths);
41 +
42 + hr = PathGetHierarchyArray(L"\\\\server\\share\\subdir\\file.txt", &rgsczPaths, &cPaths);
43 + NativeAssert::Succeeded(hr, "Failed to get parent directories array for UNC file path");
44 + Assert::Equal<DWORD>(3, cPaths);
45 + NativeAssert::StringEqual(L"\\\\server\\share\\", rgsczPaths[0]);
46 + NativeAssert::StringEqual(L"\\\\server\\share\\subdir\\", rgsczPaths[1]);
47 + NativeAssert::StringEqual(L"\\\\server\\share\\subdir\\file.txt", rgsczPaths[2]);
48 + ReleaseNullStrArray(rgsczPaths, cPaths);
49 +
50 + hr = PathGetHierarchyArray(L"\\\\server\\share\\subdir\\", &rgsczPaths, &cPaths);
51 + NativeAssert::Succeeded(hr, "Failed to get parent directories array for UNC directory path");
52 + Assert::Equal<DWORD>(2, cPaths);
53 + NativeAssert::StringEqual(L"\\\\server\\share\\", rgsczPaths[0]);
54 + NativeAssert::StringEqual(L"\\\\server\\share\\subdir\\", rgsczPaths[1]);
55 + ReleaseNullStrArray(rgsczPaths, cPaths);
56 +
57 + hr = PathGetHierarchyArray(L"Software\\Microsoft\\Windows\\ValueName", &rgsczPaths, &cPaths);
58 + NativeAssert::Succeeded(hr, "Failed to get parent directories array for UNC directory path");
59 + Assert::Equal<DWORD>(4, cPaths);
60 + NativeAssert::StringEqual(L"Software\\", rgsczPaths[0]);
61 + NativeAssert::StringEqual(L"Software\\Microsoft\\", rgsczPaths[1]);
62 + NativeAssert::StringEqual(L"Software\\Microsoft\\Windows\\", rgsczPaths[2]);
63 + NativeAssert::StringEqual(L"Software\\Microsoft\\Windows\\ValueName", rgsczPaths[3]);
64 + ReleaseNullStrArray(rgsczPaths, cPaths);
65 +
66 + hr = PathGetHierarchyArray(L"Software\\Microsoft\\Windows\\", &rgsczPaths, &cPaths);
67 + NativeAssert::Succeeded(hr, "Failed to get parent directories array for UNC directory path");
68 + Assert::Equal<DWORD>(3, cPaths);
69 + NativeAssert::StringEqual(L"Software\\", rgsczPaths[0]);
70 + NativeAssert::StringEqual(L"Software\\Microsoft\\", rgsczPaths[1]);
71 + NativeAssert::StringEqual(L"Software\\Microsoft\\Windows\\", rgsczPaths[2]);
72 + ReleaseNullStrArray(rgsczPaths, cPaths);
73 + }
74 + finally
75 + {
76 + ReleaseStrArray(rgsczPaths, cPaths);
77 + }
78 + }
79 + };
80 +}
src/test/DUtilUnitTest/SceUtilTest.cpp new
+488
@@ -0,0 +1,488 @@
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 +#include <sqlce_oledb.h>
6 +#include <sceutil.h>
7 +
8 +using namespace System;
9 +using namespace Xunit;
10 +using namespace WixTest;
11 +
12 +#define ASSIGN_INDEX_STRUCT(a, b, c) {a.wzName = c; a.rgColumns = b; a.cColumns = countof(b);};
13 +
14 +namespace DutilTests
15 +{
16 + enum TABLES
17 + {
18 + TABLE_A,
19 + TABLE_COUNT
20 + };
21 +
22 + enum TABLE_A_COLUMNS
23 + {
24 + TABLE_A_KEY,
25 + TABLE_A_BINARY,
26 + TABLE_A_DWORD,
27 + TABLE_A_QWORD,
28 + TABLE_A_BOOL,
29 + TABLE_A_STRING,
30 + TABLE_A_DWORD_NULLABLE,
31 + TABLE_A_INITIAL_COLUMNS,
32 +
33 + TABLE_A_EXTRA_STRING = TABLE_A_INITIAL_COLUMNS,
34 + TABLE_A_FINAL_COLUMNS
35 + };
36 +
37 + struct TableARowValue
38 + {
39 + DWORD dwAutoGenKey;
40 +
41 + BYTE *pbBinary;
42 + DWORD cBinary;
43 +
44 + DWORD dw;
45 + DWORD64 qw;
46 + BOOL f;
47 + LPWSTR scz;
48 +
49 + BOOL fNullablePresent;
50 + DWORD dwNullable;
51 +
52 + BOOL fSchemaV2;
53 + LPWSTR sczExtra;
54 + };
55 +
56 + public ref class SceUtil
57 + {
58 + public:
59 + void ReleaseSceSchema(SCE_DATABASE_SCHEMA *pdsSchema)
60 + {
61 + DWORD dwTable;
62 +
63 + for (dwTable = 0; dwTable < pdsSchema->cTables; ++dwTable)
64 + {
65 + ReleaseNullMem(pdsSchema->rgTables[dwTable].rgColumns);
66 + ReleaseNullMem(pdsSchema->rgTables[dwTable].rgIndexes);
67 + }
68 +
69 + ReleaseMem(pdsSchema->rgTables);
70 +
71 + return;
72 + }
73 +
74 + void SetupSchema(SCE_DATABASE_SCHEMA *pSchema, BOOL fIncludeExtended)
75 + {
76 + pSchema->cTables = TABLE_COUNT;
77 + pSchema->rgTables = static_cast<SCE_TABLE_SCHEMA*>(MemAlloc(TABLE_COUNT * sizeof(SCE_TABLE_SCHEMA), TRUE));
78 + NativeAssert::True(pSchema->rgTables != NULL);
79 +
80 + pSchema->rgTables[TABLE_A].wzName = L"TableA";
81 + pSchema->rgTables[TABLE_A].cColumns = fIncludeExtended ? TABLE_A_FINAL_COLUMNS : TABLE_A_INITIAL_COLUMNS;
82 + pSchema->rgTables[TABLE_A].cIndexes = 2;
83 +
84 + for (DWORD i = 0; i < pSchema->cTables; ++i)
85 + {
86 + pSchema->rgTables[i].rgColumns = static_cast<SCE_COLUMN_SCHEMA*>(MemAlloc(sizeof(SCE_COLUMN_SCHEMA) * pSchema->rgTables[i].cColumns, TRUE));
87 + NativeAssert::True(pSchema->rgTables[i].rgColumns != NULL);
88 +
89 + pSchema->rgTables[i].rgIndexes = static_cast<SCE_INDEX_SCHEMA*>(MemAlloc(sizeof(SCE_COLUMN_SCHEMA) * pSchema->rgTables[i].cIndexes, TRUE));
90 + NativeAssert::True(pSchema->rgTables[i].rgIndexes != NULL);
91 + }
92 +
93 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_KEY].wzName = L"Key";
94 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_KEY].dbtColumnType = DBTYPE_I4;
95 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_KEY].fPrimaryKey = TRUE;
96 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_KEY].fAutoIncrement = TRUE;
97 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_BINARY].wzName = L"Binary";
98 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_BINARY].dbtColumnType = DBTYPE_BYTES;
99 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_DWORD].wzName = L"Dword";
100 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_DWORD].dbtColumnType = DBTYPE_I4;
101 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_QWORD].wzName = L"Qword";
102 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_QWORD].dbtColumnType = DBTYPE_I8;
103 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_BOOL].wzName = L"Bool";
104 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_BOOL].dbtColumnType = DBTYPE_BOOL;
105 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_STRING].wzName = L"String";
106 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_STRING].dbtColumnType = DBTYPE_WSTR;
107 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_DWORD_NULLABLE].wzName = L"Nullable";
108 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_DWORD_NULLABLE].dbtColumnType = DBTYPE_I4;
109 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_DWORD_NULLABLE].fNullable = TRUE;
110 +
111 + if (fIncludeExtended)
112 + {
113 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_EXTRA_STRING].wzName = L"ExtraString";
114 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_EXTRA_STRING].dbtColumnType = DBTYPE_WSTR;
115 + pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_EXTRA_STRING].fNullable = TRUE;
116 + }
117 +
118 + static DWORD rgdwTableA_Index1[] = { TABLE_A_DWORD, TABLE_A_STRING, TABLE_A_QWORD };
119 + static DWORD rgdwTableA_Index2[] = { TABLE_A_DWORD, TABLE_A_STRING };
120 +
121 + ASSIGN_INDEX_STRUCT(pSchema->rgTables[TABLE_A].rgIndexes[0], rgdwTableA_Index1, L"Dword_String_Qword");
122 + ASSIGN_INDEX_STRUCT(pSchema->rgTables[TABLE_A].rgIndexes[1], rgdwTableA_Index2, L"Dword_String");
123 + }
124 +
125 + void SetStructValues(TableARowValue *pValue, BYTE *pbBinary, DWORD cBinary, DWORD dw, DWORD64 qw, BOOL f, LPWSTR scz, DWORD *pdw, LPWSTR sczExtra)
126 + {
127 + pValue->pbBinary = pbBinary;
128 + pValue->cBinary = cBinary;
129 + pValue->dw = dw;
130 + pValue->qw = qw;
131 + pValue->f = f;
132 + pValue->scz = scz;
133 +
134 + if (pdw)
135 + {
136 + pValue->fNullablePresent = TRUE;
137 + pValue->dwNullable = *pdw;
138 + }
139 + else
140 + {
141 + pValue->fNullablePresent = FALSE;
142 + }
143 +
144 + if (sczExtra)
145 + {
146 + pValue->fSchemaV2 = TRUE;
147 + pValue->sczExtra = sczExtra;
148 + }
149 + else
150 + {
151 + pValue->fSchemaV2 = FALSE;
152 + }
153 + }
154 +
155 + void AssertStructValuesSame(TableARowValue *pValueExpected, TableARowValue *pValueOther)
156 + {
157 + NativeAssert::Equal(pValueExpected->cBinary, pValueOther->cBinary);
158 + NativeAssert::True(0 == memcmp(pValueExpected->pbBinary, pValueOther->pbBinary, pValueOther->cBinary));
159 +
160 + NativeAssert::Equal(pValueExpected->dw, pValueOther->dw);
161 + NativeAssert::Equal(pValueExpected->qw, pValueOther->qw);
162 + NativeAssert::Equal(pValueExpected->f, pValueOther->f);
163 + NativeAssert::True(0 == wcscmp(pValueExpected->scz, pValueOther->scz));
164 +
165 + NativeAssert::Equal(pValueExpected->fNullablePresent, pValueOther->fNullablePresent);
166 + if (pValueExpected->fNullablePresent)
167 + {
168 + NativeAssert::Equal(pValueExpected->dwNullable, pValueOther->dwNullable);
169 + }
170 +
171 + NativeAssert::Equal(pValueExpected->fSchemaV2, pValueOther->fSchemaV2);
172 + if (pValueExpected->fSchemaV2)
173 + {
174 + NativeAssert::True(0 == wcscmp(pValueExpected->sczExtra, pValueOther->sczExtra));
175 + }
176 + }
177 +
178 + void InsertRow(SCE_DATABASE *pDatabase, TableARowValue *pValue, BOOL fRollback)
179 + {
180 + HRESULT hr = S_OK;
181 + SCE_ROW_HANDLE sceRow = NULL;
182 +
183 + hr = SceBeginTransaction(pDatabase);
184 + NativeAssert::Succeeded(hr, "Failed to begin transaction");
185 +
186 + hr = ScePrepareInsert(pDatabase, TABLE_A, &sceRow);
187 + NativeAssert::Succeeded(hr, "Failed to prepare to insert row");
188 +
189 + hr = SceSetColumnBinary(sceRow, TABLE_A_BINARY, pValue->pbBinary, pValue->cBinary);
190 + NativeAssert::Succeeded(hr, "Failed to set binary value");
191 +
192 + hr = SceSetColumnDword(sceRow, TABLE_A_DWORD, pValue->dw);
193 + NativeAssert::Succeeded(hr, "Failed to set dword value");
194 +
195 + hr = SceSetColumnQword(sceRow, TABLE_A_QWORD, pValue->qw);
196 + NativeAssert::Succeeded(hr, "Failed to set qword value");
197 +
198 + hr = SceSetColumnBool(sceRow, TABLE_A_BOOL, pValue->f);
199 + NativeAssert::Succeeded(hr, "Failed to set bool value");
200 +
201 + hr = SceSetColumnString(sceRow, TABLE_A_STRING, pValue->scz);
202 + NativeAssert::Succeeded(hr, "Failed to set string value");
203 +
204 + if (pValue->fNullablePresent)
205 + {
206 + hr = SceSetColumnDword(sceRow, TABLE_A_DWORD_NULLABLE, pValue->dwNullable);
207 + NativeAssert::Succeeded(hr, "Failed to set dword value");
208 + }
209 + else
210 + {
211 + hr = SceSetColumnNull(sceRow, TABLE_A_DWORD_NULLABLE);
212 + NativeAssert::Succeeded(hr, "Failed to set null value");
213 + }
214 +
215 + if (pValue->fSchemaV2)
216 + {
217 + hr = SceSetColumnString(sceRow, TABLE_A_EXTRA_STRING, pValue->sczExtra);
218 + NativeAssert::Succeeded(hr, "Failed to set extra string value");
219 + }
220 +
221 + hr = SceFinishUpdate(sceRow);
222 + NativeAssert::Succeeded(hr, "Failed to finish insert");
223 +
224 + if (fRollback)
225 + {
226 + hr = SceRollbackTransaction(pDatabase);
227 + NativeAssert::Succeeded(hr, "Failed to rollback transaction");
228 + }
229 + else
230 + {
231 + hr = SceCommitTransaction(pDatabase);
232 + NativeAssert::Succeeded(hr, "Failed to commit transaction");
233 +
234 + hr = SceGetColumnDword(sceRow, TABLE_A_KEY, &pValue->dwAutoGenKey);
235 + NativeAssert::Succeeded(hr, "Failed to get autogen key after insert");
236 +
237 + NativeAssert::True(pValue->dwAutoGenKey != 0);
238 + }
239 +
240 + ReleaseSceRow(sceRow);
241 + }
242 +
243 + void VerifyRow(TableARowValue *pExpectedValue, SCE_ROW_HANDLE sceRow)
244 + {
245 + HRESULT hr = S_OK;
246 + TableARowValue value = {};
247 +
248 + hr = SceGetColumnBinary(sceRow, TABLE_A_BINARY, &value.pbBinary, &value.cBinary);
249 + NativeAssert::Succeeded(hr, "Failed to get binary value from result row");
250 +
251 + hr = SceGetColumnDword(sceRow, TABLE_A_DWORD, &value.dw);
252 + NativeAssert::Succeeded(hr, "Failed to get dword value from result row");
253 +
254 + hr = SceGetColumnQword(sceRow, TABLE_A_QWORD, &value.qw);
255 + NativeAssert::Succeeded(hr, "Failed to get qword value from result row");
256 +
257 + hr = SceGetColumnBool(sceRow, TABLE_A_BOOL, &value.f);
258 + NativeAssert::Succeeded(hr, "Failed to get bool value from result row");
259 +
260 + hr = SceGetColumnString(sceRow, TABLE_A_STRING, &value.scz);
261 + NativeAssert::Succeeded(hr, "Failed to get string value from result row");
262 +
263 + hr = SceGetColumnDword(sceRow, TABLE_A_DWORD_NULLABLE, &value.dwNullable);
264 + if (hr == E_NOTFOUND)
265 + {
266 + value.fNullablePresent = FALSE;
267 + hr = S_OK;
268 + }
269 + else
270 + {
271 + NativeAssert::Succeeded(hr, "Failed to get string value from result row");
272 + value.fNullablePresent = TRUE;
273 + }
274 +
275 + if (pExpectedValue->fSchemaV2)
276 + {
277 + value.fSchemaV2 = TRUE;
278 + hr = SceGetColumnString(sceRow, TABLE_A_EXTRA_STRING, &value.sczExtra);
279 + NativeAssert::Succeeded(hr, "Failed to get extra string value from result row");
280 + }
281 +
282 + AssertStructValuesSame(pExpectedValue, &value);
283 +
284 + ReleaseNullMem(value.pbBinary);
285 + ReleaseNullStr(value.scz);
286 + }
287 +
288 + void VerifyQuery(TableARowValue **rgExpectedValues, DWORD cExpectedValues, SCE_QUERY_RESULTS_HANDLE queryResults)
289 + {
290 + HRESULT hr = S_OK;
291 + SCE_ROW_HANDLE sceRow = NULL;
292 +
293 + for (DWORD i = 0; i < cExpectedValues; ++i)
294 + {
295 + hr = SceGetNextResultRow(queryResults, &sceRow);
296 + NativeAssert::Succeeded(hr, "Failed to get next result row");
297 +
298 + VerifyRow(rgExpectedValues[i], sceRow);
299 + ReleaseNullSceRow(sceRow);
300 + }
301 +
302 + // No more results
303 + NativeAssert::True(NULL == queryResults || FAILED(SceGetNextResultRow(queryResults, &sceRow)));
304 + }
305 +
306 + void TestIndex(SCE_DATABASE *pDatabase)
307 + {
308 + HRESULT hr = S_OK;
309 + BYTE binary1[50] = { 0x80, 0x70 };
310 + BYTE binary2[40] = { 0x90, 0xAB };
311 + BYTE binary3[40] = { 0x85, 0x88 };
312 + DWORD dwValue1 = 0x55555555, dwValue2 = 0x88888888;
313 + TableARowValue value1 = {}, value2 = {}, value3 = {}, value4 = {}, value5 = {};
314 + SCE_QUERY_HANDLE query = NULL;
315 + SCE_QUERY_RESULTS_HANDLE results = NULL;
316 +
317 + SetStructValues(&value1, static_cast<BYTE *>(binary1), sizeof(binary1), 3, 1, TRUE, L"zzz", &dwValue1, NULL);
318 + SetStructValues(&value2, static_cast<BYTE *>(binary2), sizeof(binary2), 3, 2, TRUE, L"yyy", &dwValue2, NULL);
319 + SetStructValues(&value3, static_cast<BYTE *>(binary3), sizeof(binary3), 3, 3, TRUE, L"xxx", NULL, NULL);
320 + SetStructValues(&value4, static_cast<BYTE *>(binary2), sizeof(binary2), 4, 4, TRUE, L"xyz", &dwValue2, NULL);
321 + SetStructValues(&value5, static_cast<BYTE *>(binary3), sizeof(binary3), 3, 1, TRUE, L"yyy", &dwValue2, NULL);
322 +
323 + // Rollback an insert to confirm the insert doesn't happen and database can still be interacted with normally afterwards
324 + InsertRow(pDatabase, &value1, TRUE);
325 +
326 + InsertRow(pDatabase, &value1, FALSE);
327 + InsertRow(pDatabase, &value2, FALSE);
328 + InsertRow(pDatabase, &value3, FALSE);
329 + InsertRow(pDatabase, &value4, FALSE);
330 + InsertRow(pDatabase, &value5, FALSE);
331 +
332 + NativeAssert::True(value1.dwAutoGenKey != value2.dwAutoGenKey);
333 +
334 + // Test setting 1 column
335 + hr = SceBeginQuery(pDatabase, TABLE_A, 0, &query);
336 + NativeAssert::Succeeded(hr, "Failed to begin query");
337 +
338 + hr = SceSetQueryColumnDword(query, 3);
339 + NativeAssert::Succeeded(hr, "Failed to set query column dword");
340 +
341 + hr = SceRunQueryRange(&query, &results);
342 + NativeAssert::Succeeded(hr, "Failed to run query");
343 + NativeAssert::True(query == NULL);
344 +
345 + TableARowValue *sortedAfterQuery1[] = { &value3, &value5, &value2, &value1 };
346 + VerifyQuery(sortedAfterQuery1, _countof(sortedAfterQuery1), results);
347 + ReleaseNullSceQueryResults(results);
348 +
349 + // Test setting 2 columns, third column is unspecified so results are sorted by it
350 + hr = SceBeginQuery(pDatabase, TABLE_A, 0, &query);
351 + NativeAssert::Succeeded(hr, "Failed to begin query");
352 +
353 + hr = SceSetQueryColumnDword(query, 3);
354 + NativeAssert::Succeeded(hr, "Failed to set query column dword");
355 +
356 + hr = SceSetQueryColumnString(query, L"yyy");
357 + NativeAssert::Succeeded(hr, "Failed to set query column dword");
358 +
359 + hr = SceRunQueryRange(&query, &results);
360 + NativeAssert::Succeeded(hr, "Failed to run query");
361 + NativeAssert::True(query == NULL);
362 +
363 + TableARowValue *sortedAfterQuery2[] = { &value5, &value2 };
364 + VerifyQuery(sortedAfterQuery2, _countof(sortedAfterQuery2), results);
365 + ReleaseNullSceQueryResults(results);
366 +
367 + // Test setting 2 columns, third column of index is unspecified so results are sorted by it
368 + hr = SceBeginQuery(pDatabase, TABLE_A, 0, &query);
369 + NativeAssert::Succeeded(hr, "Failed to begin query");
370 +
371 + hr = SceSetQueryColumnDword(query, 3);
372 + NativeAssert::Succeeded(hr, "Failed to set query column dword");
373 +
374 + hr = SceSetQueryColumnString(query, L"yyy");
375 + NativeAssert::Succeeded(hr, "Failed to set query column dword");
376 +
377 + hr = SceRunQueryRange(&query, &results);
378 + NativeAssert::Succeeded(hr, "Failed to run query");
379 + NativeAssert::True(query == NULL);
380 +
381 + TableARowValue *sortedAfterQuery3[] = { &value5, &value2 };
382 + VerifyQuery(sortedAfterQuery3, _countof(sortedAfterQuery3), results);
383 + ReleaseNullSceQueryResults(results);
384 +
385 + // Test setting 2 columns in a different (2 column) index, so there is no 3rd column in index to sort by
386 + hr = SceBeginQuery(pDatabase, TABLE_A, 1, &query);
387 + NativeAssert::Succeeded(hr, "Failed to begin query");
388 +
389 + hr = SceSetQueryColumnDword(query, 3);
390 + NativeAssert::Succeeded(hr, "Failed to set query column dword");
391 +
392 + hr = SceSetQueryColumnString(query, L"yyy");
393 + NativeAssert::Succeeded(hr, "Failed to set query column dword");
394 +
395 + hr = SceRunQueryRange(&query, &results);
396 + NativeAssert::Succeeded(hr, "Failed to run query");
397 + NativeAssert::True(query == NULL);
398 +
399 + TableARowValue *sortedAfterQuery4[] = { &value2, &value5 };
400 + VerifyQuery(sortedAfterQuery4, _countof(sortedAfterQuery4), results);
401 + ReleaseNullSceQueryResults(results);
402 + }
403 +
404 + void TestReadWriteSchemaV2(SCE_DATABASE *pDatabase)
405 + {
406 + HRESULT hr = S_OK;
407 + BYTE binary1[40] = { 0x55, 0x44 };
408 + DWORD dwValue1 = 58;
409 + TableARowValue value1 = {};
410 + SCE_QUERY_HANDLE query = NULL;
411 + SCE_ROW_HANDLE row = NULL;
412 +
413 + SetStructValues(&value1, static_cast<BYTE *>(binary1), sizeof(binary1), 5, 1, TRUE, L"zzz", &dwValue1, L"newextrastring");
414 +
415 + InsertRow(pDatabase, &value1, FALSE);
416 +
417 + // Test setting 1 column
418 + hr = SceBeginQuery(pDatabase, TABLE_A, 0, &query);
419 + NativeAssert::Succeeded(hr, "Failed to begin query");
420 +
421 + hr = SceSetQueryColumnDword(query, 5);
422 + NativeAssert::Succeeded(hr, "Failed to set query column dword");
423 +
424 + hr = SceRunQueryExact(&query, &row);
425 + NativeAssert::Succeeded(hr, "Failed to run query exact");
426 +
427 + VerifyRow(&value1, row);
428 + }
429 +
430 + [Fact]
431 + void SceUtilTest()
432 + {
433 + HRESULT hr = S_OK;
434 + BOOL fComInitialized = FALSE;
435 + LPWSTR sczDbPath = NULL;
436 + SCE_DATABASE *pDatabase = NULL;
437 + SCE_DATABASE_SCHEMA schema1 = {};
438 + SCE_DATABASE_SCHEMA schema2 = {};
439 +
440 + try
441 + {
442 + hr = ::CoInitialize(0);
443 + NativeAssert::Succeeded(hr, "Failed to initialize COM");
444 + fComInitialized = TRUE;
445 +
446 + SetupSchema(&schema1, FALSE);
447 + SetupSchema(&schema2, TRUE);
448 +
449 + hr = PathExpand(&sczDbPath, L"%TEMP%\\SceUtilTest\\UnitTest.sdf", PATH_EXPAND_ENVIRONMENT);
450 + NativeAssert::Succeeded(hr, "Failed to get path to test database");
451 +
452 + FileEnsureDelete(sczDbPath);
453 +
454 + hr = SceEnsureDatabase(sczDbPath, L"sqlceoledb40.dll", L"Test", 1, &schema1, &pDatabase);
455 + NativeAssert::Succeeded(hr, "Failed to ensure database schema");
456 +
457 + TestIndex(pDatabase);
458 +
459 + hr = SceCloseDatabase(pDatabase);
460 + pDatabase = NULL;
461 + NativeAssert::Succeeded(hr, "Failed to close database");
462 +
463 + // Add column to schema
464 + hr = SceEnsureDatabase(sczDbPath, L"sqlceoledb40.dll", L"Test", 1, &schema2, &pDatabase);
465 + NativeAssert::Succeeded(hr, "Failed to ensure database schema");
466 +
467 + TestReadWriteSchemaV2(pDatabase);
468 + }
469 + finally
470 + {
471 + ReleaseSceSchema(&schema1);
472 + ReleaseSceSchema(&schema2);
473 +
474 + if (NULL != pDatabase)
475 + {
476 + hr = SceCloseDatabase(pDatabase);
477 + NativeAssert::Succeeded(hr, "Failed to close database");
478 + }
479 + ReleaseStr(sczDbPath);
480 +
481 + if (fComInitialized)
482 + {
483 + ::CoUninitialize();
484 + }
485 + }
486 + }
487 + };
488 +}
src/test/DUtilUnitTest/StrUtilTest.cpp new
+184
@@ -0,0 +1,184 @@
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;
6 +using namespace Xunit;
7 +using namespace WixTest;
8 +
9 +namespace DutilTests
10 +{
11 + public ref class StrUtil
12 + {
13 + public:
14 + [Fact]
15 + void StrUtilFormattedTest()
16 + {
17 + HRESULT hr = S_OK;
18 + LPWSTR sczText = NULL;
19 +
20 + try
21 + {
22 + hr = StrAllocFormatted(&sczText, L"%hs - %ls - %u", "ansi string", L"unicode string", 1234);
23 + NativeAssert::Succeeded(hr, "Failed to format string.");
24 + NativeAssert::StringEqual(L"ansi string - unicode string - 1234", sczText);
25 +
26 + ReleaseNullStr(sczText);
27 +
28 + hr = StrAllocString(&sczText, L"repeat", 0);
29 + NativeAssert::Succeeded(hr, "Failed to allocate string.");
30 +
31 + hr = StrAllocFormatted(&sczText, L"%ls and %ls", sczText, sczText);
32 + NativeAssert::Succeeded(hr, "Failed to format string unto itself.");
33 + NativeAssert::StringEqual(L"repeat and repeat", sczText);
34 + }
35 + finally
36 + {
37 + ReleaseStr(sczText);
38 + }
39 + }
40 +
41 + [Fact]
42 + void StrUtilTrimTest()
43 + {
44 + TestTrim(L"", L"");
45 + TestTrim(L"Blah", L"Blah");
46 + TestTrim(L"\t\t\tBlah", L"Blah");
47 + TestTrim(L"\t Blah ", L"Blah");
48 + TestTrim(L"Blah ", L"Blah");
49 + TestTrim(L"\t Spaces \t Between \t", L"Spaces \t Between");
50 + TestTrim(L" \t\t\t ", L"");
51 +
52 + TestTrimAnsi("", "");
53 + TestTrimAnsi("Blah", "Blah");
54 + TestTrimAnsi("\t\t\tBlah", "Blah");
55 + TestTrimAnsi(" Blah ", "Blah");
56 + TestTrimAnsi("Blah ", "Blah");
57 + TestTrimAnsi("\t Spaces \t Between \t", "Spaces \t Between");
58 + TestTrimAnsi(" \t\t\t ", "");
59 + }
60 +
61 + [Fact]
62 + void StrUtilConvertTest()
63 + {
64 + char a[] = { 'a', 'b', 'C', 'd', '\0', '\0' };
65 +
66 + TestStrAllocStringAnsi(a, 5, L"abCd");
67 + TestStrAllocStringAnsi(a, 4, L"abCd");
68 + TestStrAllocStringAnsi(a, 3, L"abC");
69 + TestStrAllocStringAnsi(a, 2, L"ab");
70 + TestStrAllocStringAnsi(a, 1, L"a");
71 + TestStrAllocStringAnsi(a, 0, L"abCd");
72 +
73 + wchar_t b[] = { L'a', L'b', L'C', L'd', L'\0', L'\0' };
74 +
75 + TestStrAnsiAllocString(b, 5, "abCd");
76 + TestStrAnsiAllocString(b, 4, "abCd");
77 + TestStrAnsiAllocString(b, 3, "abC");
78 + TestStrAnsiAllocString(b, 2, "ab");
79 + TestStrAnsiAllocString(b, 1, "a");
80 + TestStrAnsiAllocString(b, 0, "abCd");
81 + }
82 +
83 + private:
84 + void TestTrim(LPCWSTR wzInput, LPCWSTR wzExpectedResult)
85 + {
86 + HRESULT hr = S_OK;
87 + LPWSTR sczOutput = NULL;
88 +
89 + try
90 + {
91 + hr = StrTrimWhitespace(&sczOutput, wzInput);
92 + NativeAssert::Succeeded(hr, "Failed to trim whitespace from string: {0}", wzInput);
93 +
94 + if (0 != wcscmp(wzExpectedResult, sczOutput))
95 + {
96 + hr = E_FAIL;
97 + ExitOnFailure(hr, "Trimmed string \"%ls\", expected result \"%ls\", actual result \"%ls\"", wzInput, wzExpectedResult, sczOutput);
98 + }
99 + }
100 + finally
101 + {
102 + ReleaseStr(sczOutput);
103 + }
104 +
105 + LExit:
106 + return;
107 + }
108 +
109 + void TestTrimAnsi(LPCSTR szInput, LPCSTR szExpectedResult)
110 + {
111 + HRESULT hr = S_OK;
112 + LPSTR sczOutput = NULL;
113 +
114 + try
115 + {
116 + hr = StrAnsiTrimWhitespace(&sczOutput, szInput);
117 + NativeAssert::Succeeded(hr, "Failed to trim whitespace from string: \"{0}\"", szInput);
118 +
119 + if (0 != strcmp(szExpectedResult, sczOutput))
120 + {
121 + hr = E_FAIL;
122 + ExitOnFailure(hr, "Trimmed string \"%hs\", expected result \"%hs\", actual result \"%hs\"", szInput, szExpectedResult, sczOutput);
123 + }
124 + }
125 + finally
126 + {
127 + ReleaseStr(sczOutput);
128 + }
129 +
130 + LExit:
131 + return;
132 + }
133 +
134 + void TestStrAllocStringAnsi(LPCSTR szSource, DWORD cchSource, LPCWSTR wzExpectedResult)
135 + {
136 + HRESULT hr = S_OK;
137 + LPWSTR sczOutput = NULL;
138 +
139 + try
140 + {
141 + hr = StrAllocStringAnsi(&sczOutput, szSource, cchSource, CP_UTF8);
142 + NativeAssert::Succeeded(hr, "Failed to call StrAllocStringAnsi on string: \"{0}\"", szSource);
143 +
144 + if (0 != wcscmp(sczOutput, wzExpectedResult))
145 + {
146 + hr = E_FAIL;
147 + ExitOnFailure(hr, "String doesn't match, expected result \"%ls\", actual result \"%ls\"", wzExpectedResult, sczOutput);
148 + }
149 + }
150 + finally
151 + {
152 + ReleaseStr(sczOutput);
153 + }
154 +
155 + LExit:
156 + return;
157 + }
158 +
159 + void TestStrAnsiAllocString(LPWSTR wzSource, DWORD cchSource, LPCSTR szExpectedResult)
160 + {
161 + HRESULT hr = S_OK;
162 + LPSTR sczOutput = NULL;
163 +
164 + try
165 + {
166 + hr = StrAnsiAllocString(&sczOutput, wzSource, cchSource, CP_UTF8);
167 + NativeAssert::Succeeded(hr, "Failed to call StrAllocStringAnsi on string: \"{0}\"", wzSource);
168 +
169 + if (0 != strcmp(sczOutput, szExpectedResult))
170 + {
171 + hr = E_FAIL;
172 + ExitOnFailure(hr, "String doesn't match, expected result \"%hs\", actual result \"%hs\"", szExpectedResult, sczOutput);
173 + }
174 + }
175 + finally
176 + {
177 + ReleaseStr(sczOutput);
178 + }
179 +
180 + LExit:
181 + return;
182 + }
183 + };
184 +}
src/test/DUtilUnitTest/UnitTest.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 "UnitTest.dll"
5 +#define VER_INTERNAL_NAME "setup"
6 +#define VER_FILE_DESCRIPTION "WiX Toolset Bootstrapper unit tests"
7 +#include "wix.rc"
src/test/DUtilUnitTest/UriUtilTest.cpp new
+96
@@ -0,0 +1,96 @@
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;
6 +using namespace System::Text;
7 +using namespace System::Collections::Generic;
8 +using namespace Xunit;
9 +
10 +namespace CfgTests
11 +{
12 + public ref class UriUtil
13 + {
14 + public:
15 + [Fact]
16 + void UriProtocolTest()
17 + {
18 + HRESULT hr = S_OK;
19 +
20 + LPCWSTR uri = L"https://localhost/";
21 + URI_PROTOCOL uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
22 + hr = UriProtocol(uri, &uriProtocol);
23 + ExitOnFailure(hr, "Failed to determine UriProtocol");
24 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_HTTPS, (int)uriProtocol);
25 +
26 + uri = L"HTTPS://localhost/";
27 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
28 + hr = UriProtocol(uri, &uriProtocol);
29 + ExitOnFailure(hr, "Failed to determine UriProtocol");
30 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_HTTPS, (int)uriProtocol);
31 +
32 + uri = L"HtTpS://localhost/";
33 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
34 + hr = UriProtocol(uri, &uriProtocol);
35 + ExitOnFailure(hr, "Failed to determine UriProtocol");
36 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_HTTPS, (int)uriProtocol);
37 +
38 + uri = L"HTTP://localhost/";
39 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
40 + hr = UriProtocol(uri, &uriProtocol);
41 + ExitOnFailure(hr, "Failed to determine UriProtocol");
42 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_HTTP, (int)uriProtocol);
43 +
44 + uri = L"http://localhost/";
45 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
46 + hr = UriProtocol(uri, &uriProtocol);
47 + ExitOnFailure(hr, "Failed to determine UriProtocol");
48 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_HTTP, (int)uriProtocol);
49 +
50 + uri = L"HtTp://localhost/";
51 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
52 + hr = UriProtocol(uri, &uriProtocol);
53 + ExitOnFailure(hr, "Failed to determine UriProtocol");
54 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_HTTP, (int)uriProtocol);
55 +
56 + uri = L"file://localhost/";
57 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
58 + hr = UriProtocol(uri, &uriProtocol);
59 + ExitOnFailure(hr, "Failed to determine UriProtocol");
60 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_FILE, (int)uriProtocol);
61 +
62 + uri = L"FILE://localhost/";
63 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
64 + hr = UriProtocol(uri, &uriProtocol);
65 + ExitOnFailure(hr, "Failed to determine UriProtocol");
66 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_FILE, (int)uriProtocol);
67 +
68 + uri = L"FiLe://localhost/";
69 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
70 + hr = UriProtocol(uri, &uriProtocol);
71 + ExitOnFailure(hr, "Failed to determine UriProtocol");
72 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_FILE, (int)uriProtocol);
73 +
74 + uri = L"FTP://localhost/";
75 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
76 + hr = UriProtocol(uri, &uriProtocol);
77 + ExitOnFailure(hr, "Failed to determine UriProtocol");
78 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_FTP, (int)uriProtocol);
79 +
80 + uri = L"ftp://localhost/";
81 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
82 + hr = UriProtocol(uri, &uriProtocol);
83 + ExitOnFailure(hr, "Failed to determine UriProtocol");
84 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_FTP, (int)uriProtocol);
85 +
86 + uri = L"FtP://localhost/";
87 + uriProtocol = URI_PROTOCOL::URI_PROTOCOL_UNKNOWN;
88 + hr = UriProtocol(uri, &uriProtocol);
89 + ExitOnFailure(hr, "Failed to determine UriProtocol");
90 + Assert::Equal((int)URI_PROTOCOL::URI_PROTOCOL_FTP, (int)uriProtocol);
91 +
92 + LExit:
93 + ;
94 + }
95 + };
96 +}
src/test/DUtilUnitTest/VarHelpers.cpp new
+147
@@ -0,0 +1,147 @@
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 DutilTests
7 +{
8 + using namespace System;
9 + using namespace WixTest;
10 +
11 + void VarSetStringHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, LPCWSTR wzValue)
12 + {
13 + HRESULT hr = S_OK;
14 +
15 + hr = VarSetString(pVariables, wzVariable, wzValue);
16 + NativeAssert::Succeeded(hr, "Failed to set {0} to: {1}", wzVariable, wzValue);
17 + }
18 +
19 + void VarSetNumericHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, LONGLONG llValue)
20 + {
21 + HRESULT hr = S_OK;
22 +
23 + hr = VarSetNumeric(pVariables, wzVariable, llValue);
24 + NativeAssert::Succeeded(hr, gcnew String("Failed to set {0} to: {1}"), gcnew String(wzVariable), llValue);
25 + }
26 +
27 + void VarSetVersionHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, DWORD64 qwValue)
28 + {
29 + HRESULT hr = S_OK;
30 +
31 + hr = VarSetVersion(pVariables, wzVariable, qwValue);
32 + NativeAssert::Succeeded(hr, gcnew String("Failed to set {0} to: 0x{1:X8}"), gcnew String(wzVariable), qwValue);
33 + }
34 +
35 + void VarGetStringHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, LPCWSTR wzExpectedValue)
36 + {
37 + HRESULT hr = S_OK;
38 + LPWSTR scz = NULL;
39 +
40 + try
41 + {
42 + hr = VarGetString(pVariables, wzVariable, &scz);
43 + NativeAssert::Succeeded(hr, "Failed to get: {0}", wzVariable);
44 + NativeAssert::StringEqual(wzExpectedValue, scz);
45 + }
46 + finally
47 + {
48 + ReleaseStr(scz);
49 + }
50 + }
51 +
52 + void VarGetNumericHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, LONGLONG llExpectedValue)
53 + {
54 + HRESULT hr = S_OK;
55 + LONGLONG llValue = 0;
56 +
57 + hr = VarGetNumeric(pVariables, wzVariable, &llValue);
58 + NativeAssert::Succeeded(hr, "Failed to get: {0}", wzVariable);
59 + NativeAssert::Equal(llExpectedValue, llValue);
60 + }
61 +
62 + void VarGetVersionHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, DWORD64 qwExpectedValue)
63 + {
64 + HRESULT hr = S_OK;
65 + DWORD64 qwValue = 0;
66 +
67 + hr = VarGetVersion(pVariables, wzVariable, &qwValue);
68 + NativeAssert::Succeeded(hr, "Failed to get: {0}", wzVariable);
69 + NativeAssert::Equal(qwExpectedValue, qwValue);
70 + }
71 +
72 + void VarGetFormattedHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, LPCWSTR wzExpectedValue)
73 + {
74 + HRESULT hr = S_OK;
75 + LPWSTR scz = NULL;
76 +
77 + try
78 + {
79 + hr = VarGetFormatted(pVariables, wzVariable, &scz);
80 + NativeAssert::Succeeded(hr, "Failed to get formatted: {0}", wzVariable);
81 + NativeAssert::StringEqual(wzExpectedValue, scz);
82 + }
83 + finally
84 + {
85 + ReleaseStr(scz);
86 + }
87 + }
88 +
89 + void VarFormatStringHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzIn, LPCWSTR wzExpectedValue)
90 + {
91 + HRESULT hr = S_OK;
92 + LPWSTR scz = NULL;
93 +
94 + try
95 + {
96 + hr = VarFormatString(pVariables, wzIn, &scz, NULL);
97 + NativeAssert::Succeeded(hr, "Failed to format string: '{0}'", wzIn);
98 + NativeAssert::StringEqual(wzExpectedValue, scz);
99 + }
100 + finally
101 + {
102 + ReleaseStr(scz);
103 + }
104 + }
105 +
106 + void VarEscapeStringHelper(LPCWSTR wzIn, LPCWSTR wzExpectedValue)
107 + {
108 + HRESULT hr = S_OK;
109 + LPWSTR scz = NULL;
110 +
111 + try
112 + {
113 + hr = VarEscapeString(wzIn, &scz);
114 + NativeAssert::Succeeded(hr, "Failed to escape string: '{0}'", wzIn);
115 + NativeAssert::StringEqual(wzExpectedValue, scz);
116 + }
117 + finally
118 + {
119 + ReleaseStr(scz);
120 + }
121 + }
122 +
123 + bool EvaluateConditionHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzCondition)
124 + {
125 + HRESULT hr = S_OK;
126 + BOOL f = FALSE;
127 +
128 + hr = CondEvaluate(pVariables, wzCondition, &f);
129 + NativeAssert::Succeeded(hr, "Failed to evaluate condition: '{0}'", wzCondition);
130 +
131 + return f ? true : false;
132 + }
133 +
134 + bool EvaluateFailureConditionHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzCondition)
135 + {
136 + HRESULT hr = S_OK;
137 + BOOL f = FALSE;
138 +
139 + hr = CondEvaluate(pVariables, wzCondition, &f);
140 + if (E_INVALIDDATA != hr)
141 + {
142 + NativeAssert::Succeeded(hr, "Failed to evaluate condition: '{0}'", wzCondition);
143 + }
144 +
145 + return E_INVALIDDATA == hr ? true : false;
146 + }
147 +}
src/test/DUtilUnitTest/VarHelpers.h new
+20
@@ -0,0 +1,20 @@
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 DutilTests
6 +{
7 +
8 +void VarSetStringHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, LPCWSTR wzValue);
9 +void VarSetNumericHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, LONGLONG llValue);
10 +void VarSetVersionHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, DWORD64 qwValue);
11 +void VarGetStringHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, LPCWSTR wzExpectedValue);
12 +void VarGetNumericHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, LONGLONG llExpectedValue);
13 +void VarGetVersionHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, DWORD64 qwExpectedValue);
14 +void VarGetFormattedHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzVariable, LPCWSTR wzExpectedValue);
15 +void VarFormatStringHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzIn, LPCWSTR wzExpectedValue);
16 +void VarEscapeStringHelper(LPCWSTR wzIn, LPCWSTR wzExpectedValue);
17 +bool EvaluateConditionHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzCondition);
18 +bool EvaluateFailureConditionHelper(VARIABLES_HANDLE pVariables, LPCWSTR wzCondition);
19 +
20 +}
src/test/DUtilUnitTest/VarUtilTest.cpp new
+532
@@ -0,0 +1,532 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +#include "precomp.h"
4 +#undef GetTempPath
5 +#undef GetEnvironmentVariable
6 +
7 +using namespace System;
8 +using namespace Xunit;
9 +using namespace WixTest;
10 +
11 +namespace DutilTests
12 +{
13 + typedef struct _VarUtilContext
14 + {
15 + DWORD dw;
16 + LPWSTR scz;
17 + } VarUtilContext;
18 +
19 + void FreeValueContext(LPVOID pvContext)
20 + {
21 + if (pvContext)
22 + {
23 + MemFree(pvContext);
24 + }
25 + }
26 +
27 + public ref class VarUtil
28 + {
29 + public:
30 + [NamedFact(Skip = "varutil Not Implemented Yet.")]
31 + void VarUtilBasicTest()
32 + {
33 + HRESULT hr = S_OK;
34 + VARIABLES_HANDLE pVariables = NULL;
35 +
36 + try
37 + {
38 + hr = VarCreate(&pVariables);
39 + NativeAssert::Succeeded(hr, "Failed to initialize variables.");
40 +
41 + // set variables
42 + VarSetStringHelper(pVariables, L"PROP1", L"VAL1");
43 + VarSetNumericHelper(pVariables, L"PROP2", 2);
44 + VarSetStringHelper(pVariables, L"PROP5", L"VAL5");
45 + VarSetStringHelper(pVariables, L"PROP3", L"VAL3");
46 + VarSetStringHelper(pVariables, L"PROP4", L"VAL4");
47 + VarSetStringHelper(pVariables, L"PROP6", L"VAL6");
48 + VarSetStringHelper(pVariables, L"PROP7", L"7");
49 + VarSetVersionHelper(pVariables, L"PROP8", MAKEQWORDVERSION(1, 1, 0, 0));
50 +
51 + // set overwritten variables
52 + VarSetStringHelper(pVariables, L"OVERWRITTEN_STRING", L"ORIGINAL");
53 + VarSetNumericHelper(pVariables, L"OVERWRITTEN_STRING", 42);
54 +
55 + VarSetNumericHelper(pVariables, L"OVERWRITTEN_NUMBER", 5);
56 + VarSetStringHelper(pVariables, L"OVERWRITTEN_NUMBER", L"NEW");
57 +
58 + // get and verify variable values
59 + VarGetStringHelper(pVariables, L"PROP1", L"VAL1");
60 + VarGetNumericHelper(pVariables, L"PROP2", 2);
61 + VarGetStringHelper(pVariables, L"PROP2", L"2");
62 + VarGetStringHelper(pVariables, L"PROP3", L"VAL3");
63 + VarGetStringHelper(pVariables, L"PROP4", L"VAL4");
64 + VarGetStringHelper(pVariables, L"PROP5", L"VAL5");
65 + VarGetStringHelper(pVariables, L"PROP6", L"VAL6");
66 + VarGetNumericHelper(pVariables, L"PROP7", 7);
67 + VarGetVersionHelper(pVariables, L"PROP8", MAKEQWORDVERSION(1, 1, 0, 0));
68 + VarGetStringHelper(pVariables, L"PROP8", L"1.1.0.0");
69 +
70 + VarGetNumericHelper(pVariables, L"OVERWRITTEN_STRING", 42);
71 + VarGetStringHelper(pVariables, L"OVERWRITTEN_NUMBER", L"NEW");
72 + }
73 + finally
74 + {
75 + ReleaseVariables(pVariables);
76 + }
77 + }
78 +
79 + [NamedFact(Skip = "varutil Not Implemented Yet.")]
80 + void VarUtilFormatTest()
81 + {
82 + HRESULT hr = S_OK;
83 + VARIABLES_HANDLE pVariables = NULL;
84 + LPWSTR scz = NULL;
85 + DWORD cch = 0;
86 + try
87 + {
88 + hr = VarCreate(&pVariables);
89 + NativeAssert::Succeeded(hr, "Failed to initialize variables.");
90 +
91 + // set variables
92 + VarSetStringHelper(pVariables, L"PROP1", L"VAL1");
93 + VarSetStringHelper(pVariables, L"PROP2", L"VAL2");
94 + VarSetNumericHelper(pVariables, L"PROP3", 3);
95 +
96 + // test string formatting
97 + VarFormatStringHelper(pVariables, L"NOPROP", L"NOPROP");
98 + VarFormatStringHelper(pVariables, L"[PROP1]", L"VAL1");
99 + VarFormatStringHelper(pVariables, L" [PROP1] ", L" VAL1 ");
100 + VarFormatStringHelper(pVariables, L"PRE [PROP1]", L"PRE VAL1");
101 + VarFormatStringHelper(pVariables, L"[PROP1] POST", L"VAL1 POST");
102 + VarFormatStringHelper(pVariables, L"PRE [PROP1] POST", L"PRE VAL1 POST");
103 + VarFormatStringHelper(pVariables, L"[PROP1] MID [PROP2]", L"VAL1 MID VAL2");
104 + VarFormatStringHelper(pVariables, L"[NONE]", L"");
105 + VarFormatStringHelper(pVariables, L"[prop1]", L"");
106 + VarFormatStringHelper(pVariables, L"[\\[]", L"[");
107 + VarFormatStringHelper(pVariables, L"[\\]]", L"]");
108 + VarFormatStringHelper(pVariables, L"[]", L"[]");
109 + VarFormatStringHelper(pVariables, L"[NONE", L"[NONE");
110 + VarGetFormattedHelper(pVariables, L"PROP2", L"VAL2");
111 + VarGetFormattedHelper(pVariables, L"PROP3", L"3");
112 +
113 + hr = VarFormatString(pVariables, L"PRE [PROP1] POST", &scz, &cch);
114 + NativeAssert::Succeeded(hr, "Failed to format string.");
115 +
116 + Assert::Equal<DWORD>(lstrlenW(scz), cch);
117 +
118 + hr = VarFormatString(pVariables, L"PRE [PROP1] POST", NULL, &cch);
119 + NativeAssert::Succeeded(hr, "Failed to format string.");
120 +
121 + Assert::Equal<DWORD>(lstrlenW(scz), cch);
122 + }
123 + finally
124 + {
125 + ReleaseVariables(pVariables);
126 + ReleaseStr(scz);
127 + }
128 + }
129 +
130 + [NamedFact(Skip = "varutil Not Implemented Yet.")]
131 + void VarUtilEscapeTest()
132 + {
133 + // test string escaping
134 + VarEscapeStringHelper(L"[", L"[\\[]");
135 + VarEscapeStringHelper(L"]", L"[\\]]");
136 + VarEscapeStringHelper(L" [TEXT] ", L" [\\[]TEXT[\\]] ");
137 + }
138 +
139 + [NamedFact(Skip = "varutil Not Implemented Yet.")]
140 + void VarUtilConditionTest()
141 + {
142 + HRESULT hr = S_OK;
143 + VARIABLES_HANDLE pVariables = NULL;
144 +
145 + try
146 + {
147 + hr = VarCreate(&pVariables);
148 + NativeAssert::Succeeded(hr, "Failed to initialize variables.");
149 +
150 + // set variables
151 + VarSetStringHelper(pVariables, L"PROP1", L"VAL1");
152 + VarSetStringHelper(pVariables, L"PROP2", L"VAL2");
153 + VarSetStringHelper(pVariables, L"PROP3", L"VAL3");
154 + VarSetStringHelper(pVariables, L"PROP4", L"BEGIN MID END");
155 + VarSetNumericHelper(pVariables, L"PROP5", 5);
156 + VarSetNumericHelper(pVariables, L"PROP6", 6);
157 + VarSetStringHelper(pVariables, L"PROP7", L"");
158 + VarSetNumericHelper(pVariables, L"PROP8", 0);
159 + VarSetStringHelper(pVariables, L"_PROP9", L"VAL9");
160 + VarSetNumericHelper(pVariables, L"PROP10", -10);
161 + VarSetNumericHelper(pVariables, L"PROP11", 9223372036854775807ll);
162 + VarSetNumericHelper(pVariables, L"PROP12", -9223372036854775808ll);
163 + VarSetNumericHelper(pVariables, L"PROP13", 0x00010000);
164 + VarSetNumericHelper(pVariables, L"PROP14", 0x00000001);
165 + VarSetNumericHelper(pVariables, L"PROP15", 0x00010001);
166 + VarSetVersionHelper(pVariables, L"PROP16", MAKEQWORDVERSION(0, 0, 0, 0));
167 + VarSetVersionHelper(pVariables, L"PROP17", MAKEQWORDVERSION(1, 0, 0, 0));
168 + VarSetVersionHelper(pVariables, L"PROP18", MAKEQWORDVERSION(1, 1, 0, 0));
169 + VarSetVersionHelper(pVariables, L"PROP19", MAKEQWORDVERSION(1, 1, 1, 0));
170 + VarSetVersionHelper(pVariables, L"PROP20", MAKEQWORDVERSION(1, 1, 1, 1));
171 + VarSetNumericHelper(pVariables, L"vPROP21", 1);
172 + VarSetVersionHelper(pVariables, L"PROP22", MAKEQWORDVERSION(65535, 65535, 65535, 65535));
173 + VarSetStringHelper(pVariables, L"PROP23", L"1.1.1");
174 +
175 + // test conditions
176 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1"));
177 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5"));
178 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP7"));
179 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP8"));
180 + Assert::True(EvaluateConditionHelper(pVariables, L"_PROP9"));
181 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP16"));
182 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP17"));
183 +
184 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\""));
185 + Assert::False(EvaluateConditionHelper(pVariables, L"NONE = \"NOT\""));
186 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 <> \"VAL1\""));
187 + Assert::True(EvaluateConditionHelper(pVariables, L"NONE <> \"NOT\""));
188 +
189 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 ~= \"val1\""));
190 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"val1\""));
191 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 ~<> \"val1\""));
192 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 <> \"val1\""));
193 +
194 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 = 5"));
195 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 = 0"));
196 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 <> 5"));
197 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 <> 0"));
198 +
199 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP10 = -10"));
200 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP10 <> -10"));
201 +
202 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP17 = v1"));
203 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP17 = v0"));
204 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP17 <> v1"));
205 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP17 <> v0"));
206 +
207 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP16 = v0"));
208 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP17 = v1"));
209 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP18 = v1.1"));
210 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP19 = v1.1.1"));
211 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP20 = v1.1.1.1"));
212 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP20 = v1.1.1.1.0"));
213 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP20 = v1.1.1.1.1"));
214 + Assert::True(EvaluateConditionHelper(pVariables, L"vPROP21 = 1"));
215 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP23 = v1.1.1"));
216 + Assert::True(EvaluateConditionHelper(pVariables, L"v1.1.1 = PROP23"));
217 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 <> v1.1.1"));
218 + Assert::True(EvaluateConditionHelper(pVariables, L"v1.1.1 <> PROP1"));
219 +
220 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP11 = 9223372036854775806"));
221 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP11 = 9223372036854775807"));
222 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP11 = 9223372036854775808"));
223 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP11 = 92233720368547758070000"));
224 +
225 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP12 = -9223372036854775807"));
226 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP12 = -9223372036854775808"));
227 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP12 = -9223372036854775809"));
228 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP12 = -92233720368547758080000"));
229 +
230 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP22 = v65535.65535.65535.65535"));
231 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP22 = v65536.65535.65535.65535"));
232 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"PROP22 = v65535.655350000.65535.65535"));
233 +
234 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 < 6"));
235 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 < 5"));
236 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 > 4"));
237 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 > 5"));
238 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 <= 6"));
239 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 <= 5"));
240 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 <= 4"));
241 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 >= 4"));
242 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP5 >= 5"));
243 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP5 >= 6"));
244 +
245 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP4 << \"BEGIN\""));
246 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP4 << \"END\""));
247 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP4 >> \"END\""));
248 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP4 >> \"BEGIN\""));
249 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP4 >< \"MID\""));
250 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP4 >< \"NONE\""));
251 +
252 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP16 < v1.1"));
253 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP16 < v0"));
254 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP17 > v0.12"));
255 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP17 > v1"));
256 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP18 >= v1.0"));
257 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP18 >= v1.1"));
258 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP18 >= v2.1"));
259 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP19 <= v1.1234.1"));
260 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP19 <= v1.1.1"));
261 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP19 <= v1.0.123"));
262 +
263 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP6 = \"6\""));
264 + Assert::True(EvaluateConditionHelper(pVariables, L"\"6\" = PROP6"));
265 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP6 = \"ABC\""));
266 + Assert::False(EvaluateConditionHelper(pVariables, L"\"ABC\" = PROP6"));
267 + Assert::False(EvaluateConditionHelper(pVariables, L"\"ABC\" = PROP6"));
268 +
269 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP13 << 1"));
270 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP13 << 0"));
271 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP14 >> 1"));
272 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP14 >> 0"));
273 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP15 >< 65537"));
274 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP15 >< 0"));
275 +
276 + Assert::False(EvaluateConditionHelper(pVariables, L"NOT PROP1"));
277 + Assert::True(EvaluateConditionHelper(pVariables, L"NOT (PROP1 <> \"VAL1\")"));
278 +
279 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND PROP2 = \"VAL2\""));
280 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
281 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"NOT\" AND PROP2 = \"VAL2\""));
282 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"NOT\" AND PROP2 = \"NOT\""));
283 +
284 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" OR PROP2 = \"VAL2\""));
285 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" OR PROP2 = \"NOT\""));
286 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"NOT\" OR PROP2 = \"VAL2\""));
287 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"NOT\" OR PROP2 = \"NOT\""));
288 +
289 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND PROP2 = \"VAL2\" OR PROP3 = \"NOT\""));
290 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\" OR PROP3 = \"VAL3\""));
291 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND PROP2 = \"NOT\" OR PROP3 = \"NOT\""));
292 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP1 = \"VAL1\" AND (PROP2 = \"NOT\" OR PROP3 = \"VAL3\")"));
293 + Assert::True(EvaluateConditionHelper(pVariables, L"(PROP1 = \"VAL1\" AND PROP2 = \"VAL2\") OR PROP3 = \"NOT\""));
294 +
295 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP3 = \"NOT\" OR PROP1 = \"VAL1\" AND PROP2 = \"VAL2\""));
296 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP3 = \"VAL3\" OR PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
297 + Assert::False(EvaluateConditionHelper(pVariables, L"PROP3 = \"NOT\" OR PROP1 = \"VAL1\" AND PROP2 = \"NOT\""));
298 + Assert::True(EvaluateConditionHelper(pVariables, L"(PROP3 = \"NOT\" OR PROP1 = \"VAL1\") AND PROP2 = \"VAL2\""));
299 + Assert::True(EvaluateConditionHelper(pVariables, L"PROP3 = \"NOT\" OR (PROP1 = \"VAL1\" AND PROP2 = \"VAL2\")"));
300 +
301 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"="));
302 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"(PROP1"));
303 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"(PROP1 = \""));
304 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"1A"));
305 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"*"));
306 +
307 + Assert::True(EvaluateFailureConditionHelper(pVariables, L"1 == 1"));
308 + }
309 + finally
310 + {
311 + ReleaseVariables(pVariables);
312 + }
313 + }
314 +
315 + [NamedFact(Skip = "varutil Not Implemented Yet.")]
316 + void VarUtilValueTest()
317 + {
318 + HRESULT hr = S_OK;
319 + VARIABLES_HANDLE pVariables = NULL;
320 + VARIABLE_VALUE values[8];
321 +
322 + try
323 + {
324 + hr = VarCreate(&pVariables);
325 + NativeAssert::Succeeded(hr, "Failed to initialize variables.");
326 +
327 + // set variables
328 + InitNumericValue(pVariables, values + 0, 2, FALSE, 1, L"PROP1");
329 + InitStringValue(pVariables, values + 1, L"VAL2", FALSE, 2, L"PROP2");
330 + InitVersionValue(pVariables, values + 2, MAKEQWORDVERSION(1, 1, 0, 0), FALSE, 3, L"PROP3");
331 + InitNoneValue(pVariables, values + 3, FALSE, 4, L"PROP4");
332 + InitNoneValue(pVariables, values + 4, TRUE, 5, L"PROP5");
333 + InitVersionValue(pVariables, values + 5, MAKEQWORDVERSION(1, 1, 1, 0), TRUE, 6, L"PROP6");
334 + InitStringValue(pVariables, values + 6, L"7", TRUE, 7, L"PROP7");
335 + InitNumericValue(pVariables, values + 7, 11, TRUE, 8, L"PROP8");
336 +
337 + for (DWORD i = 0; i < 8; i++)
338 + {
339 + VerifyValue(pVariables, values + i);
340 + }
341 + }
342 + finally
343 + {
344 + VarDestroy(pVariables, FreeValueContext);
345 + }
346 + }
347 +
348 + [NamedFact(Skip = "varutil Not Implemented Yet.")]
349 + void VarUtilEnumTest()
350 + {
351 + HRESULT hr = S_OK;
352 + const DWORD dwIndex = 8;
353 + VARIABLES_HANDLE pVariables = NULL;
354 + VARIABLE_ENUM_HANDLE pEnum = NULL;
355 + VARIABLE_VALUE values[dwIndex];
356 + VARIABLE_VALUE* pValue = NULL;
357 +
358 + try
359 + {
360 + hr = VarCreate(&pVariables);
361 + NativeAssert::Succeeded(hr, "Failed to initialize variables.");
362 +
363 + hr = VarStartEnum(pVariables, &pEnum, &pValue);
364 + NativeAssert::ValidReturnCode(hr, E_NOMOREITEMS);
365 +
366 + // set variables
367 + InitNumericValue(pVariables, values + 0, 2, FALSE, 0, L"PROP1");
368 + InitStringValue(pVariables, values + 1, L"VAL2", FALSE, 0, L"PROP2");
369 + InitVersionValue(pVariables, values + 2, MAKEQWORDVERSION(1, 1, 0, 0), FALSE, 0, L"PROP3");
370 + InitNoneValue(pVariables, values + 3, FALSE, 0, L"PROP4");
371 + InitNoneValue(pVariables, values + 4, TRUE, 0, L"PROP5");
372 + InitVersionValue(pVariables, values + 5, MAKEQWORDVERSION(1, 1, 1, 0), TRUE, 0, L"PROP6");
373 + InitStringValue(pVariables, values + 6, L"7", TRUE, 0, L"PROP7");
374 + InitNumericValue(pVariables, values + 7, 11, TRUE, 0, L"PROP8");
375 +
376 + hr = VarStartEnum(pVariables, &pEnum, &pValue);
377 +
378 + for (DWORD i = dwIndex - 1; i; --i)
379 + {
380 + NativeAssert::ValidReturnCode(hr, S_OK);
381 +
382 + VarUtilContext* pContext = reinterpret_cast<VarUtilContext*>(pValue->pvContext);
383 + pContext->dw += 1;
384 +
385 + hr = VarNextVariable(pEnum, &pValue);
386 + }
387 +
388 + NativeAssert::ValidReturnCode(hr, E_NOMOREITEMS);
389 +
390 + for (DWORD j = 0; j < dwIndex; j++)
391 + {
392 + VarUtilContext* pContext = reinterpret_cast<VarUtilContext*>(values[j].pvContext);
393 + NativeAssert::Equal<DWORD>(1, pContext->dw);
394 + }
395 +
396 + VarFinishEnum(pEnum);
397 + pEnum = NULL;
398 +
399 + hr = VarStartEnum(pVariables, &pEnum, &pValue);
400 +
401 + for (DWORD i = dwIndex - 1; i; --i)
402 + {
403 + NativeAssert::ValidReturnCode(hr, S_OK);
404 +
405 + VarUtilContext* pContext = reinterpret_cast<VarUtilContext*>(pValue->pvContext);
406 + pContext->dw += 1;
407 +
408 + hr = VarNextVariable(pEnum, &pValue);
409 + }
410 +
411 + NativeAssert::ValidReturnCode(hr, E_NOMOREITEMS);
412 +
413 + for (DWORD j = 0; j < dwIndex; j++)
414 + {
415 + VarUtilContext* pContext = reinterpret_cast<VarUtilContext*>(values[j].pvContext);
416 + NativeAssert::Equal<DWORD>(2, pContext->dw);
417 + }
418 + }
419 + finally
420 + {
421 + VarFinishEnum(pEnum);
422 + ReleaseVariableValue(pValue);
423 + VarDestroy(pVariables, FreeValueContext);
424 + }
425 + }
426 +
427 + private:
428 + void InitNoneValue(VARIABLES_HANDLE pVariables, VARIABLE_VALUE* pValue, BOOL fHidden, DWORD dw, LPCWSTR wz)
429 + {
430 + pValue->type = VARIABLE_VALUE_TYPE_NONE;
431 + pValue->fHidden = fHidden;
432 +
433 + InitValueContext(pValue, dw, wz);
434 +
435 + HRESULT hr = VarSetValue(pVariables, wz, pValue);
436 + NativeAssert::Succeeded(hr, "Failed to set value for variable {0}", wz);
437 + }
438 +
439 + void InitNumericValue(VARIABLES_HANDLE pVariables, VARIABLE_VALUE* pValue, LONGLONG llValue, BOOL fHidden, DWORD dw, LPCWSTR wz)
440 + {
441 + pValue->type = VARIABLE_VALUE_TYPE_NUMERIC;
442 + pValue->fHidden = fHidden;
443 +
444 + pValue->llValue = llValue;
445 +
446 + InitValueContext(pValue, dw, wz);
447 +
448 + HRESULT hr = VarSetValue(pVariables, wz, pValue);
449 + NativeAssert::Succeeded(hr, "Failed to set value for variable {0}", wz);
450 + }
451 +
452 + void InitStringValue(VARIABLES_HANDLE pVariables, VARIABLE_VALUE* pValue, LPWSTR wzValue, BOOL fHidden, DWORD dw, LPCWSTR wz)
453 + {
454 + pValue->type = VARIABLE_VALUE_TYPE_STRING;
455 + pValue->fHidden = fHidden;
456 +
457 + HRESULT hr = StrAllocString(&pValue->sczValue, wzValue, 0);
458 + NativeAssert::Succeeded(hr, "Failed to alloc string: {0}", wzValue);
459 +
460 + InitValueContext(pValue, dw, wz);
461 +
462 + hr = VarSetValue(pVariables, wz, pValue);
463 + NativeAssert::Succeeded(hr, "Failed to set value for variable {0}", wz);
464 + }
465 +
466 + void InitVersionValue(VARIABLES_HANDLE pVariables, VARIABLE_VALUE* pValue, DWORD64 qwValue, BOOL fHidden, DWORD dw, LPCWSTR wz)
467 + {
468 + pValue->type = VARIABLE_VALUE_TYPE_VERSION;
469 + pValue->fHidden = fHidden;
470 +
471 + pValue->qwValue = qwValue;
472 +
473 + InitValueContext(pValue, dw, wz);
474 +
475 + HRESULT hr = VarSetValue(pVariables, wz, pValue);
476 + NativeAssert::Succeeded(hr, "Failed to set value for variable {0}", wz);
477 + }
478 +
479 + void InitValueContext(VARIABLE_VALUE* pValue, DWORD dw, LPCWSTR wz)
480 + {
481 + pValue->pvContext = MemAlloc(sizeof(VarUtilContext), TRUE);
482 + VarUtilContext* pContext = reinterpret_cast<VarUtilContext*>(pValue->pvContext);
483 + if (!pContext)
484 + {
485 + throw gcnew OutOfMemoryException();
486 + }
487 +
488 + pContext->dw = dw;
489 +
490 + HRESULT hr = StrAllocString(&pContext->scz, wz, 0);
491 + NativeAssert::Succeeded(hr, "Failed to alloc string: {0}", wz);
492 + }
493 +
494 + void VerifyValue(VARIABLES_HANDLE pVariables, VARIABLE_VALUE* pExpectedValue)
495 + {
496 + VARIABLE_VALUE* pActualValue = NULL;
497 +
498 + try
499 + {
500 + VarUtilContext* pExpectedContext = reinterpret_cast<VarUtilContext*>(pExpectedValue->pvContext);
501 + NativeAssert::True(NULL != pExpectedContext);
502 +
503 + HRESULT hr = VarGetValue(pVariables, pExpectedContext->scz, &pActualValue);
504 + NativeAssert::Succeeded(hr, "Failed to get value: {0}", pExpectedContext->scz);
505 +
506 + NativeAssert::Equal<DWORD>(pExpectedValue->type, pActualValue->type);
507 + NativeAssert::InRange<DWORD>(pExpectedValue->type, VARIABLE_VALUE_TYPE_NONE, VARIABLE_VALUE_TYPE_STRING);
508 +
509 + switch (pExpectedValue->type)
510 + {
511 + case VARIABLE_VALUE_TYPE_NONE:
512 + case VARIABLE_VALUE_TYPE_VERSION:
513 + NativeAssert::Equal(pExpectedValue->qwValue, pActualValue->qwValue);
514 + break;
515 + case VARIABLE_VALUE_TYPE_NUMERIC:
516 + NativeAssert::Equal(pExpectedValue->llValue, pActualValue->llValue);
517 + break;
518 + case VARIABLE_VALUE_TYPE_STRING:
519 + NativeAssert::StringEqual(pExpectedValue->sczValue, pActualValue->sczValue);
520 + break;
521 + }
522 +
523 + NativeAssert::Equal(pExpectedValue->fHidden, pActualValue->fHidden);
524 + NativeAssert::True(pExpectedValue->pvContext == pActualValue->pvContext);
525 + }
526 + finally
527 + {
528 + ReleaseVariableValue(pActualValue);
529 + }
530 + }
531 + };
532 +}
src/test/DUtilUnitTest/error.h new
+8
@@ -0,0 +1,8 @@
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 +const int ERROR_STRING_BUFFER = 1024;
4 +
5 +static char szMsg[ERROR_STRING_BUFFER];
6 +static WCHAR wzMsg[ERROR_STRING_BUFFER];
7 +
8 +#define ExitTrace(x, f, ...) { HRESULT hrTemp = x; hr = ::StringCchPrintfA(szMsg, countof(szMsg), f, __VA_ARGS__); MultiByteToWideChar(CP_ACP, 0, szMsg, -1, wzMsg, countof(wzMsg)); throw gcnew System::Exception(System::String::Format("hr = 0x{0:X8}, message = {1}", hrTemp, gcnew System::String(wzMsg))); }
src/test/DUtilUnitTest/packages.config new
+7
@@ -0,0 +1,7 @@
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 +<packages>
6 + <package id="xunit" version="1.9.1" targetFramework="net40" />
7 +</packages>
src/test/DUtilUnitTest/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/DUtilUnitTest/precomp.h new
+30
@@ -0,0 +1,30 @@
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 <strsafe.h>
7 +#include <ShlObj.h>
8 +
9 +// Include error.h before dutil.h
10 +#include "error.h"
11 +#include <dutil.h>
12 +
13 +#include <dictutil.h>
14 +#include <dirutil.h>
15 +#include <fileutil.h>
16 +#include <guidutil.h>
17 +#include <iniutil.h>
18 +#include <memutil.h>
19 +#include <pathutil.h>
20 +#include <strutil.h>
21 +#include <monutil.h>
22 +#include <regutil.h>
23 +#include <uriutil.h>
24 +#include <varutil.h>
25 +#include <condutil.h>
26 +
27 +#include "VarHelpers.h"
28 +
29 +#pragma managed
30 +#include <vcclr.h>
src/test/DUtilUnitTest/resource.h new
+2
@@ -0,0 +1,2 @@
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 +