| 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 WixToolsetTest.Data |
| 4 | { |
| 5 | using System; |
| 6 | using System.IO; |
| 7 | using System.Linq; |
| 8 | using WixInternal.TestSupport; |
| 9 | using WixToolset.Data; |
| 10 | using WixToolset.Data.Bind; |
| 11 | using WixToolset.Data.Symbols; |
| 12 | using WixToolset.Data.WindowsInstaller.Rows; |
| 13 | using Xunit; |
| 14 | |
| 15 | using Wid = WixToolset.Data.WindowsInstaller; |
| 16 | |
| 17 | public class SerializeFixture |
| 18 | { |
| 19 | [Fact] |
| 20 | public void CanSaveAndLoadIntermediate() |
| 21 | { |
| 22 | var sln = new SourceLineNumber("test.wxs", 1); |
| 23 | |
| 24 | var section = new IntermediateSection("test", SectionType.Package); |
| 25 | |
| 26 | section.AddSymbol(new ComponentSymbol(sln, new Identifier(AccessModifier.Global, "TestComponent")) |
| 27 | { |
| 28 | ComponentId = String.Empty, |
| 29 | DirectoryRef = "TestFolder", |
| 30 | Location = ComponentLocation.Either, |
| 31 | KeyPath = null, |
| 32 | }); |
| 33 | |
| 34 | section.AddSymbol(new DirectorySymbol(sln, new Identifier(AccessModifier.Virtual, "TestFolder")) |
| 35 | { |
| 36 | ParentDirectoryRef = String.Empty, |
| 37 | Name = "Test Folder", |
| 38 | }); |
| 39 | |
| 40 | var intermediate = new Intermediate("TestIntermediate", IntermediateLevels.Compiled, new[] { section }, null); |
| 41 | |
| 42 | intermediate.UpdateLevel(IntermediateLevels.Linked); |
| 43 | intermediate.UpdateLevel(IntermediateLevels.Resolved); |
| 44 | |
| 45 | var path = Path.GetTempFileName(); |
| 46 | try |
| 47 | { |
| 48 | intermediate.Save(path); |
| 49 | |
| 50 | var loaded = Intermediate.Load(path); |
| 51 | |
| 52 | Assert.True(loaded.HasLevel(IntermediateLevels.Compiled)); |
| 53 | Assert.True(loaded.HasLevel(IntermediateLevels.Linked)); |
| 54 | Assert.True(loaded.HasLevel(IntermediateLevels.Resolved)); |
| 55 | |
| 56 | var componentSymbol = loaded.Sections.Single().Symbols.OfType<ComponentSymbol>().Single(); |
| 57 | |
| 58 | Assert.Equal("TestComponent", componentSymbol.Id.Id); |
| 59 | Assert.Equal(AccessModifier.Global, componentSymbol.Id.Access); |
| 60 | Assert.Equal(String.Empty, componentSymbol.ComponentId); |
| 61 | Assert.Equal("TestFolder", componentSymbol.DirectoryRef); |
| 62 | Assert.Equal(ComponentLocation.Either, componentSymbol.Location); |
| 63 | Assert.Null(componentSymbol.KeyPath); |
| 64 | |
| 65 | var directorySymbol = loaded.Sections.Single().Symbols.OfType<DirectorySymbol>().Single(); |
| 66 | |
| 67 | Assert.Equal("TestFolder", directorySymbol.Id.Id); |
| 68 | Assert.Equal(AccessModifier.Virtual, directorySymbol.Id.Access); |
| 69 | Assert.Equal(String.Empty, directorySymbol.ParentDirectoryRef); |
| 70 | Assert.Equal("Test Folder", directorySymbol.Name); |
| 71 | } |
| 72 | finally |
| 73 | { |
| 74 | File.Delete(path); |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | [Fact] |
| 79 | public void CanUpdateIntermediate() |
| 80 | { |
| 81 | var sln = new SourceLineNumber("test.wxs", 1); |
| 82 | var section = new IntermediateSection("test", SectionType.Package); |
| 83 | |
| 84 | section.AddSymbol(new ComponentSymbol(sln, new Identifier(AccessModifier.Global, "TestComponent")) |
| 85 | { |
| 86 | ComponentId = new Guid(1, 0, 0, new byte[8]).ToString("B"), |
| 87 | DirectoryRef = "TestFolder", |
| 88 | Location = ComponentLocation.Either, |
| 89 | }); |
| 90 | |
| 91 | var intermediate = new Intermediate("TestIntermediate", IntermediateLevels.Compiled, new[] { section }, null); |
| 92 | |
| 93 | var path = Path.GetTempFileName(); |
| 94 | try |
| 95 | { |
| 96 | intermediate.Save(path); |
| 97 | |
| 98 | var uri = new Uri(Path.GetFullPath(path)); |
| 99 | var stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite); |
| 100 | |
| 101 | using (var wixout = WixOutput.Read(uri, stream)) |
| 102 | { |
| 103 | var loaded = Intermediate.Load(wixout); |
| 104 | var symbol = (ComponentSymbol)loaded.Sections.Single().Symbols.Single(); |
| 105 | |
| 106 | Assert.Equal("TestComponent", symbol.Id.Id); |
| 107 | Assert.Equal(AccessModifier.Global, symbol.Id.Access); |
| 108 | |
| 109 | wixout.Reopen(writable: true); |
| 110 | |
| 111 | section.AddSymbol(new ComponentSymbol(sln, new Identifier(AccessModifier.Global, "NewComponent")) |
| 112 | { |
| 113 | ComponentId = new Guid(1, 0, 0, new byte[8]).ToString("B"), |
| 114 | }); |
| 115 | |
| 116 | intermediate.Save(wixout); |
| 117 | loaded = Intermediate.Load(wixout); |
| 118 | |
| 119 | var newSymbol = loaded.Sections.Single().Symbols.Where(t => t.Id.Id == "NewComponent"); |
| 120 | Assert.Single(newSymbol); |
| 121 | } |
| 122 | |
| 123 | var loadedAfterDispose = Intermediate.Load(path); |
| 124 | var newSymbolStillThere = loadedAfterDispose.Sections.Single().Symbols.Where(t => t.Id.Id == "NewComponent"); |
| 125 | Assert.Single(newSymbolStillThere); |
| 126 | |
| 127 | } |
| 128 | finally |
| 129 | { |
| 130 | File.Delete(path); |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | [Fact] |
| 135 | public void CanSaveAndLoadIntermediateWithCustomDefinitions() |
| 136 | { |
| 137 | var sln = new SourceLineNumber("test.wxs", 1); |
| 138 | |
| 139 | var section = new IntermediateSection("test", SectionType.Package); |
| 140 | |
| 141 | var fieldDefs = new[] |
| 142 | { |
| 143 | new IntermediateFieldDefinition("A", IntermediateFieldType.String), |
| 144 | new IntermediateFieldDefinition("B", IntermediateFieldType.Number), |
| 145 | new IntermediateFieldDefinition("C", IntermediateFieldType.Bool), |
| 146 | }; |
| 147 | |
| 148 | var symbolDef = new IntermediateSymbolDefinition("CustomDef2", fieldDefs, null); |
| 149 | |
| 150 | var symbol = symbolDef.CreateSymbol(sln, new Identifier(AccessModifier.Global, "customT")); |
| 151 | symbol.Set(0, "foo"); |
| 152 | symbol.Set(1, 2); |
| 153 | symbol.Set(2, true); |
| 154 | |
| 155 | section.AddSymbol(symbol); |
| 156 | |
| 157 | var intermediate = new Intermediate("TestIntermediate", new[] { section }, null); |
| 158 | |
| 159 | var path = Path.GetTempFileName(); |
| 160 | try |
| 161 | { |
| 162 | intermediate.Save(path); |
| 163 | |
| 164 | var loaded = Intermediate.Load(path); |
| 165 | var loadedSection = loaded.Sections.Single(); |
| 166 | var loadedSymbol = loadedSection.Symbols.Single(); |
| 167 | |
| 168 | Assert.Equal("foo", loadedSymbol.AsString(0)); |
| 169 | Assert.Equal(2, loadedSymbol[1].AsNumber()); |
| 170 | Assert.True(loadedSymbol[2].AsBool()); |
| 171 | } |
| 172 | finally |
| 173 | { |
| 174 | File.Delete(path); |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | [Fact] |
| 179 | public void CanSaveAndLoadMultipleIntermediateWithCustomDefinitions() |
| 180 | { |
| 181 | var sln = new SourceLineNumber("test.wxs", 1); |
| 182 | |
| 183 | // Intermediate #1 |
| 184 | var fieldDefs = new[] |
| 185 | { |
| 186 | new IntermediateFieldDefinition("A", IntermediateFieldType.String), |
| 187 | new IntermediateFieldDefinition("B", IntermediateFieldType.Number), |
| 188 | new IntermediateFieldDefinition("C", IntermediateFieldType.Bool), |
| 189 | }; |
| 190 | |
| 191 | var symbolDef = new IntermediateSymbolDefinition("CustomDef", fieldDefs, null); |
| 192 | |
| 193 | var symbol = symbolDef.CreateSymbol(sln, new Identifier(AccessModifier.Global, "customT")); |
| 194 | symbol.Set(0, "foo"); |
| 195 | symbol.Set(1, 2); |
| 196 | symbol.Set(2, true); |
| 197 | |
| 198 | var section = new IntermediateSection("test", SectionType.Package); |
| 199 | section.AddSymbol(symbol); |
| 200 | |
| 201 | var intermediate1 = new Intermediate("TestIntermediate", new[] { section }, null); |
| 202 | |
| 203 | // Intermediate #2 |
| 204 | var fieldDefs2 = new[] |
| 205 | { |
| 206 | new IntermediateFieldDefinition("A", IntermediateFieldType.String), |
| 207 | new IntermediateFieldDefinition("B", IntermediateFieldType.Number), |
| 208 | new IntermediateFieldDefinition("C", IntermediateFieldType.Bool), |
| 209 | new IntermediateFieldDefinition("D", IntermediateFieldType.String), |
| 210 | }; |
| 211 | |
| 212 | var symbolDef2 = new IntermediateSymbolDefinition("CustomDef2", 1, fieldDefs2, null); |
| 213 | |
| 214 | var symbol2 = symbolDef2.CreateSymbol(sln, new Identifier(AccessModifier.Global, "customT2")); |
| 215 | symbol2.Set(0, "bar"); |
| 216 | symbol2.Set(1, 3); |
| 217 | symbol2.Set(2, false); |
| 218 | symbol2.Set(3, "baz"); |
| 219 | |
| 220 | var section2 = new IntermediateSection("test2", SectionType.Fragment); |
| 221 | section2.AddSymbol(symbol2); |
| 222 | |
| 223 | var intermediate2 = new Intermediate("TestIntermediate2", new[] { section2 }, null); |
| 224 | |
| 225 | // Save |
| 226 | var path1 = Path.GetTempFileName(); |
| 227 | var path2 = Path.GetTempFileName(); |
| 228 | try |
| 229 | { |
| 230 | intermediate1.Save(path1); |
| 231 | intermediate2.Save(path2); |
| 232 | |
| 233 | var loaded = Intermediate.Load(new[] { path1, path2 }); |
| 234 | |
| 235 | var loaded1 = loaded.First(); |
| 236 | var loaded2 = loaded.Skip(1).Single(); |
| 237 | |
| 238 | var loadedSymbol1 = loaded1.Sections.Single().Symbols.Single(); |
| 239 | var loadedSymbol2 = loaded2.Sections.Single().Symbols.Single(); |
| 240 | |
| 241 | Assert.Equal("foo", loadedSymbol1.AsString(0)); |
| 242 | Assert.Equal(2, loadedSymbol1[1].AsNumber()); |
| 243 | Assert.True(loadedSymbol1[2].AsBool()); |
| 244 | |
| 245 | Assert.Equal("bar", loadedSymbol2.AsString(0)); |
| 246 | Assert.Equal(3, loadedSymbol2[1].AsNumber()); |
| 247 | Assert.False(loadedSymbol2[2].AsBool()); |
| 248 | Assert.Equal("baz", loadedSymbol2.AsString(3)); |
| 249 | } |
| 250 | finally |
| 251 | { |
| 252 | File.Delete(path2); |
| 253 | File.Delete(path1); |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | [Fact] |
| 258 | public void CanSaveAndLoadMultipleIntermediateWithCustomDefinitionsAndTags() |
| 259 | { |
| 260 | var sln = new SourceLineNumber("test.wxs", 1); |
| 261 | |
| 262 | // Intermediate #1 |
| 263 | var fieldDefs = new[] |
| 264 | { |
| 265 | new IntermediateFieldDefinition("A", IntermediateFieldType.String), |
| 266 | new IntermediateFieldDefinition("B", IntermediateFieldType.Number), |
| 267 | new IntermediateFieldDefinition("C", IntermediateFieldType.Bool), |
| 268 | }; |
| 269 | |
| 270 | var symbolDef = new IntermediateSymbolDefinition("CustomDef", fieldDefs, null); |
| 271 | |
| 272 | symbolDef.AddTag("customDef"); |
| 273 | |
| 274 | var symbol = symbolDef.CreateSymbol(sln, new Identifier(AccessModifier.Global, "customT")); |
| 275 | symbol.Set(0, "foo"); |
| 276 | symbol.Set(1, 2); |
| 277 | symbol.Set(2, true); |
| 278 | |
| 279 | symbol.AddTag("symbol1tag"); |
| 280 | |
| 281 | var section = new IntermediateSection("test", SectionType.Package); |
| 282 | section.AddSymbol(symbol); |
| 283 | |
| 284 | var intermediate1 = new Intermediate("TestIntermediate", new[] { section }, null); |
| 285 | |
| 286 | // Intermediate #2 |
| 287 | var fieldDefs2 = new[] |
| 288 | { |
| 289 | new IntermediateFieldDefinition("A", IntermediateFieldType.String), |
| 290 | new IntermediateFieldDefinition("B", IntermediateFieldType.Number), |
| 291 | new IntermediateFieldDefinition("C", IntermediateFieldType.Bool), |
| 292 | new IntermediateFieldDefinition("D", IntermediateFieldType.String), |
| 293 | }; |
| 294 | |
| 295 | var symbolDef2 = new IntermediateSymbolDefinition("CustomDef2", 1, fieldDefs2, null); |
| 296 | |
| 297 | symbolDef2.AddTag("customDef2"); |
| 298 | symbolDef2.AddTag("customDef2 tag2"); |
| 299 | |
| 300 | var symbol2 = symbolDef2.CreateSymbol(sln, new Identifier(AccessModifier.Global, "customT2")); |
| 301 | symbol2.Set(0, "bar"); |
| 302 | symbol2.Set(1, 3); |
| 303 | symbol2.Set(2, false); |
| 304 | symbol2.Set(3, "baz"); |
| 305 | |
| 306 | symbol2.AddTag("symbol2tag1"); |
| 307 | symbol2.AddTag("symbol2tag2"); |
| 308 | |
| 309 | var section2 = new IntermediateSection("test2", SectionType.Fragment); |
| 310 | section2.AddSymbol(symbol2); |
| 311 | |
| 312 | var intermediate2 = new Intermediate("TestIntermediate2", new[] { section2 }, null); |
| 313 | |
| 314 | // Save |
| 315 | var path1 = Path.GetTempFileName(); |
| 316 | var path2 = Path.GetTempFileName(); |
| 317 | try |
| 318 | { |
| 319 | intermediate1.Save(path1); |
| 320 | intermediate2.Save(path2); |
| 321 | |
| 322 | var loaded = Intermediate.Load(new[] { path1, path2 }); |
| 323 | |
| 324 | var loaded1 = loaded.First(); |
| 325 | var loaded2 = loaded.Skip(1).Single(); |
| 326 | |
| 327 | var loadedSymbol1 = loaded1.Sections.Single().Symbols.Single(); |
| 328 | var loadedSymbol2 = loaded2.Sections.Single().Symbols.Single(); |
| 329 | |
| 330 | Assert.True(loadedSymbol1.Definition.HasTag("customDef")); |
| 331 | Assert.Equal("foo", loadedSymbol1.AsString(0)); |
| 332 | Assert.Equal(2, loadedSymbol1[1].AsNumber()); |
| 333 | Assert.True(loadedSymbol1[2].AsBool()); |
| 334 | Assert.True(loadedSymbol1.HasTag("symbol1tag")); |
| 335 | |
| 336 | Assert.True(loadedSymbol2.Definition.HasTag("customDef2")); |
| 337 | Assert.True(loadedSymbol2.Definition.HasTag("customDef2 tag2")); |
| 338 | Assert.Equal("bar", loadedSymbol2.AsString(0)); |
| 339 | Assert.Equal(3, loadedSymbol2[1].AsNumber()); |
| 340 | Assert.False(loadedSymbol2[2].AsBool()); |
| 341 | Assert.Equal("baz", loadedSymbol2.AsString(3)); |
| 342 | Assert.True(loadedSymbol2.HasTag("symbol2tag1")); |
| 343 | Assert.True(loadedSymbol2.HasTag("symbol2tag2")); |
| 344 | } |
| 345 | finally |
| 346 | { |
| 347 | File.Delete(path2); |
| 348 | File.Delete(path1); |
| 349 | } |
| 350 | } |
| 351 | |
| 352 | [Fact] |
| 353 | public void CanSaveAndLoadIntermediateWithLocalization() |
| 354 | { |
| 355 | var sln = new SourceLineNumber("test.wxs", 10); |
| 356 | |
| 357 | var bindVariables = new[] |
| 358 | { |
| 359 | new BindVariable { Id = "TestVar1", Value = "TestValue1", SourceLineNumbers = sln }, |
| 360 | new BindVariable { Id = "TestVar2", Value = "TestValue2", Overridable = true, SourceLineNumbers = sln }, |
| 361 | }; |
| 362 | |
| 363 | var controls = new[] |
| 364 | { |
| 365 | new LocalizedControl("TestDlg1", "TestControl1", 10, 10, 100, 100, false, false, false, null), |
| 366 | new LocalizedControl("TestDlg1", "TestControl2", 100, 90, 50, 70, false, false, false, "localized"), |
| 367 | }; |
| 368 | |
| 369 | var localizations = new[] |
| 370 | { |
| 371 | new Localization(65001, 1252, null, bindVariables.ToDictionary(b => b.Id), controls.ToDictionary(c => c.GetKey())) |
| 372 | }; |
| 373 | |
| 374 | var section = new IntermediateSection("test", SectionType.Package); |
| 375 | |
| 376 | section.AddSymbol(new ComponentSymbol(sln, new Identifier(AccessModifier.Global, "TestComponent")) |
| 377 | { |
| 378 | ComponentId = new Guid(1, 0, 0, new byte[8]).ToString("B"), |
| 379 | DirectoryRef = "TestFolder", |
| 380 | Location = ComponentLocation.Either, |
| 381 | }); |
| 382 | |
| 383 | var intermediate = new Intermediate("TestIntermediate", new[] { section }, localizations.ToDictionary(l => l.Culture)); |
| 384 | |
| 385 | var path = Path.GetTempFileName(); |
| 386 | try |
| 387 | { |
| 388 | intermediate.Save(path); |
| 389 | |
| 390 | var loaded = Intermediate.Load(path); |
| 391 | |
| 392 | var loc = loaded.Localizations.Single(); |
| 393 | Assert.Equal(65001, loc.Codepage); |
| 394 | Assert.Empty(loc.Culture); |
| 395 | WixAssert.CompareLineByLine(new[] |
| 396 | { |
| 397 | "TestVar1/TestValue1/False", |
| 398 | "TestVar2/TestValue2/True", |
| 399 | }, loc.Variables.Select(v => String.Join("/", v.Id, v.Value, v.Overridable)).ToArray()); |
| 400 | } |
| 401 | finally |
| 402 | { |
| 403 | File.Delete(path); |
| 404 | } |
| 405 | } |
| 406 | |
| 407 | [Fact] |
| 408 | public void CanSaveAndLoadWindowsInstallerData() |
| 409 | { |
| 410 | var sln = new SourceLineNumber("test.wxs", 1); |
| 411 | var windowsInstallerData = new Wid.WindowsInstallerData(sln) |
| 412 | { |
| 413 | Type = OutputType.Package, |
| 414 | }; |
| 415 | |
| 416 | var fileTable = windowsInstallerData.EnsureTable(Wid.WindowsInstallerTableDefinitions.File); |
| 417 | var fileRow = (FileRow)fileTable.CreateRow(sln); |
| 418 | fileRow.File = "TestFile"; |
| 419 | |
| 420 | var path = Path.GetTempFileName(); |
| 421 | try |
| 422 | { |
| 423 | using (var wixout = WixOutput.Create(path)) |
| 424 | { |
| 425 | windowsInstallerData.Save(wixout); |
| 426 | } |
| 427 | |
| 428 | var loaded = Wid.WindowsInstallerData.Load(path); |
| 429 | |
| 430 | var loadedTable = Assert.Single(loaded.Tables); |
| 431 | Assert.Equal(Wid.WindowsInstallerTableDefinitions.File.Name, loadedTable.Name); |
| 432 | |
| 433 | var loadedRow = Assert.Single(loadedTable.Rows); |
| 434 | var loadedFileRow = Assert.IsType<FileRow>(loadedRow); |
| 435 | |
| 436 | Assert.Equal("TestFile", loadedFileRow.File); |
| 437 | } |
| 438 | finally |
| 439 | { |
| 440 | File.Delete(path); |
| 441 | } |
| 442 | } |
| 443 | } |
| 444 | } |