diff options
| author | Rob Mensching <rob@firegiant.com> | 2021-05-11 07:36:37 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2021-05-11 07:36:37 -0700 |
| commit | 3f583916719eeef598d10a5d4e14ef14f008243b (patch) | |
| tree | 3d528e0ddb5c0550954217c97059d2f19cd6152a /src/dtf/WixToolsetTests.Dtf.WindowsInstaller | |
| parent | 2e5ab696b8b4666d551b2a0532b95fb7fe6dbe03 (diff) | |
| download | wix-3f583916719eeef598d10a5d4e14ef14f008243b.tar.gz wix-3f583916719eeef598d10a5d4e14ef14f008243b.tar.bz2 wix-3f583916719eeef598d10a5d4e14ef14f008243b.zip | |
Merge Dtf
Diffstat (limited to 'src/dtf/WixToolsetTests.Dtf.WindowsInstaller')
6 files changed, 1189 insertions, 0 deletions
diff --git a/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/EmbeddedExternalUI.cs b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/EmbeddedExternalUI.cs new file mode 100644 index 00000000..b0fc00a8 --- /dev/null +++ b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/EmbeddedExternalUI.cs | |||
| @@ -0,0 +1,173 @@ | |||
| 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 | namespace WixToolset.Dtf.Test | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using System.Reflection; | ||
| 8 | using System.Windows.Forms; | ||
| 9 | using System.Globalization; | ||
| 10 | using System.Collections.Generic; | ||
| 11 | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
| 12 | using WixToolset.Dtf.WindowsInstaller; | ||
| 13 | using View = WixToolset.Dtf.WindowsInstaller.View; | ||
| 14 | |||
| 15 | [TestClass] | ||
| 16 | public class EmbeddedExternalUI | ||
| 17 | { | ||
| 18 | const InstallLogModes TestLogModes = | ||
| 19 | InstallLogModes.FatalExit | | ||
| 20 | InstallLogModes.Error | | ||
| 21 | InstallLogModes.Warning | | ||
| 22 | InstallLogModes.User | | ||
| 23 | InstallLogModes.Info | | ||
| 24 | InstallLogModes.ResolveSource | | ||
| 25 | InstallLogModes.OutOfDiskSpace | | ||
| 26 | InstallLogModes.ActionStart | | ||
| 27 | InstallLogModes.ActionData | | ||
| 28 | InstallLogModes.CommonData; | ||
| 29 | |||
| 30 | #if DEBUG | ||
| 31 | const string EmbeddedUISampleBinDir = @"..\..\build\debug\"; | ||
| 32 | #else | ||
| 33 | const string EmbeddedUISampleBinDir = @"..\..\build\release\"; | ||
| 34 | #endif | ||
| 35 | |||
| 36 | [TestMethod] | ||
| 37 | [Ignore] // Requires elevation. | ||
| 38 | public void EmbeddedUISingleInstall() | ||
| 39 | { | ||
| 40 | string dbFile = "EmbeddedUISingleInstall.msi"; | ||
| 41 | string productCode; | ||
| 42 | |||
| 43 | string uiDir = Path.GetFullPath(EmbeddedExternalUI.EmbeddedUISampleBinDir); | ||
| 44 | string uiFile = "WixToolset.Dtf.Samples.EmbeddedUI.dll"; | ||
| 45 | |||
| 46 | using (Database db = new Database(dbFile, DatabaseOpenMode.CreateDirect)) | ||
| 47 | { | ||
| 48 | WindowsInstallerUtils.InitializeProductDatabase(db); | ||
| 49 | WindowsInstallerUtils.CreateTestProduct(db); | ||
| 50 | |||
| 51 | productCode = db.ExecuteStringQuery("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'")[0]; | ||
| 52 | |||
| 53 | using (Record uiRec = new Record(5)) | ||
| 54 | { | ||
| 55 | uiRec[1] = "TestEmbeddedUI"; | ||
| 56 | uiRec[2] = Path.GetFileNameWithoutExtension(uiFile) + ".Wrapper.dll"; | ||
| 57 | uiRec[3] = 1; | ||
| 58 | uiRec[4] = (int) ( | ||
| 59 | EmbeddedExternalUI.TestLogModes | | ||
| 60 | InstallLogModes.Progress | | ||
| 61 | InstallLogModes.Initialize | | ||
| 62 | InstallLogModes.Terminate | | ||
| 63 | InstallLogModes.ShowDialog); | ||
| 64 | uiRec.SetStream(5, Path.Combine(uiDir, uiFile)); | ||
| 65 | db.Execute(db.Tables["MsiEmbeddedUI"].SqlInsertString, uiRec); | ||
| 66 | } | ||
| 67 | |||
| 68 | db.Commit(); | ||
| 69 | } | ||
| 70 | |||
| 71 | Installer.SetInternalUI(InstallUIOptions.Full); | ||
| 72 | |||
| 73 | ProductInstallation installation = new ProductInstallation(productCode); | ||
| 74 | Assert.IsFalse(installation.IsInstalled, "Checking that product is not installed before starting."); | ||
| 75 | |||
| 76 | Exception caughtEx = null; | ||
| 77 | try | ||
| 78 | { | ||
| 79 | Installer.EnableLog(EmbeddedExternalUI.TestLogModes, "install.log"); | ||
| 80 | Installer.InstallProduct(dbFile, String.Empty); | ||
| 81 | } | ||
| 82 | catch (Exception ex) { caughtEx = ex; } | ||
| 83 | Assert.IsNull(caughtEx, "Exception thrown while installing product: " + caughtEx); | ||
| 84 | |||
| 85 | Assert.IsTrue(installation.IsInstalled, "Checking that product is installed."); | ||
| 86 | Console.WriteLine(); | ||
| 87 | Console.WriteLine(); | ||
| 88 | Console.WriteLine(); | ||
| 89 | Console.WriteLine("==================================================================="); | ||
| 90 | Console.WriteLine(); | ||
| 91 | Console.WriteLine(); | ||
| 92 | Console.WriteLine(); | ||
| 93 | |||
| 94 | try | ||
| 95 | { | ||
| 96 | Installer.EnableLog(EmbeddedExternalUI.TestLogModes, "uninstall.log"); | ||
| 97 | Installer.InstallProduct(dbFile, "REMOVE=All"); | ||
| 98 | } | ||
| 99 | catch (Exception ex) { caughtEx = ex; } | ||
| 100 | Assert.IsNull(caughtEx, "Exception thrown while uninstalling product: " + caughtEx); | ||
| 101 | } | ||
| 102 | |||
| 103 | // This test does not pass if run normally. | ||
| 104 | // It only passes when a failure is injected into the EmbeddedUI launcher. | ||
| 105 | ////[TestMethod] | ||
| 106 | public void EmbeddedUIInitializeFails() | ||
| 107 | { | ||
| 108 | string dbFile = "EmbeddedUIInitializeFails.msi"; | ||
| 109 | string productCode; | ||
| 110 | |||
| 111 | string uiDir = Path.GetFullPath(EmbeddedExternalUI.EmbeddedUISampleBinDir); | ||
| 112 | string uiFile = "WixToolset.Dtf.Samples.EmbeddedUI.dll"; | ||
| 113 | |||
| 114 | // A number that will be used to check whether a type 19 CA runs. | ||
| 115 | const string magicNumber = "3.14159265358979323846264338327950"; | ||
| 116 | |||
| 117 | using (Database db = new Database(dbFile, DatabaseOpenMode.CreateDirect)) | ||
| 118 | { | ||
| 119 | WindowsInstallerUtils.InitializeProductDatabase(db); | ||
| 120 | WindowsInstallerUtils.CreateTestProduct(db); | ||
| 121 | |||
| 122 | const string failureActionName = "EmbeddedUIInitializeFails"; | ||
| 123 | db.Execute("INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) " + | ||
| 124 | "VALUES ('{0}', 19, '', 'Logging magic number: {1}')", failureActionName, magicNumber); | ||
| 125 | |||
| 126 | // This type 19 CA (launch condition) is given a condition of 'UILevel = 3' so that it only runs if the | ||
| 127 | // installation is running in BASIC UI mode, which is what we expect if the EmbeddedUI fails to initialize. | ||
| 128 | db.Execute("INSERT INTO `InstallExecuteSequence` (`Action`, `Condition`, `Sequence`) " + | ||
| 129 | "VALUES ('{0}', 'UILevel = 3', 1)", failureActionName); | ||
| 130 | |||
| 131 | productCode = db.ExecuteStringQuery("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'")[0]; | ||
| 132 | |||
| 133 | using (Record uiRec = new Record(5)) | ||
| 134 | { | ||
| 135 | uiRec[1] = "TestEmbeddedUI"; | ||
| 136 | uiRec[2] = Path.GetFileNameWithoutExtension(uiFile) + ".Wrapper.dll"; | ||
| 137 | uiRec[3] = 1; | ||
| 138 | uiRec[4] = (int)( | ||
| 139 | EmbeddedExternalUI.TestLogModes | | ||
| 140 | InstallLogModes.Progress | | ||
| 141 | InstallLogModes.Initialize | | ||
| 142 | InstallLogModes.Terminate | | ||
| 143 | InstallLogModes.ShowDialog); | ||
| 144 | uiRec.SetStream(5, Path.Combine(uiDir, uiFile)); | ||
| 145 | db.Execute(db.Tables["MsiEmbeddedUI"].SqlInsertString, uiRec); | ||
| 146 | } | ||
| 147 | |||
| 148 | db.Commit(); | ||
| 149 | } | ||
| 150 | |||
| 151 | Installer.SetInternalUI(InstallUIOptions.Full); | ||
| 152 | |||
| 153 | ProductInstallation installation = new ProductInstallation(productCode); | ||
| 154 | Assert.IsFalse(installation.IsInstalled, "Checking that product is not installed before starting."); | ||
| 155 | |||
| 156 | string logFile = "install.log"; | ||
| 157 | Exception caughtEx = null; | ||
| 158 | try | ||
| 159 | { | ||
| 160 | Installer.EnableLog(EmbeddedExternalUI.TestLogModes, logFile); | ||
| 161 | Installer.InstallProduct(dbFile, String.Empty); | ||
| 162 | } | ||
| 163 | catch (Exception ex) { caughtEx = ex; } | ||
| 164 | Assert.IsInstanceOfType(caughtEx, typeof(InstallerException), | ||
| 165 | "Excpected InstallerException installing product; caught: " + caughtEx); | ||
| 166 | |||
| 167 | Assert.IsFalse(installation.IsInstalled, "Checking that product is not installed."); | ||
| 168 | |||
| 169 | string logText = File.ReadAllText(logFile); | ||
| 170 | Assert.IsTrue(logText.Contains(magicNumber), "Checking that the type 19 custom action ran."); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | } | ||
diff --git a/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/Schema.cs b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/Schema.cs new file mode 100644 index 00000000..26c172c9 --- /dev/null +++ b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/Schema.cs | |||
| @@ -0,0 +1,238 @@ | |||
| 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 | namespace WixToolset.Dtf.Test | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using System.Collections.Generic; | ||
| 8 | using System.Text; | ||
| 9 | using WixToolset.Dtf.WindowsInstaller; | ||
| 10 | |||
| 11 | public static class Schema | ||
| 12 | { | ||
| 13 | public static IList<TableInfo> Tables | ||
| 14 | { | ||
| 15 | get | ||
| 16 | { | ||
| 17 | return new TableInfo[] | ||
| 18 | { | ||
| 19 | Binary, | ||
| 20 | Component, | ||
| 21 | CustomAction, | ||
| 22 | Directory, | ||
| 23 | EmbeddedUI, | ||
| 24 | Feature, | ||
| 25 | FeatureComponents, | ||
| 26 | File, | ||
| 27 | InstallExecuteSequence, | ||
| 28 | Media, | ||
| 29 | Property, | ||
| 30 | Registry | ||
| 31 | }; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | #region Table data | ||
| 36 | |||
| 37 | public static TableInfo Binary { get { return new TableInfo( | ||
| 38 | "Binary", | ||
| 39 | new ColumnInfo[] | ||
| 40 | { | ||
| 41 | new ColumnInfo("Name", typeof(String), 72, true), | ||
| 42 | new ColumnInfo("Data", typeof(Stream), 0, true), | ||
| 43 | }, | ||
| 44 | new string[] { "Name" }); | ||
| 45 | } } | ||
| 46 | |||
| 47 | public static TableInfo Component { get { return new TableInfo( | ||
| 48 | "Component", | ||
| 49 | new ColumnInfo[] | ||
| 50 | { | ||
| 51 | new ColumnInfo("Component", typeof(String), 72, true), | ||
| 52 | new ColumnInfo("ComponentId", typeof(String), 38, false), | ||
| 53 | new ColumnInfo("Directory_", typeof(String), 72, true), | ||
| 54 | new ColumnInfo("Attributes", typeof(Int16), 2, true), | ||
| 55 | new ColumnInfo("Condition", typeof(String), 255, false), | ||
| 56 | new ColumnInfo("KeyPath", typeof(String), 72, false), | ||
| 57 | }, | ||
| 58 | new string[] { "Component" }); | ||
| 59 | } } | ||
| 60 | |||
| 61 | public static TableInfo CustomAction { get { return new TableInfo( | ||
| 62 | "CustomAction", | ||
| 63 | new ColumnInfo[] | ||
| 64 | { | ||
| 65 | new ColumnInfo("Action", typeof(String), 72, true), | ||
| 66 | new ColumnInfo("Type", typeof(Int16), 2, true), | ||
| 67 | new ColumnInfo("Source", typeof(String), 64, false), | ||
| 68 | new ColumnInfo("Target", typeof(String), 255, false), | ||
| 69 | }, | ||
| 70 | new string[] { "Action" }); | ||
| 71 | } } | ||
| 72 | |||
| 73 | public static TableInfo Directory { get { return new TableInfo( | ||
| 74 | "Directory", | ||
| 75 | new ColumnInfo[] | ||
| 76 | { | ||
| 77 | new ColumnInfo("Directory", typeof(String), 72, true), | ||
| 78 | new ColumnInfo("Directory_Parent", typeof(String), 72, false), | ||
| 79 | new ColumnInfo("DefaultDir", typeof(String), 255, true, false, true), | ||
| 80 | }, | ||
| 81 | new string[] { "Directory" }); | ||
| 82 | } } | ||
| 83 | |||
| 84 | public static TableInfo EmbeddedUI { get { return new TableInfo( | ||
| 85 | "MsiEmbeddedUI", | ||
| 86 | new ColumnInfo[] | ||
| 87 | { | ||
| 88 | new ColumnInfo("MsiEmbeddedUI", typeof(String), 72, true), | ||
| 89 | new ColumnInfo("FileName", typeof(String), 72, true), | ||
| 90 | new ColumnInfo("Attributes", typeof(Int16), 2, true), | ||
| 91 | new ColumnInfo("MessageFilter", typeof(Int32), 4, false), | ||
| 92 | new ColumnInfo("Data", typeof(Stream), 0, true), | ||
| 93 | }, | ||
| 94 | new string[] { "MsiEmbeddedUI" }); | ||
| 95 | } } | ||
| 96 | |||
| 97 | public static TableInfo Feature { get { return new TableInfo( | ||
| 98 | "Feature", | ||
| 99 | new ColumnInfo[] | ||
| 100 | { | ||
| 101 | new ColumnInfo("Feature", typeof(String), 38, true), | ||
| 102 | new ColumnInfo("Feature_Parent", typeof(String), 38, false), | ||
| 103 | new ColumnInfo("Title", typeof(String), 64, false, false, true), | ||
| 104 | new ColumnInfo("Description", typeof(String), 64, false, false, true), | ||
| 105 | new ColumnInfo("Display", typeof(Int16), 2, false), | ||
| 106 | new ColumnInfo("Level", typeof(Int16), 2, true), | ||
| 107 | new ColumnInfo("Directory_", typeof(String), 72, false), | ||
| 108 | new ColumnInfo("Attributes", typeof(Int16), 2, true), | ||
| 109 | }, | ||
| 110 | new string[] { "Feature" }); | ||
| 111 | } } | ||
| 112 | |||
| 113 | public static TableInfo FeatureComponents { get { return new TableInfo( | ||
| 114 | "FeatureComponents", | ||
| 115 | new ColumnInfo[] | ||
| 116 | { | ||
| 117 | new ColumnInfo("Feature_", typeof(String), 38, true), | ||
| 118 | new ColumnInfo("Component_", typeof(String), 72, true), | ||
| 119 | }, | ||
| 120 | new string[] { "Feature_", "Component_" }); | ||
| 121 | } } | ||
| 122 | |||
| 123 | public static TableInfo File { get { return new TableInfo( | ||
| 124 | "File", | ||
| 125 | new ColumnInfo[] | ||
| 126 | { | ||
| 127 | new ColumnInfo("File", typeof(String), 72, true), | ||
| 128 | new ColumnInfo("Component_", typeof(String), 72, true), | ||
| 129 | new ColumnInfo("FileName", typeof(String), 255, true, false, true), | ||
| 130 | new ColumnInfo("FileSize", typeof(Int32), 4, true), | ||
| 131 | new ColumnInfo("Version", typeof(String), 72, false), | ||
| 132 | new ColumnInfo("Language", typeof(String), 20, false), | ||
| 133 | new ColumnInfo("Attributes", typeof(Int16), 2, false), | ||
| 134 | new ColumnInfo("Sequence", typeof(Int16), 2, true), | ||
| 135 | }, | ||
| 136 | new string[] { "File" }); | ||
| 137 | } } | ||
| 138 | |||
| 139 | public static TableInfo InstallExecuteSequence { get { return new TableInfo( | ||
| 140 | "InstallExecuteSequence", | ||
| 141 | new ColumnInfo[] | ||
| 142 | { | ||
| 143 | new ColumnInfo("Action", typeof(String), 72, true), | ||
| 144 | new ColumnInfo("Condition", typeof(String), 255, false), | ||
| 145 | new ColumnInfo("Sequence", typeof(Int16), 2, true), | ||
| 146 | }, | ||
| 147 | new string[] { "Action" }); | ||
| 148 | } } | ||
| 149 | |||
| 150 | public static TableInfo Media { get { return new TableInfo( | ||
| 151 | "Media", | ||
| 152 | new ColumnInfo[] | ||
| 153 | { | ||
| 154 | new ColumnInfo("DiskId", typeof(Int16), 2, true), | ||
| 155 | new ColumnInfo("LastSequence", typeof(Int16), 2, true), | ||
| 156 | new ColumnInfo("DiskPrompt", typeof(String), 64, false, false, true), | ||
| 157 | new ColumnInfo("Cabinet", typeof(String), 255, false), | ||
| 158 | new ColumnInfo("VolumeLabel", typeof(String), 32, false), | ||
| 159 | new ColumnInfo("Source", typeof(String), 32, false), | ||
| 160 | }, | ||
| 161 | new string[] { "DiskId" }); | ||
| 162 | } } | ||
| 163 | |||
| 164 | public static TableInfo Property { get { return new TableInfo( | ||
| 165 | "Property", | ||
| 166 | new ColumnInfo[] | ||
| 167 | { | ||
| 168 | new ColumnInfo("Property", typeof(String), 72, true), | ||
| 169 | new ColumnInfo("Value", typeof(String), 255, true), | ||
| 170 | }, | ||
| 171 | new string[] { "Property" }); | ||
| 172 | } } | ||
| 173 | |||
| 174 | public static TableInfo Registry { get { return new TableInfo( | ||
| 175 | "Registry", | ||
| 176 | new ColumnInfo[] | ||
| 177 | { | ||
| 178 | new ColumnInfo("Registry", typeof(String), 72, true), | ||
| 179 | new ColumnInfo("Root", typeof(Int16), 2, true), | ||
| 180 | new ColumnInfo("Key", typeof(String), 255, true, false, true), | ||
| 181 | new ColumnInfo("Name", typeof(String), 255, false, false, true), | ||
| 182 | new ColumnInfo("Value", typeof(String), 0, false, false, true), | ||
| 183 | new ColumnInfo("Component_", typeof(String), 72, true), | ||
| 184 | }, | ||
| 185 | new string[] { "Registry" }); | ||
| 186 | } } | ||
| 187 | |||
| 188 | #endregion | ||
| 189 | |||
| 190 | } | ||
| 191 | |||
| 192 | public class Action | ||
| 193 | { | ||
| 194 | public readonly string Name; | ||
| 195 | public readonly int Sequence; | ||
| 196 | |||
| 197 | public Action(string name, int sequence) | ||
| 198 | { | ||
| 199 | this.Name = name; | ||
| 200 | this.Sequence = sequence; | ||
| 201 | } | ||
| 202 | |||
| 203 | } | ||
| 204 | |||
| 205 | public class Sequence | ||
| 206 | { | ||
| 207 | public static IList<Action> InstallExecute | ||
| 208 | { | ||
| 209 | get | ||
| 210 | { | ||
| 211 | return new Action[] | ||
| 212 | { | ||
| 213 | new Action("CostInitialize", 800), | ||
| 214 | new Action("FileCost", 900), | ||
| 215 | new Action("CostFinalize", 1000), | ||
| 216 | new Action("InstallValidate", 1400), | ||
| 217 | new Action("InstallInitialize", 1500), | ||
| 218 | new Action("ProcessComponents", 1600), | ||
| 219 | new Action("UnpublishComponents", 1700), | ||
| 220 | new Action("UnpublishFeatures", 1800), | ||
| 221 | new Action("RemoveRegistryValues", 2600), | ||
| 222 | new Action("RemoveFiles", 3500), | ||
| 223 | new Action("RemoveFolders", 3600), | ||
| 224 | new Action("CreateFolders", 3700), | ||
| 225 | new Action("MoveFiles", 3800), | ||
| 226 | new Action("InstallFiles", 4000), | ||
| 227 | new Action("WriteRegistryValues", 5000), | ||
| 228 | new Action("RegisterProduct", 6100), | ||
| 229 | new Action("PublishComponents", 6200), | ||
| 230 | new Action("PublishFeatures", 6300), | ||
| 231 | new Action("PublishProduct", 6400), | ||
| 232 | new Action("InstallFinalize", 6600), | ||
| 233 | }; | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | } | ||
| 238 | } | ||
diff --git a/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WindowsInstallerTest.cs b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WindowsInstallerTest.cs new file mode 100644 index 00000000..f994dfef --- /dev/null +++ b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WindowsInstallerTest.cs | |||
| @@ -0,0 +1,409 @@ | |||
| 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 | namespace WixToolset.Dtf.Test | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using System.Windows.Forms; | ||
| 8 | using System.Globalization; | ||
| 9 | using System.Collections.Generic; | ||
| 10 | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
| 11 | using WixToolset.Dtf.WindowsInstaller; | ||
| 12 | using View = WixToolset.Dtf.WindowsInstaller.View; | ||
| 13 | |||
| 14 | [TestClass] | ||
| 15 | public class WindowsInstallerTest | ||
| 16 | { | ||
| 17 | public WindowsInstallerTest() | ||
| 18 | { | ||
| 19 | } | ||
| 20 | |||
| 21 | [TestInitialize()] | ||
| 22 | public void Initialize() | ||
| 23 | { | ||
| 24 | } | ||
| 25 | |||
| 26 | [TestCleanup()] | ||
| 27 | public void Cleanup() | ||
| 28 | { | ||
| 29 | } | ||
| 30 | |||
| 31 | [TestMethod] | ||
| 32 | [Ignore] // Currently fails. | ||
| 33 | public void InstallerErrorMessages() | ||
| 34 | { | ||
| 35 | string msg3002 = Installer.GetErrorMessage(3002); | ||
| 36 | Console.WriteLine("3002=" + msg3002); | ||
| 37 | Assert.IsNotNull(msg3002); | ||
| 38 | Assert.IsTrue(msg3002.Length > 0); | ||
| 39 | } | ||
| 40 | |||
| 41 | [TestMethod] | ||
| 42 | public void InstallerDatabaseSchema() | ||
| 43 | { | ||
| 44 | string dbFile = "InstallerDatabaseSchema.msi"; | ||
| 45 | |||
| 46 | using (Database db = new Database(dbFile, DatabaseOpenMode.CreateDirect)) | ||
| 47 | { | ||
| 48 | WindowsInstallerUtils.InitializeProductDatabase(db); | ||
| 49 | db.Commit(); | ||
| 50 | } | ||
| 51 | |||
| 52 | Assert.IsTrue(File.Exists(dbFile), "Checking whether created database file " + dbFile + " exists."); | ||
| 53 | |||
| 54 | using (Database db = new Database(dbFile, DatabaseOpenMode.ReadOnly)) | ||
| 55 | { | ||
| 56 | TableCollection tables = db.Tables; | ||
| 57 | Assert.AreEqual<int>(Schema.Tables.Count, tables.Count, "Counting tables."); | ||
| 58 | Assert.AreEqual<int>(Schema.Property.Columns.Count, tables["Property"].Columns.Count, "Counting columns in Property table."); | ||
| 59 | |||
| 60 | foreach (TableInfo tableInfo in tables) | ||
| 61 | { | ||
| 62 | Console.WriteLine(tableInfo.Name); | ||
| 63 | foreach (ColumnInfo columnInfo in tableInfo.Columns) | ||
| 64 | { | ||
| 65 | Console.WriteLine("\t{0} {1}", columnInfo.Name, columnInfo.ColumnDefinitionString); | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | [TestMethod] | ||
| 72 | public void InstallerViewTables() | ||
| 73 | { | ||
| 74 | string dbFile = "InstallerViewTables.msi"; | ||
| 75 | |||
| 76 | using (Database db = new Database(dbFile, DatabaseOpenMode.CreateDirect)) | ||
| 77 | { | ||
| 78 | WindowsInstallerUtils.InitializeProductDatabase(db); | ||
| 79 | db.Commit(); | ||
| 80 | |||
| 81 | using (View view1 = db.OpenView("SELECT `Property`, `Value` FROM `Property` WHERE `Value` IS NOT NULL")) | ||
| 82 | { | ||
| 83 | IList<TableInfo> viewTables = view1.Tables; | ||
| 84 | Assert.IsNotNull(viewTables); | ||
| 85 | Assert.AreEqual<int>(1, viewTables.Count); | ||
| 86 | Assert.AreEqual<String>("Property", viewTables[0].Name); | ||
| 87 | } | ||
| 88 | |||
| 89 | using (View view2 = db.OpenView("INSERT INTO `Property` (`Property`, `Value`) VALUES ('TestViewTables', 1)")) | ||
| 90 | { | ||
| 91 | IList<TableInfo> viewTables = view2.Tables; | ||
| 92 | Assert.IsNotNull(viewTables); | ||
| 93 | Assert.AreEqual<int>(1, viewTables.Count); | ||
| 94 | Assert.AreEqual<String>("Property", viewTables[0].Name); | ||
| 95 | } | ||
| 96 | |||
| 97 | using (View view3 = db.OpenView("UPDATE `Property` SET `Value` = 2 WHERE `Property` = 'TestViewTables'")) | ||
| 98 | { | ||
| 99 | IList<TableInfo> viewTables = view3.Tables; | ||
| 100 | Assert.IsNotNull(viewTables); | ||
| 101 | Assert.AreEqual<int>(1, viewTables.Count); | ||
| 102 | Assert.AreEqual<String>("Property", viewTables[0].Name); | ||
| 103 | } | ||
| 104 | |||
| 105 | using (View view4 = db.OpenView("alter table Property hold")) | ||
| 106 | { | ||
| 107 | IList<TableInfo> viewTables = view4.Tables; | ||
| 108 | Assert.IsNotNull(viewTables); | ||
| 109 | Assert.AreEqual<int>(1, viewTables.Count); | ||
| 110 | Assert.AreEqual<String>("Property", viewTables[0].Name); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | [TestMethod] | ||
| 116 | public void InstallerInstallProduct() | ||
| 117 | { | ||
| 118 | string dbFile = "InstallerInstallProduct.msi"; | ||
| 119 | string productCode; | ||
| 120 | |||
| 121 | using (Database db = new Database(dbFile, DatabaseOpenMode.CreateDirect)) | ||
| 122 | { | ||
| 123 | WindowsInstallerUtils.InitializeProductDatabase(db); | ||
| 124 | WindowsInstallerUtils.CreateTestProduct(db); | ||
| 125 | |||
| 126 | productCode = db.ExecuteStringQuery("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'")[0]; | ||
| 127 | |||
| 128 | db.Commit(); | ||
| 129 | } | ||
| 130 | |||
| 131 | ProductInstallation installation = new ProductInstallation(productCode); | ||
| 132 | Assert.IsFalse(installation.IsInstalled, "Checking that product is not installed before starting."); | ||
| 133 | |||
| 134 | Installer.SetInternalUI(InstallUIOptions.Silent); | ||
| 135 | ExternalUIHandler prevHandler = Installer.SetExternalUI(WindowsInstallerTest.ExternalUILogger, | ||
| 136 | InstallLogModes.FatalExit | | ||
| 137 | InstallLogModes.Error | | ||
| 138 | InstallLogModes.Warning | | ||
| 139 | InstallLogModes.User | | ||
| 140 | InstallLogModes.Info | | ||
| 141 | InstallLogModes.ResolveSource | | ||
| 142 | InstallLogModes.OutOfDiskSpace | | ||
| 143 | InstallLogModes.ActionStart | | ||
| 144 | InstallLogModes.ActionData | | ||
| 145 | InstallLogModes.CommonData | | ||
| 146 | InstallLogModes.Progress | | ||
| 147 | InstallLogModes.Initialize | | ||
| 148 | InstallLogModes.Terminate | | ||
| 149 | InstallLogModes.ShowDialog); | ||
| 150 | Assert.IsNull(prevHandler, "Checking that returned previous UI handler is null."); | ||
| 151 | |||
| 152 | Exception caughtEx = null; | ||
| 153 | try | ||
| 154 | { | ||
| 155 | Installer.InstallProduct(dbFile, String.Empty); | ||
| 156 | } | ||
| 157 | catch (Exception ex) { caughtEx = ex; } | ||
| 158 | Assert.IsNull(caughtEx, "Exception thrown while installing product: " + caughtEx); | ||
| 159 | |||
| 160 | prevHandler = Installer.SetExternalUI(prevHandler, InstallLogModes.None); | ||
| 161 | Assert.AreEqual<ExternalUIHandler>(WindowsInstallerTest.ExternalUILogger, prevHandler, "Checking that previously-set UI handler is returned."); | ||
| 162 | |||
| 163 | Assert.IsTrue(installation.IsInstalled, "Checking that product is installed."); | ||
| 164 | Console.WriteLine(); | ||
| 165 | Console.WriteLine(); | ||
| 166 | Console.WriteLine(); | ||
| 167 | Console.WriteLine("==================================================================="); | ||
| 168 | Console.WriteLine(); | ||
| 169 | Console.WriteLine(); | ||
| 170 | Console.WriteLine(); | ||
| 171 | |||
| 172 | ExternalUIRecordHandler prevRecHandler = Installer.SetExternalUI(WindowsInstallerTest.ExternalUIRecordLogger, | ||
| 173 | InstallLogModes.FatalExit | | ||
| 174 | InstallLogModes.Error | | ||
| 175 | InstallLogModes.Warning | | ||
| 176 | InstallLogModes.User | | ||
| 177 | InstallLogModes.Info | | ||
| 178 | InstallLogModes.ResolveSource | | ||
| 179 | InstallLogModes.OutOfDiskSpace | | ||
| 180 | InstallLogModes.ActionStart | | ||
| 181 | InstallLogModes.ActionData | | ||
| 182 | InstallLogModes.CommonData | | ||
| 183 | InstallLogModes.Progress | | ||
| 184 | InstallLogModes.Initialize | | ||
| 185 | InstallLogModes.Terminate | | ||
| 186 | InstallLogModes.ShowDialog); | ||
| 187 | Assert.IsNull(prevRecHandler, "Checking that returned previous UI record handler is null."); | ||
| 188 | |||
| 189 | try | ||
| 190 | { | ||
| 191 | Installer.InstallProduct(dbFile, "REMOVE=All"); | ||
| 192 | } | ||
| 193 | catch (Exception ex) { caughtEx = ex; } | ||
| 194 | Assert.IsNull(caughtEx, "Exception thrown while installing product: " + caughtEx); | ||
| 195 | |||
| 196 | Assert.IsFalse(installation.IsInstalled, "Checking that product is not installed after removing."); | ||
| 197 | |||
| 198 | prevRecHandler = Installer.SetExternalUI(prevRecHandler, InstallLogModes.None); | ||
| 199 | Assert.AreEqual<ExternalUIRecordHandler>(WindowsInstallerTest.ExternalUIRecordLogger, prevRecHandler, "Checking that previously-set UI record handler is returned."); | ||
| 200 | } | ||
| 201 | |||
| 202 | public static MessageResult ExternalUILogger( | ||
| 203 | InstallMessage messageType, | ||
| 204 | string message, | ||
| 205 | MessageButtons buttons, | ||
| 206 | MessageIcon icon, | ||
| 207 | MessageDefaultButton defaultButton) | ||
| 208 | { | ||
| 209 | Console.WriteLine("{0}: {1}", messageType, message); | ||
| 210 | return MessageResult.None; | ||
| 211 | } | ||
| 212 | |||
| 213 | public static MessageResult ExternalUIRecordLogger( | ||
| 214 | InstallMessage messageType, | ||
| 215 | Record messageRecord, | ||
| 216 | MessageButtons buttons, | ||
| 217 | MessageIcon icon, | ||
| 218 | MessageDefaultButton defaultButton) | ||
| 219 | { | ||
| 220 | if (messageRecord != null) | ||
| 221 | { | ||
| 222 | if (messageRecord.FormatString.Length == 0 && messageRecord.FieldCount > 0) | ||
| 223 | { | ||
| 224 | messageRecord.FormatString = "1: [1] 2: [2] 3: [3] 4: [4] 5: [5]"; | ||
| 225 | } | ||
| 226 | Console.WriteLine("{0}: {1}", messageType, messageRecord.ToString()); | ||
| 227 | } | ||
| 228 | else | ||
| 229 | { | ||
| 230 | Console.WriteLine("{0}: (null)", messageType); | ||
| 231 | } | ||
| 232 | return MessageResult.None; | ||
| 233 | } | ||
| 234 | |||
| 235 | [TestMethod] | ||
| 236 | [Ignore] // Currently fails. | ||
| 237 | public void InstallerMessageResources() | ||
| 238 | { | ||
| 239 | string message1101 = Installer.GetErrorMessage(1101); | ||
| 240 | Console.WriteLine("Message 1101: " + message1101); | ||
| 241 | Assert.IsNotNull(message1101); | ||
| 242 | Assert.IsTrue(message1101.Contains("file")); | ||
| 243 | |||
| 244 | message1101 = Installer.GetErrorMessage(1101, CultureInfo.GetCultureInfo(1033)); | ||
| 245 | Console.WriteLine("Message 1101: " + message1101); | ||
| 246 | Assert.IsNotNull(message1101); | ||
| 247 | Assert.IsTrue(message1101.Contains("file")); | ||
| 248 | |||
| 249 | string message2621 = Installer.GetErrorMessage(2621); | ||
| 250 | Console.WriteLine("Message 2621: " + message2621); | ||
| 251 | Assert.IsNotNull(message2621); | ||
| 252 | Assert.IsTrue(message2621.Contains("DLL")); | ||
| 253 | |||
| 254 | string message3002 = Installer.GetErrorMessage(3002); | ||
| 255 | Console.WriteLine("Message 3002: " + message3002); | ||
| 256 | Assert.IsNotNull(message3002); | ||
| 257 | Assert.IsTrue(message3002.Contains("sequencing")); | ||
| 258 | } | ||
| 259 | |||
| 260 | [TestMethod] | ||
| 261 | public void EnumComponentQualifiers() | ||
| 262 | { | ||
| 263 | foreach (ComponentInstallation comp in ComponentInstallation.AllComponents) | ||
| 264 | { | ||
| 265 | bool qualifiers = false; | ||
| 266 | foreach (ComponentInstallation.Qualifier qualifier in comp.Qualifiers) | ||
| 267 | { | ||
| 268 | if (!qualifiers) | ||
| 269 | { | ||
| 270 | Console.WriteLine(comp.Path); | ||
| 271 | qualifiers = true; | ||
| 272 | } | ||
| 273 | |||
| 274 | Console.WriteLine("\t{0}: {1}", qualifier.QualifierCode, qualifier.Data); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | [TestMethod] | ||
| 280 | public void DeleteRecord() | ||
| 281 | { | ||
| 282 | string dbFile = "DeleteRecord.msi"; | ||
| 283 | |||
| 284 | using (Database db = new Database(dbFile, DatabaseOpenMode.CreateDirect)) | ||
| 285 | { | ||
| 286 | WindowsInstallerUtils.InitializeProductDatabase(db); | ||
| 287 | WindowsInstallerUtils.CreateTestProduct(db); | ||
| 288 | |||
| 289 | string query = "SELECT `Property`, `Value` FROM `Property` WHERE `Property` = 'UpgradeCode'"; | ||
| 290 | |||
| 291 | using (View view = db.OpenView(query)) | ||
| 292 | { | ||
| 293 | view.Execute(); | ||
| 294 | |||
| 295 | Record rec = view.Fetch(); | ||
| 296 | |||
| 297 | Console.WriteLine("Calling ToString() : " + rec); | ||
| 298 | |||
| 299 | view.Delete(rec); | ||
| 300 | } | ||
| 301 | |||
| 302 | Assert.AreEqual(0, db.ExecuteStringQuery(query).Count); | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | [TestMethod] | ||
| 307 | public void InsertRecordThenTryFormatString() | ||
| 308 | { | ||
| 309 | string dbFile = "InsertRecordThenTryFormatString.msi"; | ||
| 310 | |||
| 311 | using (Database db = new Database(dbFile, DatabaseOpenMode.CreateDirect)) | ||
| 312 | { | ||
| 313 | WindowsInstallerUtils.InitializeProductDatabase(db); | ||
| 314 | WindowsInstallerUtils.CreateTestProduct(db); | ||
| 315 | |||
| 316 | string parameterFormatString = "[1]"; | ||
| 317 | string[] properties = new string[] | ||
| 318 | { | ||
| 319 | "SonGoku", "Over 9000", | ||
| 320 | }; | ||
| 321 | |||
| 322 | string query = "SELECT `Property`, `Value` FROM `Property`"; | ||
| 323 | |||
| 324 | using (View view = db.OpenView(query)) | ||
| 325 | { | ||
| 326 | using (Record rec = new Record(2)) | ||
| 327 | { | ||
| 328 | rec[1] = properties[0]; | ||
| 329 | rec[2] = properties[1]; | ||
| 330 | rec.FormatString = parameterFormatString; | ||
| 331 | Console.WriteLine("Format String before inserting: " + rec.FormatString); | ||
| 332 | view.Insert(rec); | ||
| 333 | |||
| 334 | Console.WriteLine("Format String after inserting: " + rec.FormatString); | ||
| 335 | // After inserting, the format string is invalid. | ||
| 336 | Assert.AreEqual(String.Empty, rec.ToString()); | ||
| 337 | |||
| 338 | // Setting the format string manually makes it valid again. | ||
| 339 | rec.FormatString = parameterFormatString; | ||
| 340 | Assert.AreEqual(properties[0], rec.ToString()); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | } | ||
| 344 | } | ||
| 345 | |||
| 346 | [TestMethod] | ||
| 347 | public void SeekRecordThenTryFormatString() | ||
| 348 | { | ||
| 349 | string dbFile = "SeekRecordThenTryFormatString.msi"; | ||
| 350 | |||
| 351 | using (Database db = new Database(dbFile, DatabaseOpenMode.CreateDirect)) | ||
| 352 | { | ||
| 353 | WindowsInstallerUtils.InitializeProductDatabase(db); | ||
| 354 | WindowsInstallerUtils.CreateTestProduct(db); | ||
| 355 | |||
| 356 | string parameterFormatString = "[1]"; | ||
| 357 | string[] properties = new string[] | ||
| 358 | { | ||
| 359 | "SonGoku", "Over 9000", | ||
| 360 | }; | ||
| 361 | |||
| 362 | string query = "SELECT `Property`, `Value` FROM `Property`"; | ||
| 363 | |||
| 364 | using (View view = db.OpenView(query)) | ||
| 365 | { | ||
| 366 | using (Record rec = new Record(2)) | ||
| 367 | { | ||
| 368 | rec[1] = properties[0]; | ||
| 369 | rec[2] = properties[1]; | ||
| 370 | rec.FormatString = parameterFormatString; | ||
| 371 | Console.WriteLine("Record fields before seeking: " + rec[0] + " " + rec[1] + " " + rec[2]); | ||
| 372 | view.Seek(rec); | ||
| 373 | |||
| 374 | //TODO: Why does view.Seek remove the record fields? | ||
| 375 | Console.WriteLine("Record fields after seeking: " + rec[0] + " " + rec[1] + " " + rec[2]); | ||
| 376 | // After inserting, the format string is invalid. | ||
| 377 | Assert.AreEqual(String.Empty, rec.ToString()); | ||
| 378 | } | ||
| 379 | } | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | [TestMethod] | ||
| 384 | public void TestToString() | ||
| 385 | { | ||
| 386 | string defaultString = "1: "; | ||
| 387 | string vegetaShout = "It's OVER 9000!!"; | ||
| 388 | string gokuPowerLevel = "9001"; | ||
| 389 | string nappaInquiry = "Vegeta, what's the Scouter say about his power level?"; | ||
| 390 | string parameterFormatString = "[1]"; | ||
| 391 | |||
| 392 | Record rec = new Record(1); | ||
| 393 | Assert.AreEqual(defaultString, rec.ToString(), "Testing default FormatString"); | ||
| 394 | |||
| 395 | rec.FormatString = String.Empty; | ||
| 396 | Assert.AreEqual(defaultString, rec.ToString(), "Explicitly set the FormatString to the empty string."); | ||
| 397 | |||
| 398 | rec.FormatString = vegetaShout; | ||
| 399 | Assert.AreEqual(vegetaShout, rec.ToString(), "Testing text only (empty FormatString)"); | ||
| 400 | |||
| 401 | rec.FormatString = gokuPowerLevel; | ||
| 402 | Assert.AreEqual(gokuPowerLevel, rec.ToString(), "Testing numbers only from a record that wasn't fetched."); | ||
| 403 | |||
| 404 | Record rec2 = new Record(nappaInquiry); | ||
| 405 | rec2.FormatString = parameterFormatString; | ||
| 406 | Assert.AreEqual(nappaInquiry, rec2.ToString(), "Testing text with a FormatString set."); | ||
| 407 | } | ||
| 408 | } | ||
| 409 | } | ||
diff --git a/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WindowsInstallerTransactions.cs b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WindowsInstallerTransactions.cs new file mode 100644 index 00000000..3bdf5acd --- /dev/null +++ b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WindowsInstallerTransactions.cs | |||
| @@ -0,0 +1,161 @@ | |||
| 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 | namespace WixToolset.Dtf.Test | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using System.Windows.Forms; | ||
| 8 | using System.Globalization; | ||
| 9 | using System.Collections.Generic; | ||
| 10 | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
| 11 | using WixToolset.Dtf.WindowsInstaller; | ||
| 12 | using View = WixToolset.Dtf.WindowsInstaller.View; | ||
| 13 | |||
| 14 | [TestClass] | ||
| 15 | public class WindowsInstallerTransactions | ||
| 16 | { | ||
| 17 | [TestInitialize()] | ||
| 18 | public void Initialize() | ||
| 19 | { | ||
| 20 | } | ||
| 21 | |||
| 22 | [TestCleanup()] | ||
| 23 | public void Cleanup() | ||
| 24 | { | ||
| 25 | } | ||
| 26 | |||
| 27 | [TestMethod] | ||
| 28 | [Ignore] // Requires elevation. | ||
| 29 | public void InstallerTransactTwoProducts() | ||
| 30 | { | ||
| 31 | string dbFile1 = "InstallerTransactProduct1.msi"; | ||
| 32 | string dbFile2 = "InstallerTransactProduct2.msi"; | ||
| 33 | string productCode1; | ||
| 34 | string productCode2; | ||
| 35 | |||
| 36 | using (Database db1 = new Database(dbFile1, DatabaseOpenMode.CreateDirect)) | ||
| 37 | { | ||
| 38 | WindowsInstallerUtils.InitializeProductDatabase(db1); | ||
| 39 | WindowsInstallerUtils.CreateTestProduct(db1); | ||
| 40 | |||
| 41 | productCode1 = db1.ExecuteStringQuery("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'")[0]; | ||
| 42 | |||
| 43 | db1.Commit(); | ||
| 44 | } | ||
| 45 | |||
| 46 | using (Database db2 = new Database(dbFile2, DatabaseOpenMode.CreateDirect)) | ||
| 47 | { | ||
| 48 | WindowsInstallerUtils.InitializeProductDatabase(db2); | ||
| 49 | WindowsInstallerUtils.CreateTestProduct(db2); | ||
| 50 | |||
| 51 | productCode2 = db2.ExecuteStringQuery("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'")[0]; | ||
| 52 | |||
| 53 | db2.Commit(); | ||
| 54 | } | ||
| 55 | |||
| 56 | ProductInstallation installation1 = new ProductInstallation(productCode1); | ||
| 57 | ProductInstallation installation2 = new ProductInstallation(productCode2); | ||
| 58 | Assert.IsFalse(installation1.IsInstalled, "Checking that product 1 is not installed before starting."); | ||
| 59 | Assert.IsFalse(installation2.IsInstalled, "Checking that product 2 is not installed before starting."); | ||
| 60 | |||
| 61 | Installer.SetInternalUI(InstallUIOptions.Silent); | ||
| 62 | ExternalUIHandler prevHandler = Installer.SetExternalUI(WindowsInstallerTest.ExternalUILogger, | ||
| 63 | InstallLogModes.FatalExit | | ||
| 64 | InstallLogModes.Error | | ||
| 65 | InstallLogModes.Warning | | ||
| 66 | InstallLogModes.User | | ||
| 67 | InstallLogModes.Info | | ||
| 68 | InstallLogModes.ResolveSource | | ||
| 69 | InstallLogModes.OutOfDiskSpace | | ||
| 70 | InstallLogModes.ActionStart | | ||
| 71 | InstallLogModes.ActionData | | ||
| 72 | InstallLogModes.CommonData | | ||
| 73 | InstallLogModes.Progress | | ||
| 74 | InstallLogModes.Initialize | | ||
| 75 | InstallLogModes.Terminate | | ||
| 76 | InstallLogModes.ShowDialog); | ||
| 77 | Assert.IsNull(prevHandler, "Checking that returned previous UI handler is null."); | ||
| 78 | |||
| 79 | Transaction transaction = new Transaction("TestInstallTransaction", TransactionAttributes.None); | ||
| 80 | |||
| 81 | Exception caughtEx = null; | ||
| 82 | try | ||
| 83 | { | ||
| 84 | Installer.InstallProduct(dbFile1, String.Empty); | ||
| 85 | } | ||
| 86 | catch (Exception ex) { caughtEx = ex; } | ||
| 87 | Assert.IsNull(caughtEx, "Exception thrown while installing product 1: " + caughtEx); | ||
| 88 | |||
| 89 | Console.WriteLine(); | ||
| 90 | Console.WriteLine("==================================================================="); | ||
| 91 | Console.WriteLine(); | ||
| 92 | |||
| 93 | try | ||
| 94 | { | ||
| 95 | Installer.InstallProduct(dbFile2, String.Empty); | ||
| 96 | } | ||
| 97 | catch (Exception ex) { caughtEx = ex; } | ||
| 98 | Assert.IsNull(caughtEx, "Exception thrown while installing product 2: " + caughtEx); | ||
| 99 | |||
| 100 | transaction.Commit(); | ||
| 101 | transaction.Close(); | ||
| 102 | |||
| 103 | prevHandler = Installer.SetExternalUI(prevHandler, InstallLogModes.None); | ||
| 104 | Assert.AreEqual<ExternalUIHandler>(WindowsInstallerTest.ExternalUILogger, prevHandler, "Checking that previously-set UI handler is returned."); | ||
| 105 | |||
| 106 | Assert.IsTrue(installation1.IsInstalled, "Checking that product 1 is installed."); | ||
| 107 | Assert.IsTrue(installation2.IsInstalled, "Checking that product 2 is installed."); | ||
| 108 | |||
| 109 | Console.WriteLine(); | ||
| 110 | Console.WriteLine(); | ||
| 111 | Console.WriteLine(); | ||
| 112 | Console.WriteLine("==================================================================="); | ||
| 113 | Console.WriteLine("==================================================================="); | ||
| 114 | Console.WriteLine(); | ||
| 115 | Console.WriteLine(); | ||
| 116 | Console.WriteLine(); | ||
| 117 | |||
| 118 | ExternalUIRecordHandler prevRecHandler = Installer.SetExternalUI(WindowsInstallerTest.ExternalUIRecordLogger, | ||
| 119 | InstallLogModes.FatalExit | | ||
| 120 | InstallLogModes.Error | | ||
| 121 | InstallLogModes.Warning | | ||
| 122 | InstallLogModes.User | | ||
| 123 | InstallLogModes.Info | | ||
| 124 | InstallLogModes.ResolveSource | | ||
| 125 | InstallLogModes.OutOfDiskSpace | | ||
| 126 | InstallLogModes.ActionStart | | ||
| 127 | InstallLogModes.ActionData | | ||
| 128 | InstallLogModes.CommonData | | ||
| 129 | InstallLogModes.Progress | | ||
| 130 | InstallLogModes.Initialize | | ||
| 131 | InstallLogModes.Terminate | | ||
| 132 | InstallLogModes.ShowDialog); | ||
| 133 | Assert.IsNull(prevRecHandler, "Checking that returned previous UI record handler is null."); | ||
| 134 | |||
| 135 | transaction = new Transaction("TestUninstallTransaction", TransactionAttributes.None); | ||
| 136 | |||
| 137 | try | ||
| 138 | { | ||
| 139 | Installer.InstallProduct(dbFile1, "REMOVE=All"); | ||
| 140 | } | ||
| 141 | catch (Exception ex) { caughtEx = ex; } | ||
| 142 | Assert.IsNull(caughtEx, "Exception thrown while removing product 1: " + caughtEx); | ||
| 143 | |||
| 144 | try | ||
| 145 | { | ||
| 146 | Installer.InstallProduct(dbFile2, "REMOVE=All"); | ||
| 147 | } | ||
| 148 | catch (Exception ex) { caughtEx = ex; } | ||
| 149 | Assert.IsNull(caughtEx, "Exception thrown while removing product 2: " + caughtEx); | ||
| 150 | |||
| 151 | transaction.Commit(); | ||
| 152 | transaction.Close(); | ||
| 153 | |||
| 154 | Assert.IsFalse(installation1.IsInstalled, "Checking that product 1 is not installed after removing."); | ||
| 155 | Assert.IsFalse(installation2.IsInstalled, "Checking that product 2 is not installed after removing."); | ||
| 156 | |||
| 157 | prevRecHandler = Installer.SetExternalUI(prevRecHandler, InstallLogModes.None); | ||
| 158 | Assert.AreEqual<ExternalUIRecordHandler>(WindowsInstallerTest.ExternalUIRecordLogger, prevRecHandler, "Checking that previously-set UI record handler is returned."); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
diff --git a/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WindowsInstallerUtils.cs b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WindowsInstallerUtils.cs new file mode 100644 index 00000000..644f1988 --- /dev/null +++ b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WindowsInstallerUtils.cs | |||
| @@ -0,0 +1,174 @@ | |||
| 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 | namespace WixToolset.Dtf.Test | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.Text; | ||
| 8 | using WixToolset.Dtf.WindowsInstaller; | ||
| 9 | |||
| 10 | public class WindowsInstallerUtils | ||
| 11 | { | ||
| 12 | public static void InitializeProductDatabase(Database db) | ||
| 13 | { | ||
| 14 | InitializeProductDatabase(db, false); | ||
| 15 | } | ||
| 16 | |||
| 17 | public static void InitializeProductDatabase(Database db, bool sixtyFourBit) | ||
| 18 | { | ||
| 19 | db.SummaryInfo.CodePage = (short) Encoding.Default.CodePage; | ||
| 20 | db.SummaryInfo.Title = "Windows Installer Test"; | ||
| 21 | db.SummaryInfo.Subject = db.SummaryInfo.Title; | ||
| 22 | db.SummaryInfo.Author = typeof(WindowsInstallerUtils).Assembly.FullName; | ||
| 23 | db.SummaryInfo.CreatingApp = db.SummaryInfo.Author; | ||
| 24 | db.SummaryInfo.Comments = typeof(WindowsInstallerUtils).FullName + ".CreateBasicDatabase()"; | ||
| 25 | db.SummaryInfo.Keywords = "Installer,MSI,Database"; | ||
| 26 | db.SummaryInfo.PageCount = 300; | ||
| 27 | db.SummaryInfo.WordCount = 0; | ||
| 28 | db.SummaryInfo.RevisionNumber = Guid.NewGuid().ToString("B").ToUpper(); | ||
| 29 | db.SummaryInfo.Template = (sixtyFourBit ? "x64" : "Intel") + ";0"; | ||
| 30 | |||
| 31 | foreach (TableInfo tableInfo in Schema.Tables) | ||
| 32 | { | ||
| 33 | db.Execute(tableInfo.SqlCreateString); | ||
| 34 | } | ||
| 35 | |||
| 36 | db.Execute("INSERT INTO `Directory` (`Directory`, `DefaultDir`) VALUES ('TARGETDIR', 'SourceDir')"); | ||
| 37 | db.Execute("INSERT INTO `Directory` (`Directory`, `Directory_Parent`, `DefaultDir`) VALUES ('ProgramFilesFolder', 'TARGETDIR', '.')"); | ||
| 38 | |||
| 39 | foreach (Action action in Sequence.InstallExecute) | ||
| 40 | { | ||
| 41 | db.Execute("INSERT INTO `InstallExecuteSequence` (`Action`, `Sequence`) VALUES ('{0}', {1})", | ||
| 42 | action.Name, action.Sequence); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | public const string UpgradeCode = "{05955FE8-005F-4695-A81F-D559338065BB}"; | ||
| 47 | |||
| 48 | public static void CreateTestProduct(Database db) | ||
| 49 | { | ||
| 50 | Guid productGuid = Guid.NewGuid(); | ||
| 51 | |||
| 52 | string[] properties = new string[] | ||
| 53 | { | ||
| 54 | "ProductCode", productGuid.ToString("B").ToUpper(), | ||
| 55 | "UpgradeCode", UpgradeCode, | ||
| 56 | "ProductName", "Windows Installer Test Product " + productGuid.ToString("P").ToUpper(), | ||
| 57 | "ProductVersion", "1.0.0.0000", | ||
| 58 | }; | ||
| 59 | |||
| 60 | using (View view = db.OpenView("INSERT INTO `Property` (`Property`, `Value`) VALUES (?, ?)")) | ||
| 61 | { | ||
| 62 | using (Record rec = new Record(2)) | ||
| 63 | { | ||
| 64 | for (int i = 0; i < properties.Length; i += 2) | ||
| 65 | { | ||
| 66 | rec[1] = properties[i]; | ||
| 67 | rec[2] = properties[i + 1]; | ||
| 68 | view.Execute(rec); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | int randomId = new Random().Next(10000); | ||
| 74 | string productDir = "TestDir" + randomId; | ||
| 75 | db.Execute( | ||
| 76 | "INSERT INTO `Directory` (`Directory`, `Directory_Parent`, `DefaultDir`) " + | ||
| 77 | "VALUES ('TestDir', 'ProgramFilesFolder', 'TestDir|{0}:.')", productDir); | ||
| 78 | |||
| 79 | string compId = Guid.NewGuid().ToString("B").ToUpper(); | ||
| 80 | db.Execute( | ||
| 81 | "INSERT INTO `Component` " + | ||
| 82 | "(`Component`, `ComponentId`, `Directory_`, `Attributes`, `KeyPath`) " + | ||
| 83 | "VALUES ('{0}', '{1}', '{2}', {3}, '{4}')", | ||
| 84 | "TestRegComp1", | ||
| 85 | compId, | ||
| 86 | "TestDir", | ||
| 87 | (int) ComponentAttributes.RegistryKeyPath, | ||
| 88 | "TestReg1"); | ||
| 89 | |||
| 90 | string productReg = "TestReg" + randomId; | ||
| 91 | db.Execute( | ||
| 92 | "INSERT INTO `Registry` (`Registry`, `Root`, `Key`, `Component_`) VALUES ('{0}', {1}, '{2}', '{3}')", | ||
| 93 | "TestReg1", | ||
| 94 | -1, | ||
| 95 | @"Software\Microsoft\Windows Installer Test\" + productReg, | ||
| 96 | "TestRegComp1"); | ||
| 97 | |||
| 98 | db.Execute( | ||
| 99 | "INSERT INTO `Feature` (`Feature`, `Title`, `Level`, `Attributes`) VALUES ('{0}', '{1}', {2}, {3})", | ||
| 100 | "TestFeature1", | ||
| 101 | "Test Feature 1", | ||
| 102 | 1, | ||
| 103 | (int) FeatureAttributes.None); | ||
| 104 | |||
| 105 | db.Execute( | ||
| 106 | "INSERT INTO `FeatureComponents` (`Feature_`, `Component_`) VALUES ('{0}', '{1}')", | ||
| 107 | "TestFeature1", | ||
| 108 | "TestRegComp1"); | ||
| 109 | } | ||
| 110 | |||
| 111 | public static void AddFeature(Database db, string featureName) | ||
| 112 | { | ||
| 113 | db.Execute( | ||
| 114 | "INSERT INTO `Feature` (`Feature`, `Title`, `Level`, `Attributes`) VALUES ('{0}', '{1}', {2}, {3})", | ||
| 115 | featureName, | ||
| 116 | featureName, | ||
| 117 | 1, | ||
| 118 | (int) FeatureAttributes.None); | ||
| 119 | } | ||
| 120 | |||
| 121 | public static void AddRegistryComponent(Database db, | ||
| 122 | string featureName, string compName, string compId, | ||
| 123 | string keyName, string keyValueName, string value) | ||
| 124 | { | ||
| 125 | db.Execute( | ||
| 126 | "INSERT INTO `Component` " + | ||
| 127 | "(`Component`, `ComponentId`, `Directory_`, `Attributes`, `KeyPath`) " + | ||
| 128 | "VALUES ('{0}', '{1}', '{2}', {3}, '{4}')", | ||
| 129 | compName, | ||
| 130 | compId, | ||
| 131 | "TestDir", | ||
| 132 | (int) ComponentAttributes.RegistryKeyPath, | ||
| 133 | compName + "Reg1"); | ||
| 134 | db.Execute( | ||
| 135 | "INSERT INTO `Registry` (`Registry`, `Root`, `Key`, `Name`, `Value`, `Component_`) VALUES ('{0}', {1}, '{2}', '{3}', '{4}', '{5}')", | ||
| 136 | compName + "Reg1", | ||
| 137 | -1, | ||
| 138 | @"Software\Microsoft\Windows Installer Test\" + keyName, | ||
| 139 | keyValueName, | ||
| 140 | value, | ||
| 141 | compName); | ||
| 142 | db.Execute( | ||
| 143 | "INSERT INTO `FeatureComponents` (`Feature_`, `Component_`) VALUES ('{0}', '{1}')", | ||
| 144 | featureName, | ||
| 145 | compName); | ||
| 146 | } | ||
| 147 | |||
| 148 | public static void AddFileComponent(Database db, | ||
| 149 | string featureName, string compName, string compId, | ||
| 150 | string fileKey, string fileName) | ||
| 151 | { | ||
| 152 | db.Execute( | ||
| 153 | "INSERT INTO `Component` " + | ||
| 154 | "(`Component`, `ComponentId`, `Directory_`, `Attributes`, `KeyPath`) " + | ||
| 155 | "VALUES ('{0}', '{1}', '{2}', {3}, '{4}')", | ||
| 156 | compName, | ||
| 157 | compId, | ||
| 158 | "TestDir", | ||
| 159 | (int) ComponentAttributes.None, | ||
| 160 | fileKey); | ||
| 161 | db.Execute( | ||
| 162 | "INSERT INTO `File` " + | ||
| 163 | "(`File`, `Component_`, `FileName`, `FileSize`, `Attributes`, `Sequence`) " + | ||
| 164 | "VALUES ('{0}', '{1}', '{2}', 1, 0, 1)", | ||
| 165 | fileKey, | ||
| 166 | compName, | ||
| 167 | fileName); | ||
| 168 | db.Execute( | ||
| 169 | "INSERT INTO `FeatureComponents` (`Feature_`, `Component_`) VALUES ('{0}', '{1}')", | ||
| 170 | featureName, | ||
| 171 | compName); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } | ||
diff --git a/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WixToolsetTests.Dtf.WindowsInstaller.csproj b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WixToolsetTests.Dtf.WindowsInstaller.csproj new file mode 100644 index 00000000..dbddb682 --- /dev/null +++ b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller/WixToolsetTests.Dtf.WindowsInstaller.csproj | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 3 | |||
| 4 | <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> | ||
| 5 | <PropertyGroup> | ||
| 6 | <ProjectGuid>{16F5202F-9276-4166-975C-C9654BAF8012}</ProjectGuid> | ||
| 7 | <OutputType>Library</OutputType> | ||
| 8 | <RootNamespace>WixToolsetTests.Dtf</RootNamespace> | ||
| 9 | <AssemblyName>WixToolsetTests.Dtf.WindowsInstaller</AssemblyName> | ||
| 10 | <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> | ||
| 11 | <CreateDocumentation>false</CreateDocumentation> | ||
| 12 | </PropertyGroup> | ||
| 13 | |||
| 14 | <ItemGroup> | ||
| 15 | <Compile Include="EmbeddedExternalUI.cs" /> | ||
| 16 | <Compile Include="Schema.cs" /> | ||
| 17 | <Compile Include="WindowsInstallerTest.cs" /> | ||
| 18 | <Compile Include="WindowsInstallerTransactions.cs" /> | ||
| 19 | <Compile Include="WindowsInstallerUtils.cs" /> | ||
| 20 | </ItemGroup> | ||
| 21 | |||
| 22 | <ItemGroup> | ||
| 23 | <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> | ||
| 24 | <Reference Include="System" /> | ||
| 25 | <Reference Include="System.Windows.Forms" /> | ||
| 26 | <Reference Include="System.Xml" /> | ||
| 27 | </ItemGroup> | ||
| 28 | |||
| 29 | <ItemGroup> | ||
| 30 | <ProjectReference Include="..\WixToolset.Dtf.WindowsInstaller\WixToolset.Dtf.WindowsInstaller.csproj" /> | ||
| 31 | </ItemGroup> | ||
| 32 | |||
| 33 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> | ||
| 34 | </Project> | ||
