diff options
Diffstat (limited to '')
10 files changed, 1963 insertions, 0 deletions
diff --git a/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.CustomActions/CustomActionTest.cs b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.CustomActions/CustomActionTest.cs new file mode 100644 index 00000000..bf843024 --- /dev/null +++ b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.CustomActions/CustomActionTest.cs | |||
@@ -0,0 +1,206 @@ | |||
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.Text; | ||
8 | using System.Collections.Generic; | ||
9 | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
10 | using WixToolset.Dtf.WindowsInstaller; | ||
11 | |||
12 | [TestClass] | ||
13 | public class CustomActionTest | ||
14 | { | ||
15 | public CustomActionTest() | ||
16 | { | ||
17 | } | ||
18 | |||
19 | [TestMethod] | ||
20 | [Ignore] // Currently fails. | ||
21 | public void CustomActionTest1() | ||
22 | { | ||
23 | InstallLogModes logEverything = | ||
24 | InstallLogModes.FatalExit | | ||
25 | InstallLogModes.Error | | ||
26 | InstallLogModes.Warning | | ||
27 | InstallLogModes.User | | ||
28 | InstallLogModes.Info | | ||
29 | InstallLogModes.ResolveSource | | ||
30 | InstallLogModes.OutOfDiskSpace | | ||
31 | InstallLogModes.ActionStart | | ||
32 | InstallLogModes.ActionData | | ||
33 | InstallLogModes.CommonData | | ||
34 | InstallLogModes.Progress | | ||
35 | InstallLogModes.Initialize | | ||
36 | InstallLogModes.Terminate | | ||
37 | InstallLogModes.ShowDialog; | ||
38 | |||
39 | Installer.SetInternalUI(InstallUIOptions.Silent); | ||
40 | ExternalUIHandler prevHandler = Installer.SetExternalUI( | ||
41 | WindowsInstallerTest.ExternalUILogger, logEverything); | ||
42 | |||
43 | try | ||
44 | { | ||
45 | string[] customActions = new string[] { "SampleCA1", "SampleCA2" }; | ||
46 | #if DEBUG | ||
47 | string caDir = @"..\..\..\..\..\build\debug\x86\"; | ||
48 | #else | ||
49 | string caDir = @"..\..\..\..\..\build\ship\x86\"; | ||
50 | #endif | ||
51 | caDir = Path.GetFullPath(caDir); | ||
52 | string caFile = "WixToolset.Dtf.Samples.ManagedCA.dll"; | ||
53 | string caProduct = "CustomActionTest.msi"; | ||
54 | |||
55 | this.CreateCustomActionProduct(caProduct, caDir + caFile, customActions, false); | ||
56 | |||
57 | Exception caughtEx = null; | ||
58 | try | ||
59 | { | ||
60 | Installer.InstallProduct(caProduct, String.Empty); | ||
61 | } | ||
62 | catch (Exception ex) { caughtEx = ex; } | ||
63 | Assert.IsInstanceOfType(caughtEx, typeof(InstallCanceledException), | ||
64 | "Exception thrown while installing product: " + caughtEx); | ||
65 | |||
66 | string arch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"); | ||
67 | string arch2 = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432"); | ||
68 | if (arch == "AMD64" || arch2 == "AMD64") | ||
69 | { | ||
70 | caDir = caDir.Replace("x86", "x64"); | ||
71 | |||
72 | this.CreateCustomActionProduct(caProduct, caDir + caFile, customActions, true); | ||
73 | |||
74 | caughtEx = null; | ||
75 | try | ||
76 | { | ||
77 | Installer.InstallProduct(caProduct, String.Empty); | ||
78 | } | ||
79 | catch (Exception ex) { caughtEx = ex; } | ||
80 | Assert.IsInstanceOfType(caughtEx, typeof(InstallCanceledException), | ||
81 | "Exception thrown while installing 64bit product: " + caughtEx); | ||
82 | } | ||
83 | } | ||
84 | finally | ||
85 | { | ||
86 | Installer.SetExternalUI(prevHandler, InstallLogModes.None); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | private void CreateCustomActionProduct( | ||
91 | string msiFile, string customActionFile, IList<string> customActions, bool sixtyFourBit) | ||
92 | { | ||
93 | using (Database db = new Database(msiFile, DatabaseOpenMode.CreateDirect)) | ||
94 | { | ||
95 | WindowsInstallerUtils.InitializeProductDatabase(db, sixtyFourBit); | ||
96 | WindowsInstallerUtils.CreateTestProduct(db); | ||
97 | |||
98 | if (!File.Exists(customActionFile)) | ||
99 | throw new FileNotFoundException(customActionFile); | ||
100 | |||
101 | using (Record binRec = new Record(2)) | ||
102 | { | ||
103 | binRec[1] = Path.GetFileName(customActionFile); | ||
104 | binRec.SetStream(2, customActionFile); | ||
105 | |||
106 | db.Execute("INSERT INTO `Binary` (`Name`, `Data`) VALUES (?, ?)", binRec); | ||
107 | } | ||
108 | |||
109 | using (Record binRec2 = new Record(2)) | ||
110 | { | ||
111 | binRec2[1] = "TestData"; | ||
112 | binRec2.SetStream(2, new MemoryStream(Encoding.UTF8.GetBytes("This is a test data stream."))); | ||
113 | |||
114 | db.Execute("INSERT INTO `Binary` (`Name`, `Data`) VALUES (?, ?)", binRec2); | ||
115 | } | ||
116 | |||
117 | for (int i = 0; i < customActions.Count; i++) | ||
118 | { | ||
119 | db.Execute( | ||
120 | "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('{0}', 1, '{1}', '{2}')", | ||
121 | customActions[i], | ||
122 | Path.GetFileName(customActionFile), | ||
123 | customActions[i]); | ||
124 | db.Execute( | ||
125 | "INSERT INTO `InstallExecuteSequence` (`Action`, `Condition`, `Sequence`) VALUES ('{0}', '', {1})", | ||
126 | customActions[i], | ||
127 | 101 + i); | ||
128 | } | ||
129 | |||
130 | db.Execute("INSERT INTO `Property` (`Property`, `Value`) VALUES ('SampleCATest', 'TestValue')"); | ||
131 | |||
132 | db.Commit(); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | [TestMethod] | ||
137 | public void CustomActionData() | ||
138 | { | ||
139 | string dataString = "Key1=Value1;Key2=;Key3;Key4=Value=4;Key5"; | ||
140 | string dataString2 = "Key1=;Key2=Value2;Key3;Key4;Key6=Value;;6=6;Key7=Value7"; | ||
141 | |||
142 | CustomActionData data = new CustomActionData(dataString); | ||
143 | Assert.AreEqual<string>(dataString, data.ToString()); | ||
144 | |||
145 | data["Key1"] = String.Empty; | ||
146 | data["Key2"] = "Value2"; | ||
147 | data["Key4"] = null; | ||
148 | data.Remove("Key5"); | ||
149 | data["Key6"] = "Value;6=6"; | ||
150 | data["Key7"] = "Value7"; | ||
151 | |||
152 | Assert.AreEqual<string>(dataString2, data.ToString()); | ||
153 | |||
154 | MyDataClass myData = new MyDataClass(); | ||
155 | myData.Member1 = "test1"; | ||
156 | myData.Member2 = "test2"; | ||
157 | data.AddObject("MyData", myData); | ||
158 | |||
159 | string myDataString = data.ToString(); | ||
160 | CustomActionData data2 = new CustomActionData(myDataString); | ||
161 | |||
162 | MyDataClass myData2 = data2.GetObject<MyDataClass>("MyData"); | ||
163 | Assert.AreEqual<MyDataClass>(myData, myData2); | ||
164 | |||
165 | List<string> myComplexDataObject = new List<string>(); | ||
166 | myComplexDataObject.Add("CValue1"); | ||
167 | myComplexDataObject.Add("CValue2"); | ||
168 | myComplexDataObject.Add("CValue3"); | ||
169 | |||
170 | CustomActionData myComplexData = new CustomActionData(); | ||
171 | myComplexData.AddObject("MyComplexData", myComplexDataObject); | ||
172 | myComplexData.AddObject("NestedData", data); | ||
173 | string myComplexDataString = myComplexData.ToString(); | ||
174 | |||
175 | CustomActionData myComplexData2 = new CustomActionData(myComplexDataString); | ||
176 | List<string> myComplexDataObject2 = myComplexData2.GetObject<List<string>>("MyComplexData"); | ||
177 | |||
178 | Assert.AreEqual<int>(myComplexDataObject.Count, myComplexDataObject2.Count); | ||
179 | for (int i = 0; i < myComplexDataObject.Count; i++) | ||
180 | { | ||
181 | Assert.AreEqual<string>(myComplexDataObject[i], myComplexDataObject2[i]); | ||
182 | } | ||
183 | |||
184 | data2 = myComplexData2.GetObject<CustomActionData>("NestedData"); | ||
185 | Assert.AreEqual<string>(data.ToString(), data2.ToString()); | ||
186 | } | ||
187 | |||
188 | public class MyDataClass | ||
189 | { | ||
190 | public string Member1; | ||
191 | public string Member2; | ||
192 | |||
193 | public override bool Equals(object obj) | ||
194 | { | ||
195 | MyDataClass other = obj as MyDataClass; | ||
196 | return other != null && this.Member1 == other.Member1 && this.Member2 == other.Member2; | ||
197 | } | ||
198 | |||
199 | public override int GetHashCode() | ||
200 | { | ||
201 | return (this.Member1 != null ? this.Member1.GetHashCode() : 0) ^ | ||
202 | (this.Member2 != null ? this.Member2.GetHashCode() : 0); | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | } | ||
diff --git a/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.CustomActions/WixToolsetTests.Dtf.WindowsInstaller.CustomActions.csproj b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.CustomActions/WixToolsetTests.Dtf.WindowsInstaller.CustomActions.csproj new file mode 100644 index 00000000..aadd4592 --- /dev/null +++ b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.CustomActions/WixToolsetTests.Dtf.WindowsInstaller.CustomActions.csproj | |||
@@ -0,0 +1,28 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
3 | |||
4 | |||
5 | <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> | ||
6 | <PropertyGroup> | ||
7 | <ProjectGuid>{137D376B-989F-4FEA-9A67-01D8D38CA0DE}</ProjectGuid> | ||
8 | <OutputType>Library</OutputType> | ||
9 | <RootNamespace>WixToolsetTests.Dtf</RootNamespace> | ||
10 | <AssemblyName>WixToolsetTests.Dtf.WindowsInstaller.CustomActions</AssemblyName> | ||
11 | <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> | ||
12 | <CreateDocumentation>false</CreateDocumentation> | ||
13 | </PropertyGroup> | ||
14 | |||
15 | <ItemGroup> | ||
16 | <Compile Include="CustomActionTest.cs" /> | ||
17 | </ItemGroup> | ||
18 | |||
19 | <ItemGroup> | ||
20 | <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> | ||
21 | <Reference Include="System" /> | ||
22 | <Reference Include="System.Windows.Forms" /> | ||
23 | <Reference Include="$(OutputPath)\WixToolset.Dtf.WindowsInstaller.dll" /> | ||
24 | <ProjectReference Include="..\WixToolsetTests.Dtf.WindowsInstaller\WixToolsetTests.Dtf.WindowsInstaller.csproj" /> | ||
25 | </ItemGroup> | ||
26 | |||
27 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> | ||
28 | </Project> | ||
diff --git a/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.Linq/LinqTest.cs b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.Linq/LinqTest.cs new file mode 100644 index 00000000..7776a1c3 --- /dev/null +++ b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.Linq/LinqTest.cs | |||
@@ -0,0 +1,509 @@ | |||
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 | using System; | ||
4 | using System.Text; | ||
5 | using System.Collections; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Linq; | ||
8 | using System.Linq.Expressions; | ||
9 | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
10 | using WixToolset.Dtf.WindowsInstaller; | ||
11 | using WixToolset.Dtf.WindowsInstaller.Linq; | ||
12 | |||
13 | namespace WixToolset.Dtf.Test | ||
14 | { | ||
15 | [TestClass] | ||
16 | public class LinqTest | ||
17 | { | ||
18 | private void InitLinqTestDatabase(QDatabase db) | ||
19 | { | ||
20 | WindowsInstallerUtils.InitializeProductDatabase(db); | ||
21 | WindowsInstallerUtils.CreateTestProduct(db); | ||
22 | |||
23 | db.Execute( | ||
24 | "INSERT INTO `Feature` (`Feature`, `Title`, `Description`, `Level`, `Attributes`) VALUES ('{0}', '{1}', '{2}', {3}, {4})", | ||
25 | "TestFeature2", | ||
26 | "Test Feature 2", | ||
27 | "Test Feature 2 Description", | ||
28 | 1, | ||
29 | (int) FeatureAttributes.None); | ||
30 | |||
31 | WindowsInstallerUtils.AddRegistryComponent( | ||
32 | db, "TestFeature2", "MyTestRegComp", | ||
33 | Guid.NewGuid().ToString("B"), | ||
34 | "SOFTWARE\\Microsoft\\DTF\\Test", | ||
35 | "MyTestRegComp", "test"); | ||
36 | WindowsInstallerUtils.AddRegistryComponent( | ||
37 | db, "TestFeature2", "MyTestRegComp2", | ||
38 | Guid.NewGuid().ToString("B"), | ||
39 | "SOFTWARE\\Microsoft\\DTF\\Test", | ||
40 | "MyTestRegComp2", "test2"); | ||
41 | WindowsInstallerUtils.AddRegistryComponent( | ||
42 | db, "TestFeature2", "excludeComp", | ||
43 | Guid.NewGuid().ToString("B"), | ||
44 | "SOFTWARE\\Microsoft\\DTF\\Test", | ||
45 | "MyTestRegComp3", "test3"); | ||
46 | |||
47 | db.Commit(); | ||
48 | |||
49 | db.Log = Console.Out; | ||
50 | } | ||
51 | |||
52 | [TestMethod] | ||
53 | public void LinqSimple() | ||
54 | { | ||
55 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
56 | { | ||
57 | this.InitLinqTestDatabase(db); | ||
58 | |||
59 | var comps = from c in db.Components | ||
60 | select c; | ||
61 | |||
62 | int count = 0; | ||
63 | foreach (var c in comps) | ||
64 | { | ||
65 | Console.WriteLine(c); | ||
66 | count++; | ||
67 | } | ||
68 | |||
69 | Assert.AreEqual<int>(4, count); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | [TestMethod] | ||
74 | public void LinqWhereNull() | ||
75 | { | ||
76 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
77 | { | ||
78 | this.InitLinqTestDatabase(db); | ||
79 | |||
80 | var features = from f in db.Features | ||
81 | where f.Description != null | ||
82 | select f; | ||
83 | |||
84 | int count = 0; | ||
85 | foreach (var f in features) | ||
86 | { | ||
87 | Console.WriteLine(f); | ||
88 | Assert.AreEqual<string>("TestFeature2", f.Feature); | ||
89 | count++; | ||
90 | } | ||
91 | |||
92 | Assert.AreEqual<int>(1, count); | ||
93 | |||
94 | var features2 = from f in db.Features | ||
95 | where f.Description == null | ||
96 | select f; | ||
97 | |||
98 | count = 0; | ||
99 | foreach (var f in features2) | ||
100 | { | ||
101 | Console.WriteLine(f); | ||
102 | Assert.AreEqual<string>("TestFeature1", f.Feature); | ||
103 | count++; | ||
104 | } | ||
105 | |||
106 | Assert.AreEqual<int>(1, count); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | [TestMethod] | ||
111 | public void LinqWhereOperators() | ||
112 | { | ||
113 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
114 | { | ||
115 | this.InitLinqTestDatabase(db); | ||
116 | |||
117 | for (int i = 0; i < 100; i++) | ||
118 | { | ||
119 | var newFile = db.Files.NewRecord(); | ||
120 | newFile.File = "TestFile" + i; | ||
121 | newFile.Component_ = "TestComponent"; | ||
122 | newFile.FileName = "TestFile" + i + ".txt"; | ||
123 | newFile.FileSize = i % 10; | ||
124 | newFile.Sequence = i; | ||
125 | newFile.Insert(); | ||
126 | } | ||
127 | |||
128 | var files1 = from f in db.Files where f.Sequence < 40 select f; | ||
129 | Assert.AreEqual<int>(40, files1.AsEnumerable().Count()); | ||
130 | |||
131 | var files2 = from f in db.Files where f.Sequence <= 40 select f; | ||
132 | Assert.AreEqual<int>(41, files2.AsEnumerable().Count()); | ||
133 | |||
134 | var files3 = from f in db.Files where f.Sequence > 40 select f; | ||
135 | Assert.AreEqual<int>(59, files3.AsEnumerable().Count()); | ||
136 | |||
137 | var files4 = from f in db.Files where f.Sequence >= 40 select f; | ||
138 | Assert.AreEqual<int>(60, files4.AsEnumerable().Count()); | ||
139 | |||
140 | var files5 = from f in db.Files where 40 < f.Sequence select f; | ||
141 | Assert.AreEqual<int>(59, files5.AsEnumerable().Count()); | ||
142 | |||
143 | var files6 = from f in db.Files where 40 <= f.Sequence select f; | ||
144 | Assert.AreEqual<int>(60, files6.AsEnumerable().Count()); | ||
145 | |||
146 | var files7 = from f in db.Files where 40 > f.Sequence select f; | ||
147 | Assert.AreEqual<int>(40, files7.AsEnumerable().Count()); | ||
148 | |||
149 | var files8 = from f in db.Files where 40 >= f.Sequence select f; | ||
150 | Assert.AreEqual<int>(41, files8.AsEnumerable().Count()); | ||
151 | |||
152 | var files9 = from f in db.Files where f.Sequence == 40 select f; | ||
153 | Assert.AreEqual<int>(40, files9.AsEnumerable().First().Sequence); | ||
154 | |||
155 | var files10 = from f in db.Files where f.Sequence != 40 select f; | ||
156 | Assert.AreEqual<int>(99, files10.AsEnumerable().Count()); | ||
157 | |||
158 | var files11 = from f in db.Files where 40 == f.Sequence select f; | ||
159 | Assert.AreEqual<int>(40, files11.AsEnumerable().First().Sequence); | ||
160 | |||
161 | var files12 = from f in db.Files where 40 != f.Sequence select f; | ||
162 | Assert.AreEqual<int>(99, files12.AsEnumerable().Count()); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | [TestMethod] | ||
167 | public void LinqShapeSelect() | ||
168 | { | ||
169 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
170 | { | ||
171 | this.InitLinqTestDatabase(db); | ||
172 | |||
173 | Console.WriteLine("Running LINQ query 1."); | ||
174 | var features1 = from f in db.Features | ||
175 | select new { Name = f.Feature, | ||
176 | Desc = f.Description }; | ||
177 | |||
178 | int count = 0; | ||
179 | foreach (var f in features1) | ||
180 | { | ||
181 | Console.WriteLine(f); | ||
182 | count++; | ||
183 | } | ||
184 | |||
185 | Assert.AreEqual<int>(2, count); | ||
186 | |||
187 | Console.WriteLine(); | ||
188 | Console.WriteLine("Running LINQ query 2."); | ||
189 | var features2 = from f in db.Features | ||
190 | where f.Description != null | ||
191 | select new { Name = f.Feature, | ||
192 | Desc = f.Description.ToLower() }; | ||
193 | |||
194 | count = 0; | ||
195 | foreach (var f in features2) | ||
196 | { | ||
197 | Console.WriteLine(f); | ||
198 | Assert.AreEqual<string>("TestFeature2", f.Name); | ||
199 | count++; | ||
200 | } | ||
201 | |||
202 | Assert.AreEqual<int>(1, count); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | [TestMethod] | ||
207 | public void LinqUpdateNullableString() | ||
208 | { | ||
209 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
210 | { | ||
211 | this.InitLinqTestDatabase(db); | ||
212 | |||
213 | string newDescription = "New updated feature description."; | ||
214 | |||
215 | var features = from f in db.Features | ||
216 | where f.Description != null | ||
217 | select f; | ||
218 | |||
219 | int count = 0; | ||
220 | foreach (var f in features) | ||
221 | { | ||
222 | Console.WriteLine(f); | ||
223 | Assert.AreEqual<string>("TestFeature2", f.Feature); | ||
224 | f.Description = newDescription; | ||
225 | count++; | ||
226 | } | ||
227 | |||
228 | Assert.AreEqual<int>(1, count); | ||
229 | |||
230 | var features2 = from f in db.Features | ||
231 | where f.Description == newDescription | ||
232 | select f; | ||
233 | count = 0; | ||
234 | foreach (var f in features2) | ||
235 | { | ||
236 | Console.WriteLine(f); | ||
237 | Assert.AreEqual<string>("TestFeature2", f.Feature); | ||
238 | f.Description = null; | ||
239 | count++; | ||
240 | } | ||
241 | |||
242 | Assert.AreEqual<int>(1, count); | ||
243 | |||
244 | var features3 = from f in db.Features | ||
245 | where f.Description == null | ||
246 | select f.Feature; | ||
247 | count = 0; | ||
248 | foreach (var f in features3) | ||
249 | { | ||
250 | Console.WriteLine(f); | ||
251 | count++; | ||
252 | } | ||
253 | |||
254 | Assert.AreEqual<int>(2, count); | ||
255 | |||
256 | db.Commit(); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | [TestMethod] | ||
261 | public void LinqInsertDelete() | ||
262 | { | ||
263 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
264 | { | ||
265 | this.InitLinqTestDatabase(db); | ||
266 | |||
267 | var newProp = db.Properties.NewRecord(); | ||
268 | newProp.Property = "TestNewProp1"; | ||
269 | newProp.Value = "TestNewValue"; | ||
270 | newProp.Insert(); | ||
271 | |||
272 | string prop = (from p in db.Properties | ||
273 | where p.Property == "TestNewProp1" | ||
274 | select p.Value).AsEnumerable().First(); | ||
275 | Assert.AreEqual<string>("TestNewValue", prop); | ||
276 | |||
277 | newProp.Delete(); | ||
278 | |||
279 | int propCount = (from p in db.Properties | ||
280 | where p.Property == "TestNewProp1" | ||
281 | select p.Value).AsEnumerable().Count(); | ||
282 | Assert.AreEqual<int>(0, propCount); | ||
283 | |||
284 | db.Commit(); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | [TestMethod] | ||
289 | public void LinqQueryQRecord() | ||
290 | { | ||
291 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
292 | { | ||
293 | this.InitLinqTestDatabase(db); | ||
294 | |||
295 | var installFilesSeq = (from a in db["InstallExecuteSequence"] | ||
296 | where a["Action"] == "InstallFiles" | ||
297 | select a["Sequence"]).AsEnumerable().First(); | ||
298 | Assert.AreEqual<string>("4000", installFilesSeq); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | [TestMethod] | ||
303 | public void LinqOrderBy() | ||
304 | { | ||
305 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
306 | { | ||
307 | this.InitLinqTestDatabase(db); | ||
308 | |||
309 | var actions = from a in db.InstallExecuteSequences | ||
310 | orderby a.Sequence | ||
311 | select a.Action; | ||
312 | foreach (var a in actions) | ||
313 | { | ||
314 | Console.WriteLine(a); | ||
315 | } | ||
316 | |||
317 | var files = from f in db.Files | ||
318 | orderby f.FileSize, f["Sequence"] | ||
319 | where f.Attributes == FileAttributes.None | ||
320 | select f; | ||
321 | |||
322 | foreach (var f in files) | ||
323 | { | ||
324 | Console.WriteLine(f); | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | [TestMethod] | ||
330 | public void LinqTwoWayJoin() | ||
331 | { | ||
332 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
333 | { | ||
334 | this.InitLinqTestDatabase(db); | ||
335 | int count; | ||
336 | |||
337 | var regs = from r in db.Registries | ||
338 | join c in db["Component"] on r.Component_ equals c["Component"] | ||
339 | where c["Component"] == "MyTestRegComp" && | ||
340 | r.Root == RegistryRoot.UserOrMachine | ||
341 | select new { Reg = r.Registry, Dir = c["Directory_"] }; | ||
342 | |||
343 | count = 0; | ||
344 | foreach (var r in regs) | ||
345 | { | ||
346 | Console.WriteLine(r); | ||
347 | count++; | ||
348 | } | ||
349 | Assert.AreEqual<int>(1, count); | ||
350 | |||
351 | var regs2 = from r in db.Registries | ||
352 | join c in db.Components on r.Component_ equals c.Component | ||
353 | where c.Component == "MyTestRegComp" && | ||
354 | r.Root == RegistryRoot.UserOrMachine | ||
355 | select new { Reg = r, Dir = c.Directory_ }; | ||
356 | |||
357 | count = 0; | ||
358 | foreach (var r in regs2) | ||
359 | { | ||
360 | Assert.IsNotNull(r.Reg.Registry); | ||
361 | Console.WriteLine(r); | ||
362 | count++; | ||
363 | } | ||
364 | Assert.AreEqual<int>(1, count); | ||
365 | |||
366 | var regs3 = from r in db.Registries | ||
367 | join c in db.Components on r.Component_ equals c.Component | ||
368 | where c.Component == "MyTestRegComp" && | ||
369 | r.Root == RegistryRoot.UserOrMachine | ||
370 | select r; | ||
371 | |||
372 | count = 0; | ||
373 | foreach (var r in regs3) | ||
374 | { | ||
375 | Assert.IsNotNull(r.Registry); | ||
376 | Console.WriteLine(r); | ||
377 | count++; | ||
378 | } | ||
379 | Assert.AreEqual<int>(1, count); | ||
380 | |||
381 | } | ||
382 | } | ||
383 | |||
384 | [TestMethod] | ||
385 | public void LinqFourWayJoin() | ||
386 | { | ||
387 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
388 | { | ||
389 | this.InitLinqTestDatabase(db); | ||
390 | int count; | ||
391 | |||
392 | IList<string> pretest = db.ExecuteStringQuery( | ||
393 | "SELECT `Feature`.`Feature` " + | ||
394 | "FROM `Feature`, `FeatureComponents`, `Component`, `Registry` " + | ||
395 | "WHERE `Feature`.`Feature` = `FeatureComponents`.`Feature_` " + | ||
396 | "AND `FeatureComponents`.`Component_` = `Component`.`Component` " + | ||
397 | "AND `Component`.`Component` = `Registry`.`Component_` " + | ||
398 | "AND (`Registry`.`Registry` = 'MyTestRegCompReg1')"); | ||
399 | Assert.AreEqual<int>(1, pretest.Count); | ||
400 | |||
401 | var features = from f in db.Features | ||
402 | join fc in db.FeatureComponents on f.Feature equals fc.Feature_ | ||
403 | join c in db.Components on fc.Component_ equals c.Component | ||
404 | join r in db.Registries on c.Component equals r.Component_ | ||
405 | where r.Registry == "MyTestRegCompReg1" | ||
406 | select f.Feature; | ||
407 | |||
408 | count = 0; | ||
409 | foreach (var featureName in features) | ||
410 | { | ||
411 | Console.WriteLine(featureName); | ||
412 | count++; | ||
413 | } | ||
414 | Assert.AreEqual<int>(1, count); | ||
415 | |||
416 | } | ||
417 | } | ||
418 | |||
419 | [TestMethod] | ||
420 | public void EnumTable() | ||
421 | { | ||
422 | using (QDatabase db = new QDatabase("testlinq.msi", DatabaseOpenMode.Create)) | ||
423 | { | ||
424 | this.InitLinqTestDatabase(db); | ||
425 | int count = 0; | ||
426 | foreach (var comp in db.Components) | ||
427 | { | ||
428 | Console.WriteLine(comp); | ||
429 | count++; | ||
430 | } | ||
431 | Assert.AreNotEqual<int>(0, count); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | [TestMethod] | ||
436 | public void DatabaseAsQueryable() | ||
437 | { | ||
438 | using (Database db = new Database("testlinq.msi", DatabaseOpenMode.Create)) | ||
439 | { | ||
440 | WindowsInstallerUtils.InitializeProductDatabase(db); | ||
441 | WindowsInstallerUtils.CreateTestProduct(db); | ||
442 | |||
443 | var comps = from c in db.AsQueryable().Components | ||
444 | select c; | ||
445 | |||
446 | int count = 0; | ||
447 | foreach (var c in comps) | ||
448 | { | ||
449 | Console.WriteLine(c); | ||
450 | count++; | ||
451 | } | ||
452 | |||
453 | Assert.AreEqual<int>(1, count); | ||
454 | } | ||
455 | } | ||
456 | |||
457 | [TestMethod] | ||
458 | public void EnumProducts() | ||
459 | { | ||
460 | var products = from p in ProductInstallation.AllProducts | ||
461 | where p.Publisher == ".NET Foundation" | ||
462 | select new { Name = p.ProductName, | ||
463 | Ver = p.ProductVersion, | ||
464 | Company = p.Publisher, | ||
465 | InstallDate = p.InstallDate, | ||
466 | PackageCode = p.AdvertisedPackageCode }; | ||
467 | |||
468 | foreach (var p in products) | ||
469 | { | ||
470 | Console.WriteLine(p); | ||
471 | Assert.IsTrue(p.Company == ".NET Foundation"); | ||
472 | } | ||
473 | } | ||
474 | |||
475 | [TestMethod] | ||
476 | public void EnumFeatures() | ||
477 | { | ||
478 | foreach (var p in ProductInstallation.AllProducts) | ||
479 | { | ||
480 | Console.WriteLine(p.ProductName); | ||
481 | |||
482 | foreach (var f in p.Features) | ||
483 | { | ||
484 | Console.WriteLine("\t" + f.FeatureName); | ||
485 | } | ||
486 | } | ||
487 | } | ||
488 | |||
489 | [TestMethod] | ||
490 | public void EnumComponents() | ||
491 | { | ||
492 | var comps = from c in ComponentInstallation.AllComponents | ||
493 | where c.State == InstallState.Local && | ||
494 | c.Product.Publisher == ".NET Foundation" | ||
495 | select c.Path; | ||
496 | |||
497 | int count = 0; | ||
498 | foreach (var c in comps) | ||
499 | { | ||
500 | if (++count == 100) break; | ||
501 | |||
502 | Console.WriteLine(c); | ||
503 | } | ||
504 | |||
505 | Assert.AreEqual<int>(100, count); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | } | ||
diff --git a/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.Linq/WixToolsetTests.Dtf.WindowsInstaller.Linq.csproj b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.Linq/WixToolsetTests.Dtf.WindowsInstaller.Linq.csproj new file mode 100644 index 00000000..0dc90860 --- /dev/null +++ b/src/dtf/WixToolsetTests.Dtf.WindowsInstaller.Linq/WixToolsetTests.Dtf.WindowsInstaller.Linq.csproj | |||
@@ -0,0 +1,31 @@ | |||
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>{4F55F9B8-D8B6-41EB-8796-221B4CD98324}</ProjectGuid> | ||
7 | <OutputType>Library</OutputType> | ||
8 | <RootNamespace>WixToolsetTests.Dtf</RootNamespace> | ||
9 | <AssemblyName>WixToolsetTests.Dtf.Linq</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="LinqTest.cs" /> | ||
16 | </ItemGroup> | ||
17 | |||
18 | <ItemGroup> | ||
19 | <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> | ||
20 | <Reference Include="System" /> | ||
21 | <Reference Include="System.Core" /> | ||
22 | </ItemGroup> | ||
23 | |||
24 | <ItemGroup> | ||
25 | <ProjectReference Include="..\WixToolset.Dtf.WindowsInstaller\WixToolset.Dtf.WindowsInstaller.csproj" /> | ||
26 | <ProjectReference Include="..\WixToolset.Dtf.WindowsInstaller.Linq\WixToolset.Dtf.WindowsInstaller.Linq.csproj" /> | ||
27 | <ProjectReference Include="..\WixToolsetTests.Dtf.WindowsInstaller\WixToolsetTests.Dtf.WindowsInstaller.csproj" /> | ||
28 | </ItemGroup> | ||
29 | |||
30 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> | ||
31 | </Project> | ||
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> | ||