diff options
| author | Ron Martin <cpuwzd@comcast.net> | 2022-08-29 18:38:07 -0400 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2022-10-21 19:08:08 -0700 |
| commit | 08cdc6aa2b9dd0e273a3c3a22893616d26342a0e (patch) | |
| tree | 1d0b9f7e21cec02abfda50b1a3c6d0c24308998b /src/test | |
| parent | 40bd65379768f99ec28bffe2691ba43c78c9e9c4 (diff) | |
| download | wix-08cdc6aa2b9dd0e273a3c3a22893616d26342a0e.tar.gz wix-08cdc6aa2b9dd0e273a3c3a22893616d26342a0e.tar.bz2 wix-08cdc6aa2b9dd0e273a3c3a22893616d26342a0e.zip | |
Support add, modify and remove comments on user accounts
Fixes 5371
Diffstat (limited to 'src/test')
16 files changed, 371 insertions, 44 deletions
diff --git a/src/test/burn/WixTestTools/MSIExec.cs b/src/test/burn/WixTestTools/MSIExec.cs index a905ec5a..fb161495 100644 --- a/src/test/burn/WixTestTools/MSIExec.cs +++ b/src/test/burn/WixTestTools/MSIExec.cs | |||
| @@ -259,7 +259,7 @@ namespace WixTestTools | |||
| 259 | arguments.Append(" /a "); | 259 | arguments.Append(" /a "); |
| 260 | break; | 260 | break; |
| 261 | case MSIExecMode.Repair: | 261 | case MSIExecMode.Repair: |
| 262 | arguments.Append(" /f "); | 262 | arguments.Append(" /fvomusa "); |
| 263 | break; | 263 | break; |
| 264 | case MSIExecMode.Cleanup: | 264 | case MSIExecMode.Cleanup: |
| 265 | case MSIExecMode.Uninstall: | 265 | case MSIExecMode.Uninstall: |
diff --git a/src/test/burn/WixTestTools/UserVerifier.cs b/src/test/burn/WixTestTools/UserVerifier.cs index b5218a79..51c6c31e 100644 --- a/src/test/burn/WixTestTools/UserVerifier.cs +++ b/src/test/burn/WixTestTools/UserVerifier.cs | |||
| @@ -49,7 +49,7 @@ namespace WixTestTools | |||
| 49 | UserPrincipal newUser = new UserPrincipal(new PrincipalContext(ContextType.Machine)); | 49 | UserPrincipal newUser = new UserPrincipal(new PrincipalContext(ContextType.Machine)); |
| 50 | newUser.SetPassword(password); | 50 | newUser.SetPassword(password); |
| 51 | newUser.Name = userName; | 51 | newUser.Name = userName; |
| 52 | newUser.Description = "New test User"; | 52 | newUser.Description = String.Empty; |
| 53 | newUser.UserCannotChangePassword = true; | 53 | newUser.UserCannotChangePassword = true; |
| 54 | newUser.PasswordNeverExpires = false; | 54 | newUser.PasswordNeverExpires = false; |
| 55 | newUser.Save(); | 55 | newUser.Save(); |
| @@ -109,6 +109,24 @@ namespace WixTestTools | |||
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | /// <summary> | 111 | /// <summary> |
| 112 | /// Sets the user comment for a given user | ||
| 113 | /// </summary> | ||
| 114 | /// <param name="domainName">domain name for the user, empty for local users</param> | ||
| 115 | /// <param name="userName">the user name</param> | ||
| 116 | /// <param name="comment">comment to be set for the user</param> | ||
| 117 | public static void SetUserComment(string domainName, string userName, string comment) | ||
| 118 | { | ||
| 119 | UserPrincipal user = GetUser(domainName, userName); | ||
| 120 | |||
| 121 | Assert.False(null == user, String.Format("User '{0}' was not found under domain '{1}'.", userName, domainName)); | ||
| 122 | |||
| 123 | var directoryEntry = user.GetUnderlyingObject() as DirectoryEntry; | ||
| 124 | Assert.False(null == directoryEntry); | ||
| 125 | directoryEntry.Properties["Description"].Value = comment; | ||
| 126 | user.Save(); | ||
| 127 | } | ||
| 128 | |||
| 129 | /// <summary> | ||
| 112 | /// Adds the specified user to the specified local group | 130 | /// Adds the specified user to the specified local group |
| 113 | /// </summary> | 131 | /// </summary> |
| 114 | /// <param name="userName">User to add</param> | 132 | /// <param name="userName">User to add</param> |
| @@ -162,7 +180,24 @@ namespace WixTestTools | |||
| 162 | } | 180 | } |
| 163 | 181 | ||
| 164 | /// <summary> | 182 | /// <summary> |
| 165 | /// Verify that a givin user is member of a local group | 183 | /// Verifies the user comment for a given user |
| 184 | /// </summary> | ||
| 185 | /// <param name="domainName">domain name for the user, empty for local users</param> | ||
| 186 | /// <param name="userName">the user name</param> | ||
| 187 | /// <param name="comment">the comment to be verified</param> | ||
| 188 | public static void VerifyUserComment(string domainName, string userName, string comment) | ||
| 189 | { | ||
| 190 | UserPrincipal user = GetUser(domainName, userName); | ||
| 191 | |||
| 192 | Assert.False(null == user, String.Format("User '{0}' was not found under domain '{1}'.", userName, domainName)); | ||
| 193 | |||
| 194 | var directoryEntry = user.GetUnderlyingObject() as DirectoryEntry; | ||
| 195 | Assert.False(null == directoryEntry); | ||
| 196 | Assert.True(comment == (string)(directoryEntry.Properties["Description"].Value)); | ||
| 197 | } | ||
| 198 | |||
| 199 | /// <summary> | ||
| 200 | /// Verify that a given user is member of a local group | ||
| 166 | /// </summary> | 201 | /// </summary> |
| 167 | /// <param name="domainName">domain name for the user, empty for local users</param> | 202 | /// <param name="domainName">domain name for the user, empty for local users</param> |
| 168 | /// <param name="userName">the user name</param> | 203 | /// <param name="userName">the user name</param> |
| @@ -322,7 +357,6 @@ namespace WixTestTools | |||
| 322 | missedAGroup = true; | 357 | missedAGroup = true; |
| 323 | message += String.Format("Local group '{0}' was not found. \r\n", groupName); | 358 | message += String.Format("Local group '{0}' was not found. \r\n", groupName); |
| 324 | } | 359 | } |
| 325 | |||
| 326 | } | 360 | } |
| 327 | Assert.False(missedAGroup, message); | 361 | Assert.False(missedAGroup, message); |
| 328 | } | 362 | } |
| @@ -346,3 +380,4 @@ namespace WixTestTools | |||
| 346 | } | 380 | } |
| 347 | } | 381 | } |
| 348 | } | 382 | } |
| 383 | |||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductA/ProductA.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductA/ProductA.wixproj index fbc6f292..3895b853 100644 --- a/src/test/msi/TestData/UtilExtensionUserTests/ProductA/ProductA.wixproj +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductA/ProductA.wixproj | |||
| @@ -1,7 +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. --> | 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 | <Project Sdk="WixToolset.Sdk"> | 2 | <Project Sdk="WixToolset.Sdk"> |
| 3 | <PropertyGroup> | 3 | <PropertyGroup> |
| 4 | <UpgradeCode>{1A1795A6-87C0-4A9A-ABD5-DF9BED697037}</UpgradeCode> | 4 | <UpgradeCode>{A3E0B539-63F9-4B43-9E34-F33AE1C6E06D}</UpgradeCode> |
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | 5 | <ProductComponentsRef>true</ProductComponentsRef> |
| 6 | </PropertyGroup> | 6 | </PropertyGroup> |
| 7 | <ItemGroup> | 7 | <ItemGroup> |
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductA/product.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductA/product.wxs index a7bec54e..be6e16a4 100644 --- a/src/test/msi/TestData/UtilExtensionUserTests/ProductA/product.wxs +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductA/product.wxs | |||
| @@ -15,10 +15,10 @@ | |||
| 15 | <util:Group Id="ADMIN" Name="Administrators" /> | 15 | <util:Group Id="ADMIN" Name="Administrators" /> |
| 16 | <util:Group Id="POWER_USER" Name="Power Users" /> | 16 | <util:Group Id="POWER_USER" Name="Power Users" /> |
| 17 | 17 | ||
| 18 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | 18 | <Component Id="Component1" Guid="09624A9A-4BBC-4126-BBF9-0713C5217DB1" Directory="INSTALLFOLDER"> |
| 19 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | 19 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> |
| 20 | 20 | ||
| 21 | <util:User Id="TEST_USER1" Name="testName1" Password="test123!@#" PasswordExpired="yes"> | 21 | <util:User Id="TEST_USER1" Name="testName1" Password="test123!@#" PasswordExpired="yes" CreateUser="yes" RemoveOnUninstall="yes"> |
| 22 | <util:GroupRef Id="ADMIN" /> | 22 | <util:GroupRef Id="ADMIN" /> |
| 23 | <util:GroupRef Id="POWER_USER" /> | 23 | <util:GroupRef Id="POWER_USER" /> |
| 24 | </util:User> | 24 | </util:User> |
| @@ -27,7 +27,7 @@ | |||
| 27 | <util:GroupRef Id="POWER_USER" /> | 27 | <util:GroupRef Id="POWER_USER" /> |
| 28 | </util:User> | 28 | </util:User> |
| 29 | 29 | ||
| 30 | <util:User Id="TEST_USER3" Name="[TEMPUSERNAME]" Domain="[TEMPDOMAIN]" CreateUser="no"> | 30 | <util:User Id="TEST_USER3" Name="testName3" CreateUser="no"> |
| 31 | <util:GroupRef Id="POWER_USER" /> | 31 | <util:GroupRef Id="POWER_USER" /> |
| 32 | </util:User> | 32 | </util:User> |
| 33 | </Component> | 33 | </Component> |
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/ProductAddCommentToExistingUser.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/ProductAddCommentToExistingUser.wixproj new file mode 100644 index 00000000..5938e525 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/ProductAddCommentToExistingUser.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 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 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{B33D3140-4AA5-469D-9DEE-AAF8F0C626DA}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/product.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/product.wxs new file mode 100644 index 00000000..ce8c4cae --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/product.wxs | |||
| @@ -0,0 +1,25 @@ | |||
| 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 | |||
| 4 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 5 | <Fragment> | ||
| 6 | <ComponentGroup Id="ProductComponents"> | ||
| 7 | <ComponentRef Id="Component1" /> | ||
| 8 | </ComponentGroup> | ||
| 9 | </Fragment> | ||
| 10 | |||
| 11 | <Fragment> | ||
| 12 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 13 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 14 | |||
| 15 | <util:User Id="TEST_USER1" | ||
| 16 | Name="testName1" | ||
| 17 | Password="test123!@#" | ||
| 18 | PasswordExpired="yes" | ||
| 19 | CreateUser="yes" | ||
| 20 | UpdateIfExists="yes" | ||
| 21 | RemoveOnUninstall="yes" | ||
| 22 | Comment="testComment1"/> | ||
| 23 | </Component> | ||
| 24 | </Fragment> | ||
| 25 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/ProductCommentDelete.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/ProductCommentDelete.wixproj new file mode 100644 index 00000000..63bb2370 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/ProductCommentDelete.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 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 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{9E4C301E-5F36-4A86-85BE-776E067D929D}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/product.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/product.wxs new file mode 100644 index 00000000..f0fbc55e --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/product.wxs | |||
| @@ -0,0 +1,18 @@ | |||
| 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 | |||
| 4 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 5 | <Fragment> | ||
| 6 | <ComponentGroup Id="ProductComponents"> | ||
| 7 | <ComponentRef Id="Component1" /> | ||
| 8 | </ComponentGroup> | ||
| 9 | </Fragment> | ||
| 10 | |||
| 11 | <Fragment> | ||
| 12 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 13 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 14 | |||
| 15 | <util:User Id="TEST_USER1" Name="testName1" Password="test123!@#" PasswordExpired="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" RemoveComment="yes"/> | ||
| 16 | </Component> | ||
| 17 | </Fragment> | ||
| 18 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/ProductCommentFail.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/ProductCommentFail.wixproj new file mode 100644 index 00000000..66f308ae --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/ProductCommentFail.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 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 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{85F698E0-F542-4CB4-80A1-6630D2DEB647}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/product_fail.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/product_fail.wxs new file mode 100644 index 00000000..f36d5bd5 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/product_fail.wxs | |||
| @@ -0,0 +1,22 @@ | |||
| 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 | |||
| 4 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 5 | <Fragment> | ||
| 6 | <ComponentGroup Id="ProductComponents"> | ||
| 7 | <ComponentRef Id="Component1" /> | ||
| 8 | </ComponentGroup> | ||
| 9 | |||
| 10 | <InstallExecuteSequence> | ||
| 11 | <Custom Action="CaFail" After="Wix4ConfigureUsers_X86" /> | ||
| 12 | </InstallExecuteSequence> | ||
| 13 | </Fragment> | ||
| 14 | |||
| 15 | <Fragment> | ||
| 16 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 17 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 18 | |||
| 19 | <util:User Id="TEST_USER1" Name="testName1" Password="test123!@#" PasswordExpired="yes" CreateUser="yes" RemoveOnUninstall="yes" Comment="testComment1"/> | ||
| 20 | </Component> | ||
| 21 | </Fragment> | ||
| 22 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductFail/product_fail.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductFail/product_fail.wxs index c5da862c..82472d4e 100644 --- a/src/test/msi/TestData/UtilExtensionUserTests/ProductFail/product_fail.wxs +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductFail/product_fail.wxs | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | <util:GroupRef Id="POWER_USER" /> | 31 | <util:GroupRef Id="POWER_USER" /> |
| 32 | </util:User> | 32 | </util:User> |
| 33 | 33 | ||
| 34 | <util:User Id="TEST_USER3" Name="[TEMPUSERNAME]" Domain="[TEMPDOMAIN]" CreateUser="no"> | 34 | <util:User Id="TEST_USER3" Name="testName3" CreateUser="no"> |
| 35 | <util:GroupRef Id="POWER_USER" /> | 35 | <util:GroupRef Id="POWER_USER" /> |
| 36 | </util:User> | 36 | </util:User> |
| 37 | </Component> | 37 | </Component> |
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/ProductNewUserWithComment.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/ProductNewUserWithComment.wixproj new file mode 100644 index 00000000..aeac903a --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/ProductNewUserWithComment.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 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 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{549E1829-BBDE-42E1-968A-BEB8FC12BFC7}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/product.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/product.wxs new file mode 100644 index 00000000..dde23aab --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/product.wxs | |||
| @@ -0,0 +1,25 @@ | |||
| 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 | |||
| 4 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 5 | <Fragment> | ||
| 6 | <ComponentGroup Id="ProductComponents"> | ||
| 7 | <ComponentRef Id="Component1" /> | ||
| 8 | </ComponentGroup> | ||
| 9 | </Fragment> | ||
| 10 | |||
| 11 | <Fragment> | ||
| 12 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 13 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 14 | <util:User | ||
| 15 | Id="TEST_USER1" | ||
| 16 | Name="testName1" | ||
| 17 | Password="test123!@#" | ||
| 18 | PasswordExpired="yes" | ||
| 19 | CreateUser="yes" | ||
| 20 | UpdateIfExists="yes" | ||
| 21 | RemoveOnUninstall="yes" | ||
| 22 | Comment="testComment1" /> | ||
| 23 | </Component> | ||
| 24 | </Fragment> | ||
| 25 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wixproj new file mode 100644 index 00000000..93a56216 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 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 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{79F2CB65-1E71-42EB-AA30-51BD70C29B23}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wxs new file mode 100644 index 00000000..564ce4f0 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wxs | |||
| @@ -0,0 +1,21 @@ | |||
| 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 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 3 | <Fragment> | ||
| 4 | <ComponentGroup Id="ProductComponents"> | ||
| 5 | <ComponentRef Id="Component1" /> | ||
| 6 | </ComponentGroup> | ||
| 7 | </Fragment> | ||
| 8 | |||
| 9 | <Fragment> | ||
| 10 | <Component Id="Component1" | ||
| 11 | Guid="1FDC6C4D-7741-4BF1-A4F0-4231879CEC45" | ||
| 12 | Directory="INSTALLFOLDER"> | ||
| 13 | <util:User Id="TEST_USER1" | ||
| 14 | Name="[TESTPARAMETER1]" | ||
| 15 | Password="test123!@#" | ||
| 16 | PasswordExpired="yes" | ||
| 17 | CreateUser="yes" | ||
| 18 | RemoveOnUninstall="yes" /> | ||
| 19 | </Component> | ||
| 20 | </Fragment> | ||
| 21 | </Wix> | ||
diff --git a/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionUserTests.cs b/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionUserTests.cs index fcdfde52..30bc53e8 100644 --- a/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionUserTests.cs +++ b/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionUserTests.cs | |||
| @@ -11,21 +11,14 @@ namespace WixToolsetTest.MsiE2E | |||
| 11 | { | 11 | { |
| 12 | public UtilExtensionUserTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } | 12 | public UtilExtensionUserTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } |
| 13 | 13 | ||
| 14 | const string TempDomain = "USERDOMAIN"; | ||
| 15 | const string TempUsername = "USERNAME"; | ||
| 16 | |||
| 17 | // Verify that the users specified in the authoring are created as expected. | 14 | // Verify that the users specified in the authoring are created as expected. |
| 18 | [RuntimeFact] | 15 | [RuntimeFact] |
| 19 | public void CanInstallAndUninstallUsers() | 16 | public void CanInstallAndUninstallUsers() |
| 20 | { | 17 | { |
| 21 | var arguments = new string[] | 18 | UserVerifier.CreateLocalUser("testName3", "test123!@#"); |
| 22 | { | ||
| 23 | $"TEMPDOMAIN={Environment.GetEnvironmentVariable(TempDomain)}", | ||
| 24 | $"TEMPUSERNAME={Environment.GetEnvironmentVariable(TempUsername)}", | ||
| 25 | }; | ||
| 26 | var productA = this.CreatePackageInstaller("ProductA"); | 19 | var productA = this.CreatePackageInstaller("ProductA"); |
| 27 | 20 | ||
| 28 | productA.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | 21 | productA.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 29 | 22 | ||
| 30 | // Validate New User Information. | 23 | // Validate New User Information. |
| 31 | UserVerifier.VerifyUserInformation(String.Empty, "testName1", true, false, false); | 24 | UserVerifier.VerifyUserInformation(String.Empty, "testName1", true, false, false); |
| @@ -34,62 +27,90 @@ namespace WixToolsetTest.MsiE2E | |||
| 34 | UserVerifier.VerifyUserInformation(String.Empty, "testName2", true, true, true); | 27 | UserVerifier.VerifyUserInformation(String.Empty, "testName2", true, true, true); |
| 35 | UserVerifier.VerifyUserIsMemberOf(String.Empty, "testName2", "Power Users"); | 28 | UserVerifier.VerifyUserIsMemberOf(String.Empty, "testName2", "Power Users"); |
| 36 | 29 | ||
| 37 | UserVerifier.VerifyUserIsMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | 30 | UserVerifier.VerifyUserIsMemberOf("", "testName3", "Power Users"); |
| 38 | 31 | ||
| 39 | productA.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | 32 | productA.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 40 | 33 | ||
| 41 | // Verify Users marked as RemoveOnUninstall were removed. | 34 | // Verify Users marked as RemoveOnUninstall were removed. |
| 42 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Uninstall", "testName1")); | 35 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Uninstall", "testName1")); |
| 43 | Assert.True(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was removed on Uninstall", "testName2")); | 36 | Assert.True(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was removed on Uninstall", "testName2")); |
| 44 | 37 | ||
| 38 | // Verify that user added to power users group is removed on uninstall. | ||
| 39 | UserVerifier.VerifyUserIsNotMemberOf("", "testName3", "Power Users"); | ||
| 40 | |||
| 45 | // clean up | 41 | // clean up |
| 42 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 46 | UserVerifier.DeleteLocalUser("testName2"); | 43 | UserVerifier.DeleteLocalUser("testName2"); |
| 47 | 44 | UserVerifier.DeleteLocalUser("testName3"); | |
| 48 | UserVerifier.VerifyUserIsNotMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | ||
| 49 | } | 45 | } |
| 50 | 46 | ||
| 51 | // Verify the rollback action reverts all Users changes. | 47 | // Verify the rollback action reverts all Users changes. |
| 52 | [RuntimeFact] | 48 | [RuntimeFact] |
| 53 | public void CanRollbackUsers() | 49 | public void CanRollbackUsers() |
| 54 | { | 50 | { |
| 55 | var arguments = new string[] | 51 | UserVerifier.CreateLocalUser("testName3", "test123!@#"); |
| 56 | { | ||
| 57 | $"TEMPDOMAIN={Environment.GetEnvironmentVariable(TempDomain)}", | ||
| 58 | $"TEMPUSERNAME={Environment.GetEnvironmentVariable(TempUsername)}", | ||
| 59 | }; | ||
| 60 | var productFail = this.CreatePackageInstaller("ProductFail"); | 52 | var productFail = this.CreatePackageInstaller("ProductFail"); |
| 61 | 53 | ||
| 62 | // make sure the user accounts are deleted before we start | 54 | // make sure the user accounts are deleted before we start |
| 63 | UserVerifier.DeleteLocalUser("testName1"); | 55 | UserVerifier.DeleteLocalUser("testName1"); |
| 64 | UserVerifier.DeleteLocalUser("testName2"); | 56 | UserVerifier.DeleteLocalUser("testName2"); |
| 65 | UserVerifier.VerifyUserIsNotMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | ||
| 66 | 57 | ||
| 67 | productFail.InstallProduct(MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, arguments); | 58 | productFail.InstallProduct(MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE); |
| 68 | 59 | ||
| 69 | // Verify Users marked as RemoveOnUninstall were removed. | 60 | // Verify added Users were removed on rollback. |
| 70 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Rollback", "testName1")); | 61 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Rollback", "testName1")); |
| 71 | Assert.False(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was not removed on Rollback", "testName2")); | 62 | Assert.False(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was not removed on Rollback", "testName2")); |
| 72 | 63 | ||
| 73 | UserVerifier.VerifyUserIsNotMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | 64 | // Verify that user added to power users group is removed from power users group on rollback. |
| 65 | UserVerifier.VerifyUserIsNotMemberOf("", "testName3", "Power Users"); | ||
| 66 | |||
| 67 | // clean up | ||
| 68 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 69 | UserVerifier.DeleteLocalUser("testName2"); | ||
| 70 | UserVerifier.DeleteLocalUser("testName3"); | ||
| 74 | } | 71 | } |
| 75 | 72 | ||
| 76 | // Verify that the users specified in the authoring are created as expected on repair. | 73 | |
| 77 | [RuntimeFact(Skip = "Test demonstrates failure")] | 74 | // Verify that command-line parameters aer not blocked by repair switches. |
| 78 | public void CanRepairUsers() | 75 | // Original code signalled repair mode by using "-f ", which silently |
| 76 | // terminated the command-line parsing, ignoring any parameters that followed. | ||
| 77 | [RuntimeFact()] | ||
| 78 | public void CanRepairUsersWithCommandLineParameters() | ||
| 79 | { | 79 | { |
| 80 | var arguments = new string[] | 80 | var arguments = new string[] |
| 81 | { | 81 | { |
| 82 | $"TEMPDOMAIN={Environment.GetEnvironmentVariable(TempDomain)}", | 82 | "TESTPARAMETER1=testName1", |
| 83 | $"TEMPUSERNAME={Environment.GetEnvironmentVariable(TempUsername)}", | ||
| 84 | }; | 83 | }; |
| 84 | var productWithCommandLineParameters = this.CreatePackageInstaller("ProductWithCommandLineParameters"); | ||
| 85 | |||
| 86 | // Make sure that the user doesn't exist when we start the test. | ||
| 87 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 88 | |||
| 89 | // Install | ||
| 90 | productWithCommandLineParameters.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | ||
| 91 | |||
| 92 | // Repair | ||
| 93 | productWithCommandLineParameters.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | ||
| 94 | |||
| 95 | // Clean up | ||
| 96 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 97 | } | ||
| 98 | |||
| 99 | |||
| 100 | // Verify that the users specified in the authoring are created as expected on repair. | ||
| 101 | [RuntimeFact()] | ||
| 102 | public void CanRepairUsers() | ||
| 103 | { | ||
| 104 | UserVerifier.CreateLocalUser("testName3", "test123!@#"); | ||
| 85 | var productA = this.CreatePackageInstaller("ProductA"); | 105 | var productA = this.CreatePackageInstaller("ProductA"); |
| 86 | 106 | ||
| 87 | productA.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | 107 | productA.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 88 | 108 | ||
| 109 | // Validate New User Information. | ||
| 89 | UserVerifier.DeleteLocalUser("testName1"); | 110 | UserVerifier.DeleteLocalUser("testName1"); |
| 90 | UserVerifier.SetUserInformation(String.Empty, "testName2", true, false, false); | 111 | UserVerifier.SetUserInformation(String.Empty, "testName2", true, false, false); |
| 91 | 112 | ||
| 92 | productA.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | 113 | productA.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 93 | 114 | ||
| 94 | // Validate New User Information. | 115 | // Validate New User Information. |
| 95 | UserVerifier.VerifyUserInformation(String.Empty, "testName1", true, false, false); | 116 | UserVerifier.VerifyUserInformation(String.Empty, "testName1", true, false, false); |
| @@ -98,21 +119,24 @@ namespace WixToolsetTest.MsiE2E | |||
| 98 | UserVerifier.VerifyUserInformation(String.Empty, "testName2", true, true, true); | 119 | UserVerifier.VerifyUserInformation(String.Empty, "testName2", true, true, true); |
| 99 | UserVerifier.VerifyUserIsMemberOf(String.Empty, "testName2", "Power Users"); | 120 | UserVerifier.VerifyUserIsMemberOf(String.Empty, "testName2", "Power Users"); |
| 100 | 121 | ||
| 101 | UserVerifier.VerifyUserIsMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | 122 | UserVerifier.VerifyUserIsMemberOf("", "testName3", "Power Users"); |
| 102 | 123 | ||
| 103 | productA.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | 124 | productA.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 104 | 125 | ||
| 105 | // Verify Users marked as RemoveOnUninstall were removed. | 126 | // Verify Users marked as RemoveOnUninstall were removed. |
| 106 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Uninstall", "testName1")); | 127 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Uninstall", "testName1")); |
| 107 | Assert.True(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was removed on Uninstall", "testName2")); | 128 | Assert.True(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was removed on Uninstall", "testName2")); |
| 108 | 129 | ||
| 130 | // Verify that user added to power users group is removed on uninstall. | ||
| 131 | UserVerifier.VerifyUserIsNotMemberOf("", "testName3", "Power Users"); | ||
| 132 | |||
| 109 | // clean up | 133 | // clean up |
| 134 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 110 | UserVerifier.DeleteLocalUser("testName2"); | 135 | UserVerifier.DeleteLocalUser("testName2"); |
| 111 | 136 | UserVerifier.DeleteLocalUser("testName3"); | |
| 112 | UserVerifier.VerifyUserIsNotMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | ||
| 113 | } | 137 | } |
| 114 | 138 | ||
| 115 | // Verify that Installation fails if FailIfExisits is set. | 139 | // Verify that Installation fails if FailIfExists is set. |
| 116 | [RuntimeFact] | 140 | [RuntimeFact] |
| 117 | public void FailsIfUserExists() | 141 | public void FailsIfUserExists() |
| 118 | { | 142 | { |
| @@ -135,7 +159,6 @@ namespace WixToolsetTest.MsiE2E | |||
| 135 | // clean up | 159 | // clean up |
| 136 | UserVerifier.DeleteLocalUser("existinguser"); | 160 | UserVerifier.DeleteLocalUser("existinguser"); |
| 137 | } | 161 | } |
| 138 | |||
| 139 | } | 162 | } |
| 140 | 163 | ||
| 141 | // Verify that a user cannot be created on a domain on which you dont have create user permission. | 164 | // Verify that a user cannot be created on a domain on which you dont have create user permission. |
| @@ -158,5 +181,98 @@ namespace WixToolsetTest.MsiE2E | |||
| 158 | 181 | ||
| 159 | productNonVitalGroup.InstallProduct(); | 182 | productNonVitalGroup.InstallProduct(); |
| 160 | } | 183 | } |
| 184 | |||
| 185 | // Verify that a user can be created with a user comment | ||
| 186 | [RuntimeFact] | ||
| 187 | public void CanCreateNewUserWithComment() | ||
| 188 | { | ||
| 189 | var productNewUserWithComment = this.CreatePackageInstaller("ProductNewUserWithComment"); | ||
| 190 | |||
| 191 | productNewUserWithComment.InstallProduct(); | ||
| 192 | UserVerifier.VerifyUserComment(String.Empty, "testName1", "testComment1"); | ||
| 193 | |||
| 194 | // clean up | ||
| 195 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 196 | } | ||
| 197 | |||
| 198 | // Verify that a comment can be added to an existing user | ||
| 199 | [RuntimeFact] | ||
| 200 | public void CanAddCommentToExistingUser() | ||
| 201 | { | ||
| 202 | UserVerifier.CreateLocalUser("testName1", "test123!@#"); | ||
| 203 | var productAddCommentToExistingUser = this.CreatePackageInstaller("ProductAddCommentToExistingUser"); | ||
| 204 | |||
| 205 | productAddCommentToExistingUser.InstallProduct(); | ||
| 206 | |||
| 207 | UserVerifier.VerifyUserComment(String.Empty, "testName1", "testComment1"); | ||
| 208 | |||
| 209 | // clean up | ||
| 210 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 211 | } | ||
| 212 | |||
| 213 | // Verify that a comment can be repaired for a new user | ||
| 214 | [RuntimeFact] | ||
| 215 | public void CanRepairCommentOfNewUser() | ||
| 216 | { | ||
| 217 | var productNewUserWithComment = this.CreatePackageInstaller("ProductNewUserWithComment"); | ||
| 218 | |||
| 219 | productNewUserWithComment.InstallProduct(); | ||
| 220 | UserVerifier.SetUserComment(String.Empty, "testName1", ""); | ||
| 221 | |||
| 222 | productNewUserWithComment.RepairProduct(); | ||
| 223 | UserVerifier.VerifyUserComment(String.Empty, "testName1", "testComment1"); | ||
| 224 | |||
| 225 | // clean up | ||
| 226 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 227 | } | ||
| 228 | |||
| 229 | // Verify that a comment can be changed for an existing user | ||
| 230 | [RuntimeFact] | ||
| 231 | public void CanChangeCommentOfExistingUser() | ||
| 232 | { | ||
| 233 | UserVerifier.CreateLocalUser("testName1", "test123!@#"); | ||
| 234 | UserVerifier.SetUserComment(String.Empty, "testName1", "initialTestComment1"); | ||
| 235 | var productNewUserWithComment = this.CreatePackageInstaller("ProductNewUserWithComment"); | ||
| 236 | |||
| 237 | productNewUserWithComment.InstallProduct(); | ||
| 238 | UserVerifier.VerifyUserComment(String.Empty, "testName1", "testComment1"); | ||
| 239 | |||
| 240 | // clean up | ||
| 241 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 242 | } | ||
| 243 | |||
| 244 | // Verify that a comment can be rolled back for an existing user | ||
| 245 | [RuntimeFact] | ||
| 246 | public void CanRollbackCommentOfExistingUser() | ||
| 247 | { | ||
| 248 | UserVerifier.CreateLocalUser("testName1", "test123!@#"); | ||
| 249 | UserVerifier.SetUserComment(String.Empty, "testName1", "initialTestComment1"); | ||
| 250 | var productCommentFail = this.CreatePackageInstaller("ProductCommentFail"); | ||
| 251 | |||
| 252 | productCommentFail.InstallProduct(MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE); | ||
| 253 | |||
| 254 | // Verify that comment change was rolled back. | ||
| 255 | UserVerifier.VerifyUserComment(String.Empty, "testName1", "initialTestComment1"); | ||
| 256 | |||
| 257 | // clean up | ||
| 258 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 259 | } | ||
| 260 | |||
| 261 | // Verify that a comment can be deleted for an existing user | ||
| 262 | [RuntimeFact] | ||
| 263 | public void CanDeleteCommentOfExistingUser() | ||
| 264 | { | ||
| 265 | UserVerifier.CreateLocalUser("testName1", "test123!@#"); | ||
| 266 | UserVerifier.SetUserComment(String.Empty, "testName1", "testComment1"); | ||
| 267 | var productCommentDelete = this.CreatePackageInstaller("ProductCommentDelete"); | ||
| 268 | |||
| 269 | productCommentDelete.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | ||
| 270 | |||
| 271 | // Verify that comment was removed. | ||
| 272 | UserVerifier.VerifyUserComment(String.Empty, "testName1", ""); | ||
| 273 | |||
| 274 | // clean up | ||
| 275 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 276 | } | ||
| 161 | } | 277 | } |
| 162 | } | 278 | } |
