diff options
Diffstat (limited to '')
| -rw-r--r-- | src/wix/WixToolset.Converters/WixConverter.cs | 382 | ||||
| -rw-r--r-- | src/wix/test/WixToolsetTest.Converters/ConditionFixture.cs | 341 |
2 files changed, 625 insertions, 98 deletions
diff --git a/src/wix/WixToolset.Converters/WixConverter.cs b/src/wix/WixToolset.Converters/WixConverter.cs index 178b90be..3fea4498 100644 --- a/src/wix/WixToolset.Converters/WixConverter.cs +++ b/src/wix/WixToolset.Converters/WixConverter.cs | |||
| @@ -1033,17 +1033,18 @@ namespace WixToolset.Converters | |||
| 1033 | using (var lab = new ConversionLab(element)) | 1033 | using (var lab = new ConversionLab(element)) |
| 1034 | { | 1034 | { |
| 1035 | var xConditions = element.Elements(ConditionElementName).ToList(); | 1035 | var xConditions = element.Elements(ConditionElementName).ToList(); |
| 1036 | var comments = new List<XNode>(); | 1036 | var collector = new InnerContentCollector(); |
| 1037 | var conditions = new List<KeyValuePair<string, string>>(); | 1037 | var conditions = new List<KeyValuePair<string, string>>(); |
| 1038 | 1038 | ||
| 1039 | foreach (var xCondition in xConditions) | 1039 | foreach (var xCondition in xConditions) |
| 1040 | { | 1040 | { |
| 1041 | var action = UppercaseFirstChar(xCondition.Attribute("Action")?.Value); | 1041 | var action = UppercaseFirstChar(xCondition.Attribute("Action")?.Value); |
| 1042 | |||
| 1042 | if (!String.IsNullOrEmpty(action) && | 1043 | if (!String.IsNullOrEmpty(action) && |
| 1043 | TryGetInnerText(xCondition, out var text, out comments, comments) && | 1044 | collector.CollectInnerTextAndCommentsForAttributeValue(xCondition, out string value) && |
| 1044 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the '{1}Condition' attribute instead.", xCondition.Name.LocalName, action)) | 1045 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the '{1}Condition' attribute instead.", xCondition.Name.LocalName, action)) |
| 1045 | { | 1046 | { |
| 1046 | conditions.Add(new KeyValuePair<string, string>(action, text)); | 1047 | conditions.Add(new KeyValuePair<string, string>(action, value)); |
| 1047 | } | 1048 | } |
| 1048 | } | 1049 | } |
| 1049 | 1050 | ||
| @@ -1062,7 +1063,7 @@ namespace WixToolset.Converters | |||
| 1062 | } | 1063 | } |
| 1063 | 1064 | ||
| 1064 | lab.RemoveOrphanTextNodes(); | 1065 | lab.RemoveOrphanTextNodes(); |
| 1065 | lab.AddCommentsAsSiblings(comments); | 1066 | lab.AddCommentsAsSiblings(collector.Comments); |
| 1066 | } | 1067 | } |
| 1067 | } | 1068 | } |
| 1068 | 1069 | ||
| @@ -1080,15 +1081,17 @@ namespace WixToolset.Converters | |||
| 1080 | var xCondition = element.Element(ConditionElementName); | 1081 | var xCondition = element.Element(ConditionElementName); |
| 1081 | if (xCondition != null) | 1082 | if (xCondition != null) |
| 1082 | { | 1083 | { |
| 1083 | if (TryGetInnerText(xCondition, out var text, out var comments) && | 1084 | var collector = new InnerContentCollector(); |
| 1085 | |||
| 1086 | if (collector.CollectInnerTextAndCommentsForAttributeValue(xCondition, out string value) && | ||
| 1084 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", xCondition.Name.LocalName)) | 1087 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", xCondition.Name.LocalName)) |
| 1085 | { | 1088 | { |
| 1086 | using (var lab = new ConversionLab(element)) | 1089 | using (var lab = new ConversionLab(element)) |
| 1087 | { | 1090 | { |
| 1088 | xCondition.Remove(); | 1091 | xCondition.Remove(); |
| 1089 | element.Add(new XAttribute("Condition", text)); | 1092 | element.Add(new XAttribute("Condition", value)); |
| 1090 | lab.RemoveOrphanTextNodes(); | 1093 | lab.RemoveOrphanTextNodes(); |
| 1091 | lab.AddCommentsAsSiblings(comments); | 1094 | lab.AddCommentsAsSiblings(collector.Comments); |
| 1092 | } | 1095 | } |
| 1093 | } | 1096 | } |
| 1094 | } | 1097 | } |
| @@ -1191,16 +1194,18 @@ namespace WixToolset.Converters | |||
| 1191 | if (xCondition != null) | 1194 | if (xCondition != null) |
| 1192 | { | 1195 | { |
| 1193 | var level = xCondition.Attribute("Level")?.Value; | 1196 | var level = xCondition.Attribute("Level")?.Value; |
| 1197 | var collector = new InnerContentCollector(); | ||
| 1198 | |||
| 1194 | if (!String.IsNullOrEmpty(level) && | 1199 | if (!String.IsNullOrEmpty(level) && |
| 1195 | TryGetInnerText(xCondition, out var text, out var comments) && | 1200 | collector.CollectInnerTextAndCommentsForAttributeValue(xCondition, out string value) && |
| 1196 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Level' element instead.", xCondition.Name.LocalName)) | 1201 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Level' element instead.", xCondition.Name.LocalName)) |
| 1197 | { | 1202 | { |
| 1198 | using (var lab = new ConversionLab(xCondition)) | 1203 | using (var lab = new ConversionLab(xCondition)) |
| 1199 | { | 1204 | { |
| 1200 | lab.ReplaceTargetElement(new XElement(LevelElementName, | 1205 | lab.ReplaceTargetElement(new XElement(LevelElementName, |
| 1201 | new XAttribute("Value", level), | 1206 | new XAttribute("Value", level), |
| 1202 | new XAttribute("Condition", text))); | 1207 | new XAttribute("Condition", value))); |
| 1203 | lab.AddCommentsAsSiblings(comments); | 1208 | lab.AddCommentsAsSiblings(collector.Comments); |
| 1204 | } | 1209 | } |
| 1205 | } | 1210 | } |
| 1206 | } | 1211 | } |
| @@ -1235,17 +1240,23 @@ namespace WixToolset.Converters | |||
| 1235 | private void ConvertLaunchConditionElement(XElement element) | 1240 | private void ConvertLaunchConditionElement(XElement element) |
| 1236 | { | 1241 | { |
| 1237 | var message = element.Attribute("Message")?.Value; | 1242 | var message = element.Attribute("Message")?.Value; |
| 1243 | var collector = new InnerContentCollector(); | ||
| 1238 | 1244 | ||
| 1239 | if (!String.IsNullOrEmpty(message) && | 1245 | if (!String.IsNullOrEmpty(message) && |
| 1240 | TryGetInnerText(element, out var text, out var comments) && | 1246 | collector.CollectInnerTextWithTrailingWhitespaceAndCommentsForAttributeValue(element, out string value) && |
| 1241 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Launch' element instead.", element.Name.LocalName)) | 1247 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Launch' element instead.", element.Name.LocalName)) |
| 1242 | { | 1248 | { |
| 1249 | if (String.IsNullOrWhiteSpace(value)) | ||
| 1250 | { | ||
| 1251 | value = String.Empty; | ||
| 1252 | } | ||
| 1253 | |||
| 1243 | using (var lab = new ConversionLab(element)) | 1254 | using (var lab = new ConversionLab(element)) |
| 1244 | { | 1255 | { |
| 1245 | lab.ReplaceTargetElement(new XElement(LaunchElementName, | 1256 | lab.ReplaceTargetElement(new XElement(LaunchElementName, |
| 1246 | new XAttribute("Condition", text), | 1257 | new XAttribute("Condition", value), |
| 1247 | new XAttribute("Message", message))); | 1258 | new XAttribute("Message", message))); |
| 1248 | lab.AddCommentsAsSiblings(comments); | 1259 | lab.AddCommentsAsSiblings(collector.Comments); |
| 1249 | } | 1260 | } |
| 1250 | } | 1261 | } |
| 1251 | } | 1262 | } |
| @@ -1290,7 +1301,8 @@ namespace WixToolset.Converters | |||
| 1290 | var xCondition = element.Element(ConditionElementName); | 1301 | var xCondition = element.Element(ConditionElementName); |
| 1291 | if (xCondition != null) | 1302 | if (xCondition != null) |
| 1292 | { | 1303 | { |
| 1293 | if (TryGetInnerText(xCondition, out var text, out var comments) && | 1304 | var collector = new InnerContentCollector(); |
| 1305 | if (collector.CollectInnerTextAndCommentsForAttributeValue(xCondition, out string value) && | ||
| 1294 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", xCondition.Name.LocalName)) | 1306 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", xCondition.Name.LocalName)) |
| 1295 | { | 1307 | { |
| 1296 | using (var lab = new ConversionLab(xCondition)) | 1308 | using (var lab = new ConversionLab(xCondition)) |
| @@ -1299,9 +1311,9 @@ namespace WixToolset.Converters | |||
| 1299 | } | 1311 | } |
| 1300 | using (var lab = new ConversionLab(element)) | 1312 | using (var lab = new ConversionLab(element)) |
| 1301 | { | 1313 | { |
| 1302 | element.Add(new XAttribute("Condition", text)); | 1314 | element.Add(new XAttribute("Condition", value)); |
| 1303 | lab.RemoveOrphanTextNodes(); | 1315 | lab.RemoveOrphanTextNodes(); |
| 1304 | lab.AddCommentsAsSiblings(comments); | 1316 | lab.AddCommentsAsSiblings(collector.Comments); |
| 1305 | } | 1317 | } |
| 1306 | } | 1318 | } |
| 1307 | } | 1319 | } |
| @@ -1669,33 +1681,35 @@ namespace WixToolset.Converters | |||
| 1669 | 1681 | ||
| 1670 | private void ConvertPublishElement(XElement element) | 1682 | private void ConvertPublishElement(XElement element) |
| 1671 | { | 1683 | { |
| 1672 | if (TryGetInnerText(element, out var text, out var comments) && | 1684 | var collector = new InnerContentCollector(); |
| 1685 | |||
| 1686 | if (collector.CollectInnerTextAndCommentsForAttributeValue(element, out string value) && | ||
| 1673 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", element.Name.LocalName)) | 1687 | this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", element.Name.LocalName)) |
| 1674 | { | 1688 | { |
| 1675 | using (var lab = new ConversionLab(element)) | 1689 | using (var lab = new ConversionLab(element)) |
| 1676 | { | 1690 | { |
| 1677 | if ("1" == text) | 1691 | if ("1" == value) |
| 1678 | { | 1692 | { |
| 1679 | this.OnInformation(ConverterTestType.PublishConditionOneUnnecessary, element, "Adding Condition='1' on {0} elements is no longer necessary. Remove the Condition attribute.", element.Name.LocalName); | 1693 | this.OnInformation(ConverterTestType.PublishConditionOneUnnecessary, element, "Adding Condition='1' on {0} elements is no longer necessary. Remove the Condition attribute.", element.Name.LocalName); |
| 1680 | } | 1694 | } |
| 1681 | else | 1695 | else |
| 1682 | { | 1696 | { |
| 1683 | element.Add(new XAttribute("Condition", text)); | 1697 | element.Add(new XAttribute("Condition", value)); |
| 1684 | } | 1698 | } |
| 1685 | 1699 | ||
| 1686 | lab.RemoveOrphanTextNodes(); | 1700 | lab.RemoveOrphanTextNodes(); |
| 1687 | lab.AddCommentsAsSiblings(comments); | 1701 | lab.AddCommentsAsSiblings(collector.Comments); |
| 1688 | } | 1702 | } |
| 1689 | } | 1703 | } |
| 1690 | 1704 | ||
| 1691 | var evnt = element.Attribute("Event")?.Value; | 1705 | var eventName = element.Attribute("Event")?.Value; |
| 1692 | var value = element.Attribute("Value")?.Value; | 1706 | var eventValue = element.Attribute("Value")?.Value; |
| 1693 | 1707 | ||
| 1694 | if (evnt?.Equals("DoAction", StringComparison.OrdinalIgnoreCase) == true | 1708 | if (eventName?.Equals("DoAction", StringComparison.OrdinalIgnoreCase) == true |
| 1695 | && value?.StartsWith("WixUI", StringComparison.OrdinalIgnoreCase) == true | 1709 | && eventValue?.StartsWith("WixUI", StringComparison.OrdinalIgnoreCase) == true |
| 1696 | && this.OnInformation(ConverterTestType.CustomActionIdsIncludePlatformSuffix, element, "Custom action ids have changed in WiX v4 extensions to support platform-specific custom actions. For more information, see https://wixtoolset.org/docs/fourthree/#converting-custom-wixui-dialog-sets.")) | 1710 | && this.OnInformation(ConverterTestType.CustomActionIdsIncludePlatformSuffix, element, "Custom action ids have changed in WiX v4 extensions to support platform-specific custom actions. For more information, see https://wixtoolset.org/docs/fourthree/#converting-custom-wixui-dialog-sets.")) |
| 1697 | { | 1711 | { |
| 1698 | element.Attribute("Value").Value = value + "_$(sys.BUILDARCHSHORT)"; | 1712 | element.Attribute("Value").Value = eventValue + "_$(sys.BUILDARCHSHORT)"; |
| 1699 | } | 1713 | } |
| 1700 | } | 1714 | } |
| 1701 | 1715 | ||
| @@ -1982,8 +1996,9 @@ namespace WixToolset.Converters | |||
| 1982 | } | 1996 | } |
| 1983 | 1997 | ||
| 1984 | var xScript = xCustomAction.Attribute("Script"); | 1998 | var xScript = xCustomAction.Attribute("Script"); |
| 1999 | var collector = new InnerContentCollector(); | ||
| 1985 | 2000 | ||
| 1986 | if (xScript != null && TryGetInnerText(xCustomAction, out var scriptText, out var comments)) | 2001 | if (xScript != null && collector.CollectInnerTextWithTrailingWhitespaceAndCommentsForScriptFile(xCustomAction, out string value)) |
| 1987 | { | 2002 | { |
| 1988 | if (this.OnInformation(ConverterTestType.InnerTextDeprecated, xCustomAction, "Using {0} element text is deprecated. Extract the text to a file and use the 'ScriptSourceFile' attribute to reference it.", xCustomAction.Name.LocalName)) | 2003 | if (this.OnInformation(ConverterTestType.InnerTextDeprecated, xCustomAction, "Using {0} element text is deprecated. Extract the text to a file and use the 'ScriptSourceFile' attribute to reference it.", xCustomAction.Name.LocalName)) |
| 1989 | { | 2004 | { |
| @@ -1992,12 +2007,12 @@ namespace WixToolset.Converters | |||
| 1992 | var ext = (xScript.Value == "jscript") ? ".js" : (xScript.Value == "vbscript") ? ".vbs" : ".txt"; | 2007 | var ext = (xScript.Value == "jscript") ? ".js" : (xScript.Value == "vbscript") ? ".vbs" : ".txt"; |
| 1993 | 2008 | ||
| 1994 | var scriptFile = Path.Combine(scriptFolder, id + ext); | 2009 | var scriptFile = Path.Combine(scriptFolder, id + ext); |
| 1995 | File.WriteAllText(scriptFile, scriptText); | 2010 | File.WriteAllText(scriptFile, value); |
| 1996 | 2011 | ||
| 1997 | RemoveChildren(xCustomAction); | 2012 | RemoveChildren(xCustomAction); |
| 1998 | xCustomAction.Add(new XAttribute("ScriptSourceFile", scriptFile)); | 2013 | xCustomAction.Add(new XAttribute("ScriptSourceFile", scriptFile)); |
| 1999 | 2014 | ||
| 2000 | if (comments.Any()) | 2015 | if (collector.Comments.Any()) |
| 2001 | { | 2016 | { |
| 2002 | var remainingNodes = xCustomAction.NodesAfterSelf().ToList(); | 2017 | var remainingNodes = xCustomAction.NodesAfterSelf().ToList(); |
| 2003 | var replacementNodes = remainingNodes.Where(e => XmlNodeType.Text != e.NodeType); | 2018 | var replacementNodes = remainingNodes.Where(e => XmlNodeType.Text != e.NodeType); |
| @@ -2005,7 +2020,7 @@ namespace WixToolset.Converters | |||
| 2005 | { | 2020 | { |
| 2006 | node.Remove(); | 2021 | node.Remove(); |
| 2007 | } | 2022 | } |
| 2008 | foreach (var comment in comments) | 2023 | foreach (var comment in collector.Comments) |
| 2009 | { | 2024 | { |
| 2010 | xCustomAction.Add(comment); | 2025 | xCustomAction.Add(comment); |
| 2011 | xCustomAction.Add("\n"); | 2026 | xCustomAction.Add("\n"); |
| @@ -2144,24 +2159,23 @@ namespace WixToolset.Converters | |||
| 2144 | 2159 | ||
| 2145 | private void ConvertInnerTextToAttribute(XElement element, string attributeName) | 2160 | private void ConvertInnerTextToAttribute(XElement element, string attributeName) |
| 2146 | { | 2161 | { |
| 2147 | if (TryGetInnerText(element, out var text, out var comments)) | 2162 | var collector = new InnerContentCollector(); |
| 2163 | |||
| 2164 | if (collector.CollectInnerTextAndCommentsForAttributeValue(element, out string value)) | ||
| 2148 | { | 2165 | { |
| 2149 | // If the target attribute already exists, error if we have anything more than whitespace. | 2166 | // If the target attribute already exists, error if we have anything more than whitespace. |
| 2150 | var attribute = element.Attribute(attributeName); | 2167 | var attribute = element.Attribute(attributeName); |
| 2151 | if (attribute != null) | 2168 | if (attribute != null) |
| 2152 | { | 2169 | { |
| 2153 | if (!String.IsNullOrWhiteSpace(text)) | 2170 | this.OnError(ConverterTestType.InnerTextDeprecated, attribute, "Using {0} element text is deprecated. Remove the element's text and use only the '{1}' attribute. See the conversion FAQ for more information: https://wixtoolset.org/docs/fourthree/faqs/#converting-packages", element.Name.LocalName, attributeName); |
| 2154 | { | ||
| 2155 | this.OnError(ConverterTestType.InnerTextDeprecated, attribute, "Using {0} element text is deprecated. Remove the element's text and use only the '{1}' attribute. See the conversion FAQ for more information: https://wixtoolset.org/docs/fourthree/faqs/#converting-packages", element.Name.LocalName, attributeName); | ||
| 2156 | } | ||
| 2157 | } | 2171 | } |
| 2158 | else if (this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the '{1}' attribute instead.", element.Name.LocalName, attributeName)) | 2172 | else if (this.OnInformation(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the '{1}' attribute instead.", element.Name.LocalName, attributeName)) |
| 2159 | { | 2173 | { |
| 2160 | using (var lab = new ConversionLab(element)) | 2174 | using (var lab = new ConversionLab(element)) |
| 2161 | { | 2175 | { |
| 2162 | lab.RemoveOrphanTextNodes(); | 2176 | lab.RemoveOrphanTextNodes(); |
| 2163 | element.Add(new XAttribute(attributeName, text)); | 2177 | element.Add(new XAttribute(attributeName, value)); |
| 2164 | lab.AddCommentsAsSiblings(comments); | 2178 | lab.AddCommentsAsSiblings(collector.Comments); |
| 2165 | } | 2179 | } |
| 2166 | } | 2180 | } |
| 2167 | } | 2181 | } |
| @@ -2854,42 +2868,6 @@ namespace WixToolset.Converters | |||
| 2854 | } | 2868 | } |
| 2855 | } | 2869 | } |
| 2856 | 2870 | ||
| 2857 | private static bool TryGetInnerText(XElement element, out string value, out List<XNode> comments) | ||
| 2858 | { | ||
| 2859 | return TryGetInnerText(element, out value, out comments, new List<XNode>()); | ||
| 2860 | } | ||
| 2861 | |||
| 2862 | private static bool TryGetInnerText(XElement element, out string value, out List<XNode> comments, List<XNode> initialComments) | ||
| 2863 | { | ||
| 2864 | value = null; | ||
| 2865 | comments = null; | ||
| 2866 | var found = false; | ||
| 2867 | |||
| 2868 | var nodes = element.Nodes().ToList(); | ||
| 2869 | comments = initialComments; | ||
| 2870 | var nonCommentNodes = new List<XNode>(); | ||
| 2871 | |||
| 2872 | foreach (var node in nodes) | ||
| 2873 | { | ||
| 2874 | if (XmlNodeType.Comment == node.NodeType) | ||
| 2875 | { | ||
| 2876 | comments.Add(node); | ||
| 2877 | } | ||
| 2878 | else | ||
| 2879 | { | ||
| 2880 | nonCommentNodes.Add(node); | ||
| 2881 | } | ||
| 2882 | } | ||
| 2883 | |||
| 2884 | if (nonCommentNodes.Any() && nonCommentNodes.All(e => e.NodeType == XmlNodeType.Text || e.NodeType == XmlNodeType.CDATA)) | ||
| 2885 | { | ||
| 2886 | value = String.Join(String.Empty, nonCommentNodes.Cast<XText>().Select(TrimTextValue)); | ||
| 2887 | found = true; | ||
| 2888 | } | ||
| 2889 | |||
| 2890 | return found; | ||
| 2891 | } | ||
| 2892 | |||
| 2893 | private static bool IsTextNode(XNode node, out XText text) | 2871 | private static bool IsTextNode(XNode node, out XText text) |
| 2894 | { | 2872 | { |
| 2895 | text = null; | 2873 | text = null; |
| @@ -2910,22 +2888,6 @@ namespace WixToolset.Converters | |||
| 2910 | } | 2888 | } |
| 2911 | } | 2889 | } |
| 2912 | 2890 | ||
| 2913 | private static string TrimTextValue(XText text) | ||
| 2914 | { | ||
| 2915 | var value = text.Value; | ||
| 2916 | |||
| 2917 | if (String.IsNullOrEmpty(value)) | ||
| 2918 | { | ||
| 2919 | return String.Empty; | ||
| 2920 | } | ||
| 2921 | else if (text.NodeType == XmlNodeType.CDATA && String.IsNullOrWhiteSpace(value)) | ||
| 2922 | { | ||
| 2923 | return " "; | ||
| 2924 | } | ||
| 2925 | |||
| 2926 | return value.Trim(); | ||
| 2927 | } | ||
| 2928 | |||
| 2929 | private static void RemoveChildren(XElement element) | 2891 | private static void RemoveChildren(XElement element) |
| 2930 | { | 2892 | { |
| 2931 | var nodes = element.Nodes().ToList(); | 2893 | var nodes = element.Nodes().ToList(); |
| @@ -2975,6 +2937,250 @@ namespace WixToolset.Converters | |||
| 2975 | return true; | 2937 | return true; |
| 2976 | } | 2938 | } |
| 2977 | 2939 | ||
| 2940 | // This class encapsulates methods for extraving text and comments from XElements. Multiple calls can be made to the collection | ||
| 2941 | // methods to processs multiple XElements. The Comments property is used to extract the list of comments accumulated during the collection process. | ||
| 2942 | private class InnerContentCollector | ||
| 2943 | { | ||
| 2944 | public InnerContentCollector() | ||
| 2945 | { | ||
| 2946 | this.Comments = new List<XNode>(); | ||
| 2947 | } | ||
| 2948 | |||
| 2949 | public List<XNode> Comments { get; private set; } | ||
| 2950 | |||
| 2951 | public bool CollectInnerTextAndCommentsForAttributeValue(XElement element, out string collectedText) | ||
| 2952 | { | ||
| 2953 | char[] whitespaceChars = { ' ', '\t', '\r', '\n' }; | ||
| 2954 | var nodes = element.Nodes().ToList(); | ||
| 2955 | var inWhitespace = false; | ||
| 2956 | var cDataFound = false; | ||
| 2957 | var sb = new StringBuilder(); | ||
| 2958 | |||
| 2959 | foreach (var node in nodes) | ||
| 2960 | { | ||
| 2961 | if (XmlNodeType.Comment == node.NodeType) | ||
| 2962 | { | ||
| 2963 | this.Comments.Add(node); | ||
| 2964 | } | ||
| 2965 | else if (XmlNodeType.CDATA == node.NodeType || XmlNodeType.Text == node.NodeType) | ||
| 2966 | { | ||
| 2967 | var isCData = XmlNodeType.CDATA == node.NodeType; | ||
| 2968 | |||
| 2969 | if (isCData) | ||
| 2970 | { | ||
| 2971 | cDataFound = true; | ||
| 2972 | } | ||
| 2973 | |||
| 2974 | var text = node is XText xtext ? xtext.Value : String.Empty; | ||
| 2975 | var nodeSB = new StringBuilder(); | ||
| 2976 | |||
| 2977 | foreach (var c in text) | ||
| 2978 | { | ||
| 2979 | char? emit = c; | ||
| 2980 | |||
| 2981 | // Replace contiguous whitespace with a single space. | ||
| 2982 | if (' ' == c || '\r' == c || '\n' == c || '\t' == c) | ||
| 2983 | { | ||
| 2984 | if (!inWhitespace) | ||
| 2985 | { | ||
| 2986 | inWhitespace = true; | ||
| 2987 | emit = ' '; | ||
| 2988 | } | ||
| 2989 | else | ||
| 2990 | { | ||
| 2991 | emit = null; | ||
| 2992 | } | ||
| 2993 | } | ||
| 2994 | else | ||
| 2995 | { | ||
| 2996 | inWhitespace = false; | ||
| 2997 | } | ||
| 2998 | |||
| 2999 | if (emit.HasValue) | ||
| 3000 | { | ||
| 3001 | nodeSB.Append(emit); | ||
| 3002 | } | ||
| 3003 | } | ||
| 3004 | |||
| 3005 | text = nodeSB.ToString().Trim(whitespaceChars); | ||
| 3006 | sb.Append(text); | ||
| 3007 | } | ||
| 3008 | } | ||
| 3009 | var found = false; | ||
| 3010 | collectedText = sb.ToString(); | ||
| 3011 | |||
| 3012 | if (0 < collectedText.Length) | ||
| 3013 | { | ||
| 3014 | found = true; | ||
| 3015 | } | ||
| 3016 | |||
| 3017 | collectedText = collectedText.Trim(whitespaceChars); | ||
| 3018 | |||
| 3019 | if (cDataFound) | ||
| 3020 | { | ||
| 3021 | found = true; | ||
| 3022 | |||
| 3023 | if (0 == collectedText.Length) | ||
| 3024 | { | ||
| 3025 | collectedText = " "; | ||
| 3026 | } | ||
| 3027 | } | ||
| 3028 | |||
| 3029 | return found; | ||
| 3030 | } | ||
| 3031 | |||
| 3032 | public bool CollectInnerTextWithTrailingWhitespaceAndCommentsForAttributeValue(XElement element, out string collectedText) | ||
| 3033 | { | ||
| 3034 | char[] whitespaceChars = { ' ', '\t', '\r', '\n' }; | ||
| 3035 | var nodes = element.Nodes().ToList(); | ||
| 3036 | var inWhitespace = false; | ||
| 3037 | var cDataFound = false; | ||
| 3038 | var whitespaceFound = false; | ||
| 3039 | var sb = new StringBuilder(); | ||
| 3040 | |||
| 3041 | foreach (var node in nodes) | ||
| 3042 | { | ||
| 3043 | if (XmlNodeType.Comment == node.NodeType) | ||
| 3044 | { | ||
| 3045 | this.Comments.Add(node); | ||
| 3046 | } | ||
| 3047 | else if (XmlNodeType.CDATA == node.NodeType || XmlNodeType.Text == node.NodeType) | ||
| 3048 | { | ||
| 3049 | var isCData = XmlNodeType.CDATA == node.NodeType; | ||
| 3050 | |||
| 3051 | if (isCData) | ||
| 3052 | { | ||
| 3053 | cDataFound = true; | ||
| 3054 | } | ||
| 3055 | |||
| 3056 | var text = node is XText xtext ? xtext.Value : String.Empty; | ||
| 3057 | var nodeSB = new StringBuilder(); | ||
| 3058 | |||
| 3059 | foreach (var c in text) | ||
| 3060 | { | ||
| 3061 | char? emit = c; | ||
| 3062 | |||
| 3063 | // Replace contiguous whitespace with a single space. | ||
| 3064 | if (' ' == c || '\r' == c || '\n' == c || '\t' == c) | ||
| 3065 | { | ||
| 3066 | if (!inWhitespace) | ||
| 3067 | { | ||
| 3068 | inWhitespace = true; | ||
| 3069 | whitespaceFound = true; | ||
| 3070 | emit = ' '; | ||
| 3071 | } | ||
| 3072 | else | ||
| 3073 | { | ||
| 3074 | emit = null; | ||
| 3075 | } | ||
| 3076 | } | ||
| 3077 | else | ||
| 3078 | { | ||
| 3079 | inWhitespace = false; | ||
| 3080 | } | ||
| 3081 | |||
| 3082 | if (emit.HasValue) | ||
| 3083 | { | ||
| 3084 | nodeSB.Append(emit); | ||
| 3085 | } | ||
| 3086 | } | ||
| 3087 | |||
| 3088 | text = nodeSB.ToString(); | ||
| 3089 | |||
| 3090 | if (0 < text.Length) | ||
| 3091 | { | ||
| 3092 | text = text.Trim(whitespaceChars); | ||
| 3093 | |||
| 3094 | if (0 == text.Length) | ||
| 3095 | { | ||
| 3096 | text = " "; | ||
| 3097 | } | ||
| 3098 | } | ||
| 3099 | |||
| 3100 | sb.Append(text); | ||
| 3101 | } | ||
| 3102 | } | ||
| 3103 | var found = false; | ||
| 3104 | collectedText = sb.ToString(); | ||
| 3105 | |||
| 3106 | if (0 < collectedText.Length) | ||
| 3107 | { | ||
| 3108 | found = true; | ||
| 3109 | } | ||
| 3110 | |||
| 3111 | collectedText = collectedText.Trim(whitespaceChars); | ||
| 3112 | |||
| 3113 | if (whitespaceFound) | ||
| 3114 | { | ||
| 3115 | found = true; | ||
| 3116 | } | ||
| 3117 | |||
| 3118 | if (cDataFound) | ||
| 3119 | { | ||
| 3120 | found = true; | ||
| 3121 | |||
| 3122 | if (0 == collectedText.Length) | ||
| 3123 | { | ||
| 3124 | collectedText = " "; | ||
| 3125 | } | ||
| 3126 | } | ||
| 3127 | |||
| 3128 | return found; | ||
| 3129 | } | ||
| 3130 | |||
| 3131 | public bool CollectInnerTextWithTrailingWhitespaceAndCommentsForScriptFile(XElement element, out string collectedText) | ||
| 3132 | { | ||
| 3133 | var value = String.Empty; | ||
| 3134 | char[] whitespaceChars = { ' ', '\t', '\r', '\n' }; | ||
| 3135 | var nodes = element.Nodes().ToList(); | ||
| 3136 | var cDataFound = false; | ||
| 3137 | var sb = new StringBuilder(); | ||
| 3138 | |||
| 3139 | foreach (var node in nodes) | ||
| 3140 | { | ||
| 3141 | if (XmlNodeType.Comment == node.NodeType) | ||
| 3142 | { | ||
| 3143 | this.Comments.Add(node); | ||
| 3144 | } | ||
| 3145 | else if (XmlNodeType.CDATA == node.NodeType || XmlNodeType.Text == node.NodeType) | ||
| 3146 | { | ||
| 3147 | var isCData = XmlNodeType.CDATA == node.NodeType; | ||
| 3148 | |||
| 3149 | if (isCData) | ||
| 3150 | { | ||
| 3151 | cDataFound = true; | ||
| 3152 | } | ||
| 3153 | |||
| 3154 | var text = node is XText xtext ? xtext.Value.Trim(whitespaceChars) : String.Empty; | ||
| 3155 | sb.Append(text); | ||
| 3156 | } | ||
| 3157 | } | ||
| 3158 | |||
| 3159 | var found = false; | ||
| 3160 | |||
| 3161 | collectedText = sb.ToString(); | ||
| 3162 | |||
| 3163 | if (0 < collectedText.Length) | ||
| 3164 | { | ||
| 3165 | found = true; | ||
| 3166 | } | ||
| 3167 | |||
| 3168 | collectedText = collectedText.Trim(whitespaceChars); | ||
| 3169 | |||
| 3170 | if (cDataFound) | ||
| 3171 | { | ||
| 3172 | found = true; | ||
| 3173 | |||
| 3174 | if (0 == collectedText.Length) | ||
| 3175 | { | ||
| 3176 | collectedText = " "; | ||
| 3177 | } | ||
| 3178 | } | ||
| 3179 | |||
| 3180 | return found; | ||
| 3181 | } | ||
| 3182 | } | ||
| 3183 | |||
| 2978 | /// <summary> | 3184 | /// <summary> |
| 2979 | /// Converter test types. These are used to condition error messages down to warnings. | 3185 | /// Converter test types. These are used to condition error messages down to warnings. |
| 2980 | /// </summary> | 3186 | /// </summary> |
diff --git a/src/wix/test/WixToolsetTest.Converters/ConditionFixture.cs b/src/wix/test/WixToolsetTest.Converters/ConditionFixture.cs index e3563c60..f9b60673 100644 --- a/src/wix/test/WixToolsetTest.Converters/ConditionFixture.cs +++ b/src/wix/test/WixToolsetTest.Converters/ConditionFixture.cs | |||
| @@ -21,8 +21,8 @@ namespace WixToolsetTest.Converters | |||
| 21 | " <UI>", | 21 | " <UI>", |
| 22 | " <Dialog Id='Dlg1'>", | 22 | " <Dialog Id='Dlg1'>", |
| 23 | " <Control Id='Control1'>", | 23 | " <Control Id='Control1'>", |
| 24 | " <Condition Action='disable'>x=y</Condition>", | 24 | " <Condition Action='disable'>$(var.x)=$(var.y)</Condition>", |
| 25 | " <Condition Action='hide'>a<>b</Condition>", | 25 | " <Condition Action='hide'>$(var.a)<>$(var.b)</Condition>", |
| 26 | " </Control>", | 26 | " </Control>", |
| 27 | " </Dialog>", | 27 | " </Dialog>", |
| 28 | " </UI>", | 28 | " </UI>", |
| @@ -35,7 +35,7 @@ namespace WixToolsetTest.Converters | |||
| 35 | " <Fragment>", | 35 | " <Fragment>", |
| 36 | " <UI>", | 36 | " <UI>", |
| 37 | " <Dialog Id=\"Dlg1\">", | 37 | " <Dialog Id=\"Dlg1\">", |
| 38 | " <Control Id=\"Control1\" DisableCondition=\"x=y\" HideCondition=\"a<>b\" />", | 38 | " <Control Id=\"Control1\" DisableCondition=\"$(var.x)=$(var.y)\" HideCondition=\"$(var.a)<>$(var.b)\" />", |
| 39 | " </Dialog>", | 39 | " </Dialog>", |
| 40 | " </UI>", | 40 | " </UI>", |
| 41 | " </Fragment>", | 41 | " </Fragment>", |
| @@ -64,8 +64,8 @@ namespace WixToolsetTest.Converters | |||
| 64 | " <UI>", | 64 | " <UI>", |
| 65 | " <Dialog Id='Dlg1'>", | 65 | " <Dialog Id='Dlg1'>", |
| 66 | " <Control Id='Control1'>", | 66 | " <Control Id='Control1'>", |
| 67 | " <Condition Action='hide'>x=y</Condition>", | 67 | " <Condition Action='hide'>$(var.x)=$(var.y)</Condition>", |
| 68 | " <Condition Action='hide'>a<>b</Condition>", | 68 | " <Condition Action='hide'>$(var.a)<>$(var.b)</Condition>", |
| 69 | " </Control>", | 69 | " </Control>", |
| 70 | " </Dialog>", | 70 | " </Dialog>", |
| 71 | " </UI>", | 71 | " </UI>", |
| @@ -78,7 +78,7 @@ namespace WixToolsetTest.Converters | |||
| 78 | " <Fragment>", | 78 | " <Fragment>", |
| 79 | " <UI>", | 79 | " <UI>", |
| 80 | " <Dialog Id=\"Dlg1\">", | 80 | " <Dialog Id=\"Dlg1\">", |
| 81 | " <Control Id=\"Control1\" HideCondition=\"(x=y) OR (a<>b)\" />", | 81 | " <Control Id=\"Control1\" HideCondition=\"($(var.x)=$(var.y)) OR ($(var.a)<>$(var.b))\" />", |
| 82 | " </Dialog>", | 82 | " </Dialog>", |
| 83 | " </UI>", | 83 | " </UI>", |
| 84 | " </Fragment>", | 84 | " </Fragment>", |
| @@ -107,8 +107,8 @@ namespace WixToolsetTest.Converters | |||
| 107 | " <UI>", | 107 | " <UI>", |
| 108 | " <Dialog Id='Dlg1'>", | 108 | " <Dialog Id='Dlg1'>", |
| 109 | " <Control Id='Control1'>", | 109 | " <Control Id='Control1'>", |
| 110 | " <Condition Action='disable'><!-- Comment 1 -->x=y</Condition>", | 110 | " <Condition Action='disable'><!-- Comment 1 -->$(var.x)=$(var.y)</Condition>", |
| 111 | " <Condition Action='hide'><!-- Comment 2 -->a<>b</Condition>", | 111 | " <Condition Action='hide'><!-- Comment 2 -->$(var.a)<>$(var.b)</Condition>", |
| 112 | " </Control>", | 112 | " </Control>", |
| 113 | " </Dialog>", | 113 | " </Dialog>", |
| 114 | " </UI>", | 114 | " </UI>", |
| @@ -123,7 +123,91 @@ namespace WixToolsetTest.Converters | |||
| 123 | " <Dialog Id=\"Dlg1\">", | 123 | " <Dialog Id=\"Dlg1\">", |
| 124 | " <!-- Comment 1 -->", | 124 | " <!-- Comment 1 -->", |
| 125 | " <!-- Comment 2 -->", | 125 | " <!-- Comment 2 -->", |
| 126 | " <Control Id=\"Control1\" DisableCondition=\"x=y\" HideCondition=\"a<>b\" />", | 126 | " <Control Id=\"Control1\" DisableCondition=\"$(var.x)=$(var.y)\" HideCondition=\"$(var.a)<>$(var.b)\" />", |
| 127 | " </Dialog>", | ||
| 128 | " </UI>", | ||
| 129 | " </Fragment>", | ||
| 130 | "</Wix>" | ||
| 131 | }; | ||
| 132 | |||
| 133 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 134 | |||
| 135 | var messaging = new MockMessaging(); | ||
| 136 | var converter = new WixConverter(messaging, 2, null, null); | ||
| 137 | |||
| 138 | var errors = converter.ConvertDocument(document); | ||
| 139 | Assert.Equal(4, errors); | ||
| 140 | |||
| 141 | var actualLines = UnformattedDocumentLines(document); | ||
| 142 | WixAssert.CompareLineByLine(expected, actualLines); | ||
| 143 | } | ||
| 144 | |||
| 145 | [Fact] | ||
| 146 | public void DemonstrateTheHandlingOfQuotedBackslashesInInnerText() | ||
| 147 | { | ||
| 148 | var parse = String.Join(Environment.NewLine, | ||
| 149 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 150 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
| 151 | " <Fragment>", | ||
| 152 | " <UI>", | ||
| 153 | " <Dialog Id='Dlg1'>", | ||
| 154 | " <Control Id='Control1'>", | ||
| 155 | " <Condition Action='hide'>\"\\\"=$(var.separator)</Condition>", | ||
| 156 | " </Control>", | ||
| 157 | " </Dialog>", | ||
| 158 | " </UI>", | ||
| 159 | " </Fragment>", | ||
| 160 | "</Wix>"); | ||
| 161 | |||
| 162 | var expected = new[] | ||
| 163 | { | ||
| 164 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 165 | " <Fragment>", | ||
| 166 | " <UI>", | ||
| 167 | " <Dialog Id=\"Dlg1\">", | ||
| 168 | " <Control Id=\"Control1\" HideCondition=\""\\"=$(var.separator)\" />", | ||
| 169 | " </Dialog>", | ||
| 170 | " </UI>", | ||
| 171 | " </Fragment>", | ||
| 172 | "</Wix>" | ||
| 173 | }; | ||
| 174 | |||
| 175 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 176 | |||
| 177 | var messaging = new MockMessaging(); | ||
| 178 | var converter = new WixConverter(messaging, 2, null, null); | ||
| 179 | |||
| 180 | var errors = converter.ConvertDocument(document); | ||
| 181 | |||
| 182 | var actualLines = UnformattedDocumentLines(document); | ||
| 183 | WixAssert.CompareLineByLine(expected, actualLines); | ||
| 184 | } | ||
| 185 | |||
| 186 | [Fact] | ||
| 187 | public void FixControlConditionWithStringConstants() | ||
| 188 | { | ||
| 189 | var parse = String.Join(Environment.NewLine, | ||
| 190 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 191 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
| 192 | " <Fragment>", | ||
| 193 | " <UI>", | ||
| 194 | " <Dialog Id='Dlg1'>", | ||
| 195 | " <Control Id='Control1'>", | ||
| 196 | " <Condition Action='hide'>\"x\"=$(var.y)</Condition>", | ||
| 197 | " <Condition Action='hide'>\"x's\"=$(var.y)</Condition>", | ||
| 198 | " </Control>", | ||
| 199 | " </Dialog>", | ||
| 200 | " </UI>", | ||
| 201 | " </Fragment>", | ||
| 202 | "</Wix>"); | ||
| 203 | |||
| 204 | var expected = new[] | ||
| 205 | { | ||
| 206 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 207 | " <Fragment>", | ||
| 208 | " <UI>", | ||
| 209 | " <Dialog Id=\"Dlg1\">", | ||
| 210 | " <Control Id=\"Control1\" HideCondition=\"("x"=$(var.y)) OR ("x's"=$(var.y))\" />", | ||
| 127 | " </Dialog>", | 211 | " </Dialog>", |
| 128 | " </UI>", | 212 | " </UI>", |
| 129 | " </Fragment>", | 213 | " </Fragment>", |
| @@ -306,6 +390,78 @@ namespace WixToolsetTest.Converters | |||
| 306 | } | 390 | } |
| 307 | 391 | ||
| 308 | [Fact] | 392 | [Fact] |
| 393 | public void FixMultilineComponentCondition() | ||
| 394 | { | ||
| 395 | var parse = String.Join(Environment.NewLine, | ||
| 396 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 397 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
| 398 | " <Fragment>", | ||
| 399 | " <Component Id='Comp1' Directory='ApplicationFolder'>", | ||
| 400 | " <Condition>1<2</Condition>", | ||
| 401 | " </Component>", | ||
| 402 | " </Fragment>", | ||
| 403 | "</Wix>"); | ||
| 404 | |||
| 405 | var expected = new[] | ||
| 406 | { | ||
| 407 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 408 | " <Fragment>", | ||
| 409 | " <Component Id=\"Comp1\" Directory=\"ApplicationFolder\" Condition=\"1<2\" />", | ||
| 410 | " </Fragment>", | ||
| 411 | "</Wix>" | ||
| 412 | }; | ||
| 413 | |||
| 414 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 415 | |||
| 416 | var messaging = new MockMessaging(); | ||
| 417 | var converter = new WixConverter(messaging, 2, null, null); | ||
| 418 | |||
| 419 | var errors = converter.ConvertDocument(document); | ||
| 420 | Assert.Equal(3, errors); | ||
| 421 | |||
| 422 | var actualLines = UnformattedDocumentLines(document); | ||
| 423 | WixAssert.CompareLineByLine(expected, actualLines); | ||
| 424 | } | ||
| 425 | |||
| 426 | [Fact] | ||
| 427 | public void FixMultilineComponentConditionWithComment() | ||
| 428 | { | ||
| 429 | var parse = String.Join(Environment.NewLine, | ||
| 430 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 431 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
| 432 | " <Fragment>", | ||
| 433 | " <Component Id='Comp1' Directory='ApplicationFolder'>", | ||
| 434 | " <Condition>", | ||
| 435 | " <!-- Comment -->", | ||
| 436 | " 1<2 OR ", | ||
| 437 | " 4<3", | ||
| 438 | " </Condition>", | ||
| 439 | " </Component>", | ||
| 440 | " </Fragment>", | ||
| 441 | "</Wix>"); | ||
| 442 | var expected = new[] | ||
| 443 | { | ||
| 444 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 445 | " <Fragment>", | ||
| 446 | " <!-- Comment -->", | ||
| 447 | " <Component Id=\"Comp1\" Directory=\"ApplicationFolder\" Condition=\"1<2 OR 4<3\" />", | ||
| 448 | " </Fragment>", | ||
| 449 | "</Wix>" | ||
| 450 | }; | ||
| 451 | |||
| 452 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 453 | |||
| 454 | var messaging = new MockMessaging(); | ||
| 455 | var converter = new WixConverter(messaging, 2, null, null); | ||
| 456 | |||
| 457 | var errors = converter.ConvertDocument(document); | ||
| 458 | Assert.Equal(3, errors); | ||
| 459 | |||
| 460 | var actualLines = UnformattedDocumentLines(document); | ||
| 461 | WixAssert.CompareLineByLine(expected, actualLines); | ||
| 462 | } | ||
| 463 | |||
| 464 | [Fact] | ||
| 309 | public void FixEmptyCondition() | 465 | public void FixEmptyCondition() |
| 310 | { | 466 | { |
| 311 | var parse = String.Join(Environment.NewLine, | 467 | var parse = String.Join(Environment.NewLine, |
| @@ -481,6 +637,90 @@ namespace WixToolsetTest.Converters | |||
| 481 | } | 637 | } |
| 482 | 638 | ||
| 483 | [Fact] | 639 | [Fact] |
| 640 | public void FixMultilineFeatureCondition() | ||
| 641 | { | ||
| 642 | var parse = String.Join(Environment.NewLine, | ||
| 643 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 644 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
| 645 | " <Fragment>", | ||
| 646 | " <Feature Id='ShellExtensionFeature' Level='0' InstallDefault='local' >", | ||
| 647 | " <Condition Level='1'>", | ||
| 648 | " (NOT Installed AND NOT PERUSER) OR", | ||
| 649 | " (Installed AND ZOS_SHELL_EXTENSION_INSTALLLED)", | ||
| 650 | " </Condition>", | ||
| 651 | " <ComponentGroupRef Id='ShellExtComponents' />", | ||
| 652 | " </Feature>", | ||
| 653 | " </Fragment>", | ||
| 654 | "</Wix>"); | ||
| 655 | |||
| 656 | var expected = new[] | ||
| 657 | { | ||
| 658 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 659 | " <Fragment>", | ||
| 660 | " <Feature Id=\"ShellExtensionFeature\" Level=\"0\" InstallDefault=\"local\">", | ||
| 661 | " <Level Value=\"1\" Condition=\"(NOT Installed AND NOT PERUSER) OR (Installed AND ZOS_SHELL_EXTENSION_INSTALLLED)\" />", | ||
| 662 | " <ComponentGroupRef Id=\"ShellExtComponents\" />", | ||
| 663 | " </Feature>", | ||
| 664 | " </Fragment>", | ||
| 665 | "</Wix>" | ||
| 666 | }; | ||
| 667 | |||
| 668 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 669 | |||
| 670 | var messaging = new MockMessaging(); | ||
| 671 | var converter = new WixConverter(messaging, 2, null, null); | ||
| 672 | |||
| 673 | var errors = converter.ConvertDocument(document); | ||
| 674 | Assert.Equal(3, errors); | ||
| 675 | |||
| 676 | var actualLines = UnformattedDocumentLines(document); | ||
| 677 | WixAssert.CompareLineByLine(expected, actualLines); | ||
| 678 | } | ||
| 679 | |||
| 680 | [Fact] | ||
| 681 | public void FixMultilineFeatureConditionWithComment() | ||
| 682 | { | ||
| 683 | var parse = String.Join(Environment.NewLine, | ||
| 684 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 685 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
| 686 | " <Fragment>", | ||
| 687 | " <Feature Id='ShellExtensionFeature' Level='0' InstallDefault='local' >", | ||
| 688 | " <Condition Level='1'>", | ||
| 689 | " <!-- Comment -->", | ||
| 690 | " (NOT Installed AND NOT PERUSER) OR", | ||
| 691 | " (Installed AND ZOS_SHELL_EXTENSION_INSTALLLED)", | ||
| 692 | " </Condition>", | ||
| 693 | " <ComponentGroupRef Id='ShellExtComponents' />", | ||
| 694 | " </Feature>", | ||
| 695 | " </Fragment>", | ||
| 696 | "</Wix>"); | ||
| 697 | |||
| 698 | var expected = new[] | ||
| 699 | { | ||
| 700 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 701 | " <Fragment>", | ||
| 702 | " <Feature Id=\"ShellExtensionFeature\" Level=\"0\" InstallDefault=\"local\">", | ||
| 703 | " <!-- Comment -->", | ||
| 704 | " <Level Value=\"1\" Condition=\"(NOT Installed AND NOT PERUSER) OR (Installed AND ZOS_SHELL_EXTENSION_INSTALLLED)\" />", | ||
| 705 | " <ComponentGroupRef Id=\"ShellExtComponents\" />", | ||
| 706 | " </Feature>", | ||
| 707 | " </Fragment>", | ||
| 708 | "</Wix>" | ||
| 709 | }; | ||
| 710 | |||
| 711 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 712 | |||
| 713 | var messaging = new MockMessaging(); | ||
| 714 | var converter = new WixConverter(messaging, 2, null, null); | ||
| 715 | |||
| 716 | var errors = converter.ConvertDocument(document); | ||
| 717 | Assert.Equal(3, errors); | ||
| 718 | |||
| 719 | var actualLines = UnformattedDocumentLines(document); | ||
| 720 | WixAssert.CompareLineByLine(expected, actualLines); | ||
| 721 | } | ||
| 722 | |||
| 723 | [Fact] | ||
| 484 | public void FixLaunchConditionInFragment() | 724 | public void FixLaunchConditionInFragment() |
| 485 | { | 725 | { |
| 486 | var parse = String.Join(Environment.NewLine, | 726 | var parse = String.Join(Environment.NewLine, |
| @@ -519,7 +759,7 @@ namespace WixToolsetTest.Converters | |||
| 519 | } | 759 | } |
| 520 | 760 | ||
| 521 | [Fact] | 761 | [Fact] |
| 522 | public void FixLaunchConditionWithComment() | 762 | public void FixLaunchConditionInFragmentWithComment() |
| 523 | { | 763 | { |
| 524 | var parse = String.Join(Environment.NewLine, | 764 | var parse = String.Join(Environment.NewLine, |
| 525 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | 765 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", |
| @@ -559,6 +799,87 @@ namespace WixToolsetTest.Converters | |||
| 559 | } | 799 | } |
| 560 | 800 | ||
| 561 | [Fact] | 801 | [Fact] |
| 802 | public void FixMultilineLaunchConditionInFragment() | ||
| 803 | { | ||
| 804 | var parse = String.Join(Environment.NewLine, | ||
| 805 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 806 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
| 807 | " <Fragment>", | ||
| 808 | " <Condition Message='Stop the install'>", | ||
| 809 | " 1<2 OR ", | ||
| 810 | " 4<3", | ||
| 811 | " </Condition>", | ||
| 812 | " <Condition Message='Do not stop'>", | ||
| 813 | " 1=2", | ||
| 814 | " </Condition>", | ||
| 815 | " </Fragment>", | ||
| 816 | "</Wix>"); | ||
| 817 | |||
| 818 | var expected = new[] | ||
| 819 | { | ||
| 820 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 821 | " <Fragment>", | ||
| 822 | " <Launch Condition=\"1<2 OR 4<3\" Message=\"Stop the install\" />", | ||
| 823 | " <Launch Condition=\"1=2\" Message=\"Do not stop\" />", | ||
| 824 | " </Fragment>", | ||
| 825 | "</Wix>" | ||
| 826 | }; | ||
| 827 | |||
| 828 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 829 | |||
| 830 | var messaging = new MockMessaging(); | ||
| 831 | var converter = new WixConverter(messaging, 2, null, null); | ||
| 832 | |||
| 833 | var errors = converter.ConvertDocument(document); | ||
| 834 | Assert.Equal(4, errors); | ||
| 835 | |||
| 836 | var actualLines = UnformattedDocumentLines(document); | ||
| 837 | WixAssert.CompareLineByLine(expected, actualLines); | ||
| 838 | } | ||
| 839 | |||
| 840 | [Fact] | ||
| 841 | public void FixMultilineLaunchConditionInFragmentWithComment() | ||
| 842 | { | ||
| 843 | var parse = String.Join(Environment.NewLine, | ||
| 844 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 845 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
| 846 | " <Fragment>", | ||
| 847 | " <Condition Message='Stop the install'>", | ||
| 848 | " <!-- Comment 1 -->", | ||
| 849 | " 1<2 OR", | ||
| 850 | " 4<3", | ||
| 851 | " </Condition>", | ||
| 852 | " <Condition Message='Do not stop'>", | ||
| 853 | " <!-- Comment 2 -->1=2", | ||
| 854 | " </Condition>", | ||
| 855 | " </Fragment>", | ||
| 856 | "</Wix>"); | ||
| 857 | |||
| 858 | var expected = new[] | ||
| 859 | { | ||
| 860 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 861 | " <Fragment>", | ||
| 862 | " <!-- Comment 1 -->", | ||
| 863 | " <Launch Condition=\"1<2 OR 4<3\" Message=\"Stop the install\" />", | ||
| 864 | " <!-- Comment 2 -->", | ||
| 865 | " <Launch Condition=\"1=2\" Message=\"Do not stop\" />", | ||
| 866 | " </Fragment>", | ||
| 867 | "</Wix>" | ||
| 868 | }; | ||
| 869 | |||
| 870 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 871 | |||
| 872 | var messaging = new MockMessaging(); | ||
| 873 | var converter = new WixConverter(messaging, 2, null, null); | ||
| 874 | |||
| 875 | var errors = converter.ConvertDocument(document); | ||
| 876 | Assert.Equal(4, errors); | ||
| 877 | |||
| 878 | var actualLines = UnformattedDocumentLines(document); | ||
| 879 | WixAssert.CompareLineByLine(expected, actualLines); | ||
| 880 | } | ||
| 881 | |||
| 882 | [Fact] | ||
| 562 | public void FixLaunchConditionInProduct() | 883 | public void FixLaunchConditionInProduct() |
| 563 | { | 884 | { |
| 564 | var parse = String.Join(Environment.NewLine, | 885 | var parse = String.Join(Environment.NewLine, |
