Introduce Value attribute on MultiString/MultiStringValue elements
Rob Mensching committed
Jun 17, 2020 at 12:10 UTC
457c144720964a7f50b1d184e6b19faa930e970e
5 files changed
+168
-70
src/WixToolset.Core/Compiler_2.cs
+38
-5
@@ -1964,18 +1964,15 @@ namespace WixToolset.Core
1964
{
1965
switch (child.Name.LocalName)
1966
{
1967
+ case "MultiString":
1968
case "MultiStringValue":
1969
if (RegistryValueType.MultiString != valueType && null != value)
1970
{
1971
this.Core.Write(ErrorMessages.RegistryMultipleValuesWithoutMultiString(sourceLineNumbers, node.Name.LocalName, "Value", child.Name.LocalName, "Type"));
1972
}
1972
- else if (null == value)
1973
- {
1974
- value = Common.GetInnerText(child);
1975
- }
1973
else
1974
{
1978
- value = String.Concat(value, "[~]", Common.GetInnerText(child));
1975
+ value = this.ParseRegistryMultiStringElement(child, value);
1976
}
1977
break;
1978
case "Permission":
@@ -2069,6 +2066,42 @@ namespace WixToolset.Core
2066
return keyPath;
2067
}
2068
2069
+ private string ParseRegistryMultiStringElement(XElement node, string value)
2070
+ {
2071
+ var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2072
+ string multiStringValue = null;
2073
+
2074
+ foreach (var attrib in node.Attributes())
2075
+ {
2076
+ if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2077
+ {
2078
+ switch (attrib.Name.LocalName)
2079
+ {
2080
+ case "Value":
2081
+ multiStringValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2082
+ break;
2083
+ default:
2084
+ this.Core.UnexpectedAttribute(node, attrib);
2085
+ break;
2086
+ }
2087
+ }
2088
+ }
2089
+
2090
+ if (multiStringValue == null)
2091
+ {
2092
+ multiStringValue = Common.GetInnerText(node);
2093
+ }
2094
+
2095
+ if (multiStringValue == null)
2096
+ {
2097
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value"));
2098
+ }
2099
+
2100
+ this.Core.ParseForExtensionElements(node);
2101
+
2102
+ return (null == value) ? multiStringValue : String.Concat(value, "[~]", multiStringValue);
2103
+ }
2104
+
2105
/// <summary>
2106
/// Parses a RemoveRegistryKey element.
2107
/// </summary>
src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs
-65
@@ -804,71 +804,6 @@ namespace WixToolsetTest.CoreIntegration
804
}
805
}
806
807
- [Fact]
808
- public void PopulatesRegistryTableFromRegistryValue()
809
- {
810
- var folder = TestData.Get(@"TestData");
811
-
812
- using (var fs = new DisposableFileSystem())
813
- {
814
- var baseFolder = fs.GetFolder();
815
- var intermediateFolder = Path.Combine(baseFolder, "obj");
816
- var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
817
-
818
- var result = WixRunner.Execute(new[]
819
- {
820
- "build",
821
- Path.Combine(folder, "Registry", "RegistryValue.wxs"),
822
- Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
823
- "-bindpath", Path.Combine(folder, "SingleFile", "data"),
824
- "-intermediateFolder", intermediateFolder,
825
- "-o", msiPath
826
- });
827
-
828
- result.AssertSuccess();
829
-
830
- Assert.True(File.Exists(msiPath));
831
- var results = Query.QueryDatabase(msiPath, new[] { "Registry" });
832
- Assert.Equal(new[]
833
- {
834
- "Registry:reg04OIwIchl.9ZTjisTT6NzGSsQSM\t2\tPath\\To\\AnotherKey\tSecret\t#x\tMiscComponent",
835
- "Registry:regEblTuusqFNSUQNy88zaP_UA5kIY\t2\tPath\\To\\Key\t\t1.0.1234.123\tMiscComponent",
836
- }, results);
837
- }
838
- }
839
-
840
- [Fact]
841
- public void PopulatesRegistryTableFromRemoveRegistryKey()
842
- {
843
- var folder = TestData.Get(@"TestData");
844
-
845
- using (var fs = new DisposableFileSystem())
846
- {
847
- var baseFolder = fs.GetFolder();
848
- var intermediateFolder = Path.Combine(baseFolder, "obj");
849
- var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
850
-
851
- var result = WixRunner.Execute(new[]
852
- {
853
- "build",
854
- Path.Combine(folder, "Registry", "RemoveRegistryKey.wxs"),
855
- Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
856
- "-bindpath", Path.Combine(folder, "SingleFile", "data"),
857
- "-intermediateFolder", intermediateFolder,
858
- "-o", msiPath
859
- });
860
-
861
- result.AssertSuccess();
862
-
863
- Assert.True(File.Exists(msiPath));
864
- var results = Query.QueryDatabase(msiPath, new[] { "Registry" });
865
- Assert.Equal(new[]
866
- {
867
- "Registry:RemoveAKeyName\t2\tAKeyName\t-\t\tRemoveRegistryKeyComp",
868
- }, results);
869
- }
870
- }
871
-
807
[Fact]
808
public void PopulatesReserveCostTable()
809
{
src/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs
new
+114
@@ -0,0 +1,114 @@
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.CoreIntegration
4
+{
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using System.IO;
8
+ using System.Linq;
9
+ using System.Text;
10
+ using WixBuildTools.TestSupport;
11
+ using WixToolset.Core.TestPackage;
12
+ using WixToolset.Data;
13
+ using Xunit;
14
+
15
+ public class RegistryFixture
16
+ {
17
+ [Fact]
18
+ public void PopulatesRegistryTableFromRegistryValue()
19
+ {
20
+ var folder = TestData.Get(@"TestData");
21
+
22
+ using (var fs = new DisposableFileSystem())
23
+ {
24
+ var baseFolder = fs.GetFolder();
25
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
26
+ var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
27
+
28
+ var result = WixRunner.Execute(new[]
29
+ {
30
+ "build",
31
+ Path.Combine(folder, "Registry", "RegistryValue.wxs"),
32
+ Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
33
+ "-bindpath", Path.Combine(folder, "SingleFile", "data"),
34
+ "-intermediateFolder", intermediateFolder,
35
+ "-o", msiPath
36
+ });
37
+
38
+ result.AssertSuccess();
39
+
40
+ Assert.True(File.Exists(msiPath));
41
+ var results = Query.QueryDatabase(msiPath, new[] { "Registry" });
42
+ Assert.Equal(new[]
43
+ {
44
+ "Registry:reg04OIwIchl.9ZTjisTT6NzGSsQSM\t2\tPath\\To\\AnotherKey\tSecret\t#x\tMiscComponent",
45
+ "Registry:regEblTuusqFNSUQNy88zaP_UA5kIY\t2\tPath\\To\\Key\t\t1.0.1234.123\tMiscComponent",
46
+ }, results);
47
+ }
48
+ }
49
+
50
+ [Fact]
51
+ public void PopulatesRegistryTableFromRegistryValueMultiString()
52
+ {
53
+ var folder = TestData.Get(@"TestData");
54
+
55
+ using (var fs = new DisposableFileSystem())
56
+ {
57
+ var baseFolder = fs.GetFolder();
58
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
59
+ var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
60
+
61
+ var result = WixRunner.Execute(new[]
62
+ {
63
+ "build",
64
+ Path.Combine(folder, "Registry", "RegistryValueMultiString.wxs"),
65
+ Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
66
+ "-bindpath", Path.Combine(folder, "SingleFile", "data"),
67
+ "-intermediateFolder", intermediateFolder,
68
+ "-o", msiPath
69
+ });
70
+
71
+ result.AssertSuccess();
72
+
73
+ var results = Query.QueryDatabase(msiPath, new[] { "Registry" });
74
+ Assert.Equal(new[]
75
+ {
76
+ "Registry:regitq_Wx9LfvJuNSc2un6gIHAzr4A\t2\tPath\\To\\AnotherKey\tSecret\t#x\tMultiStringComponent",
77
+ "Registry:regmeTJMpOD41igfxhTcUVZ7kNG1Mo\t2\tPath\\To\\Key\t\ta[~]b[~]c\tMultiStringComponent",
78
+ }, results);
79
+ }
80
+ }
81
+
82
+ [Fact]
83
+ public void PopulatesRegistryTableFromRemoveRegistryKey()
84
+ {
85
+ var folder = TestData.Get(@"TestData");
86
+
87
+ using (var fs = new DisposableFileSystem())
88
+ {
89
+ var baseFolder = fs.GetFolder();
90
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
91
+ var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
92
+
93
+ var result = WixRunner.Execute(new[]
94
+ {
95
+ "build",
96
+ Path.Combine(folder, "Registry", "RemoveRegistryKey.wxs"),
97
+ Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
98
+ "-bindpath", Path.Combine(folder, "SingleFile", "data"),
99
+ "-intermediateFolder", intermediateFolder,
100
+ "-o", msiPath
101
+ });
102
+
103
+ result.AssertSuccess();
104
+
105
+ Assert.True(File.Exists(msiPath));
106
+ var results = Query.QueryDatabase(msiPath, new[] { "Registry" });
107
+ Assert.Equal(new[]
108
+ {
109
+ "Registry:RemoveAKeyName\t2\tAKeyName\t-\t\tRemoveRegistryKeyComp",
110
+ }, results);
111
+ }
112
+ }
113
+ }
114
+}
src/test/WixToolsetTest.CoreIntegration/TestData/Registry/RegistryValueMultiString.wxs
new
+15
@@ -0,0 +1,15 @@
1
+<?xml version="1.0" encoding="utf-8" ?>
2
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3
+ <Fragment>
4
+ <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
5
+ <Component Id="MultiStringComponent" Guid="7C40C257-AB36-4B8C-8FD1-C56E0AC4AAEF">
6
+ <RegistryValue Root="HKLM" Key="Path\To\Key" Type="multiString" KeyPath="yes">
7
+ <MultiString Value="a" />
8
+ <MultiStringValue Value="b" />
9
+ <MultiString Value="c" />
10
+ </RegistryValue>
11
+ <RegistryValue Root="HKLM" Key="Path\To\AnotherKey" Name="Secret" Type="binary" />
12
+ </Component>
13
+ </ComponentGroup>
14
+ </Fragment>
15
+</Wix>
src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
+1
@@ -74,6 +74,7 @@
74
<Content Include="TestData\ProductWithComponentGroupRef\MinimalComponentGroup.wxs" CopyToOutputDirectory="PreserveNewest" />
75
<Content Include="TestData\ProductWithComponentGroupRef\Product.wxs" CopyToOutputDirectory="PreserveNewest" />
76
<Content Include="TestData\Registry\RegistryValue.wxs" CopyToOutputDirectory="PreserveNewest" />
77
+ <Content Include="TestData\Registry\RegistryValueMultiString.wxs" CopyToOutputDirectory="PreserveNewest" />
78
<Content Include="TestData\Registry\RemoveRegistryKey.wxs" CopyToOutputDirectory="PreserveNewest" />
79
<Content Include="TestData\ReserveCost\ReserveCost.wxs" CopyToOutputDirectory="PreserveNewest" />
80
<Content Include="TestData\SequenceTables\DecompiledSequenceTables.wxs" CopyToOutputDirectory="PreserveNewest" />