diff options
Diffstat (limited to 'src')
5 files changed, 272 insertions, 61 deletions
diff --git a/src/wix/WixToolset.Converters/HashSetExtensions.cs b/src/wix/WixToolset.Converters/HashSetExtensions.cs new file mode 100644 index 00000000..49b0d4ac --- /dev/null +++ b/src/wix/WixToolset.Converters/HashSetExtensions.cs | |||
| @@ -0,0 +1,17 @@ | |||
| 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.Converters | ||
| 4 | { | ||
| 5 | using System.Collections.Generic; | ||
| 6 | |||
| 7 | internal static class HashSetExtensions | ||
| 8 | { | ||
| 9 | public static void AddRange<T>(this HashSet<T> set, IEnumerable<T> values) | ||
| 10 | { | ||
| 11 | foreach (var value in values) | ||
| 12 | { | ||
| 13 | set.Add(value); | ||
| 14 | } | ||
| 15 | } | ||
| 16 | } | ||
| 17 | } | ||
diff --git a/src/wix/WixToolset.Converters/WixConverter.cs b/src/wix/WixToolset.Converters/WixConverter.cs index de81c876..cf77681c 100644 --- a/src/wix/WixToolset.Converters/WixConverter.cs +++ b/src/wix/WixToolset.Converters/WixConverter.cs | |||
| @@ -11,6 +11,7 @@ namespace WixToolset.Converters | |||
| 11 | using System.Text.RegularExpressions; | 11 | using System.Text.RegularExpressions; |
| 12 | using System.Xml; | 12 | using System.Xml; |
| 13 | using System.Xml.Linq; | 13 | using System.Xml.Linq; |
| 14 | using System.Xml.XPath; | ||
| 14 | using WixToolset.Data; | 15 | using WixToolset.Data; |
| 15 | using WixToolset.Data.WindowsInstaller; | 16 | using WixToolset.Data.WindowsInstaller; |
| 16 | using WixToolset.Extensibility.Services; | 17 | using WixToolset.Extensibility.Services; |
| @@ -272,6 +273,8 @@ namespace WixToolset.Converters | |||
| 272 | { WixConverter.WixLocalizationElementWithoutNamespaceName, this.ConvertWixLocalizationElementWithoutNamespace }, | 273 | { WixConverter.WixLocalizationElementWithoutNamespaceName, this.ConvertWixLocalizationElementWithoutNamespace }, |
| 273 | }; | 274 | }; |
| 274 | 275 | ||
| 276 | this.ConversionMessages = new List<Message>(); | ||
| 277 | |||
| 275 | this.Messaging = messaging; | 278 | this.Messaging = messaging; |
| 276 | 279 | ||
| 277 | this.IndentationAmount = indentationAmount; | 280 | this.IndentationAmount = indentationAmount; |
| @@ -285,7 +288,7 @@ namespace WixToolset.Converters | |||
| 285 | 288 | ||
| 286 | private CustomTableTarget CustomTableSetting { get; } | 289 | private CustomTableTarget CustomTableSetting { get; } |
| 287 | 290 | ||
| 288 | private int Messages { get; set; } | 291 | private List<Message> ConversionMessages { get; } |
| 289 | 292 | ||
| 290 | private HashSet<ConverterTestType> ErrorsAsWarnings { get; set; } | 293 | private HashSet<ConverterTestType> ErrorsAsWarnings { get; set; } |
| 291 | 294 | ||
| @@ -308,54 +311,35 @@ namespace WixToolset.Converters | |||
| 308 | /// </summary> | 311 | /// </summary> |
| 309 | /// <param name="sourceFile">The file to convert.</param> | 312 | /// <param name="sourceFile">The file to convert.</param> |
| 310 | /// <param name="saveConvertedFile">Option to save the converted Messages that are found.</param> | 313 | /// <param name="saveConvertedFile">Option to save the converted Messages that are found.</param> |
| 311 | /// <returns>The number of Messages found.</returns> | 314 | /// <returns>The number of conversions found.</returns> |
| 312 | public int ConvertFile(string sourceFile, bool saveConvertedFile) | 315 | public int ConvertFile(string sourceFile, bool saveConvertedFile) |
| 313 | { | 316 | { |
| 314 | var document = this.OpenSourceFile(sourceFile); | 317 | var savedDocument = false; |
| 315 | 318 | ||
| 316 | if (document is null) | 319 | if (this.TryOpenSourceFile(sourceFile, out var document)) |
| 317 | { | 320 | { |
| 318 | return 1; | 321 | this.Convert(document); |
| 319 | } | ||
| 320 | |||
| 321 | this.ConvertDocument(document); | ||
| 322 | 322 | ||
| 323 | // Fix Messages if requested and necessary. | 323 | // Fix Messages if requested and necessary. |
| 324 | if (saveConvertedFile && 0 < this.Messages) | 324 | if (saveConvertedFile && 0 < this.ConversionMessages.Count) |
| 325 | { | 325 | { |
| 326 | this.SaveDocument(document); | 326 | savedDocument = this.SaveDocument(document); |
| 327 | } | ||
| 327 | } | 328 | } |
| 328 | 329 | ||
| 329 | return this.Messages; | 330 | return this.ReportMessages(document, savedDocument); |
| 330 | } | 331 | } |
| 331 | 332 | ||
| 332 | /// <summary> | 333 | /// <summary> |
| 333 | /// Convert a document. | 334 | /// Convert a document. |
| 334 | /// </summary> | 335 | /// </summary> |
| 335 | /// <param name="document">The document to convert.</param> | 336 | /// <param name="document">The document to convert.</param> |
| 336 | /// <returns>The number of Messages found.</returns> | 337 | /// <returns>The number of conversions found.</returns> |
| 337 | public int ConvertDocument(XDocument document) | 338 | public int ConvertDocument(XDocument document) |
| 338 | { | 339 | { |
| 339 | // Reset the instance info. | 340 | this.Convert(document); |
| 340 | this.Messages = 0; | ||
| 341 | this.SourceVersion = 0; | ||
| 342 | this.Operation = ConvertOperation.Convert; | ||
| 343 | |||
| 344 | // Remove the declaration. | ||
| 345 | if (null != document.Declaration | ||
| 346 | && this.OnInformation(ConverterTestType.DeclarationPresent, null, "This file contains an XML declaration on the first line.")) | ||
| 347 | { | ||
| 348 | document.Declaration = null; | ||
| 349 | TrimLeadingText(document); | ||
| 350 | } | ||
| 351 | |||
| 352 | this.XRoot = document.Root; | ||
| 353 | |||
| 354 | // Start converting the nodes at the top. | ||
| 355 | this.ConvertNodes(document.Nodes(), 0); | ||
| 356 | this.RemoveUnusedNamespaces(document.Root); | ||
| 357 | 341 | ||
| 358 | return this.Messages; | 342 | return this.ReportMessages(document, false); |
| 359 | } | 343 | } |
| 360 | 344 | ||
| 361 | /// <summary> | 345 | /// <summary> |
| @@ -366,22 +350,20 @@ namespace WixToolset.Converters | |||
| 366 | /// <returns>The number of Messages found.</returns> | 350 | /// <returns>The number of Messages found.</returns> |
| 367 | public int FormatFile(string sourceFile, bool saveConvertedFile) | 351 | public int FormatFile(string sourceFile, bool saveConvertedFile) |
| 368 | { | 352 | { |
| 369 | var document = this.OpenSourceFile(sourceFile); | 353 | var savedDocument = false; |
| 370 | 354 | ||
| 371 | if (document is null) | 355 | if (this.TryOpenSourceFile(sourceFile, out var document)) |
| 372 | { | 356 | { |
| 373 | return 1; | 357 | this.FormatDocument(document); |
| 374 | } | ||
| 375 | |||
| 376 | this.FormatDocument(document); | ||
| 377 | 358 | ||
| 378 | // Fix Messages if requested and necessary. | 359 | // Fix Messages if requested and necessary. |
| 379 | if (saveConvertedFile && 0 < this.Messages) | 360 | if (saveConvertedFile && 0 < this.ConversionMessages.Count) |
| 380 | { | 361 | { |
| 381 | this.SaveDocument(document); | 362 | savedDocument = this.SaveDocument(document); |
| 363 | } | ||
| 382 | } | 364 | } |
| 383 | 365 | ||
| 384 | return this.Messages; | 366 | return this.ReportMessages(document, savedDocument); |
| 385 | } | 367 | } |
| 386 | 368 | ||
| 387 | /// <summary> | 369 | /// <summary> |
| @@ -391,43 +373,73 @@ namespace WixToolset.Converters | |||
| 391 | /// <returns>The number of Messages found.</returns> | 373 | /// <returns>The number of Messages found.</returns> |
| 392 | public int FormatDocument(XDocument document) | 374 | public int FormatDocument(XDocument document) |
| 393 | { | 375 | { |
| 376 | this.Format(document); | ||
| 377 | |||
| 378 | return this.ReportMessages(document, false); | ||
| 379 | } | ||
| 380 | |||
| 381 | private void Convert(XDocument document) | ||
| 382 | { | ||
| 394 | // Reset the instance info. | 383 | // Reset the instance info. |
| 395 | this.Messages = 0; | 384 | this.ConversionMessages.Clear(); |
| 396 | this.SourceVersion = 0; | 385 | this.SourceVersion = 0; |
| 397 | this.Operation = ConvertOperation.Format; | 386 | this.Operation = ConvertOperation.Convert; |
| 398 | 387 | ||
| 399 | // Remove the declaration. | 388 | // Remove the declaration. |
| 400 | if (null != document.Declaration | 389 | if (null != document.Declaration |
| 401 | && this.OnInformation(ConverterTestType.DeclarationPresent, null, "This file contains an XML declaration on the first line.")) | 390 | && this.OnInformation(ConverterTestType.DeclarationPresent, document, "This file contains an XML declaration on the first line.")) |
| 402 | { | 391 | { |
| 403 | document.Declaration = null; | 392 | document.Declaration = null; |
| 404 | TrimLeadingText(document); | 393 | TrimLeadingText(document); |
| 405 | } | 394 | } |
| 406 | 395 | ||
| 396 | this.XRoot = document.Root; | ||
| 397 | |||
| 407 | // Start converting the nodes at the top. | 398 | // Start converting the nodes at the top. |
| 408 | this.ConvertNodes(document.Nodes(), 0); | 399 | this.ConvertNodes(document.Nodes(), 0); |
| 409 | this.RemoveUnusedNamespaces(document.Root); | 400 | this.RemoveUnusedNamespaces(document.Root); |
| 401 | } | ||
| 402 | |||
| 403 | private void Format(XDocument document) | ||
| 404 | { | ||
| 405 | // Reset the instance info. | ||
| 406 | this.ConversionMessages.Clear(); | ||
| 407 | this.SourceVersion = 0; | ||
| 408 | this.Operation = ConvertOperation.Format; | ||
| 410 | 409 | ||
| 411 | return this.Messages; | 410 | // Remove the declaration. |
| 411 | if (null != document.Declaration | ||
| 412 | && this.OnInformation(ConverterTestType.DeclarationPresent, document, "This file contains an XML declaration on the first line.")) | ||
| 413 | { | ||
| 414 | document.Declaration = null; | ||
| 415 | TrimLeadingText(document); | ||
| 416 | } | ||
| 417 | |||
| 418 | this.XRoot = document.Root; | ||
| 419 | |||
| 420 | // Start converting the nodes at the top. | ||
| 421 | this.ConvertNodes(document.Nodes(), 0); | ||
| 422 | this.RemoveUnusedNamespaces(document.Root); | ||
| 412 | } | 423 | } |
| 413 | 424 | ||
| 414 | private XDocument OpenSourceFile(string sourceFile) | 425 | private bool TryOpenSourceFile(string sourceFile, out XDocument document) |
| 415 | { | 426 | { |
| 416 | this.SourceFile = sourceFile; | 427 | this.SourceFile = sourceFile; |
| 417 | 428 | ||
| 418 | try | 429 | try |
| 419 | { | 430 | { |
| 420 | return XDocument.Load(this.SourceFile, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | 431 | document = XDocument.Load(this.SourceFile, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); |
| 421 | } | 432 | } |
| 422 | catch (XmlException e) | 433 | catch (XmlException e) |
| 423 | { | 434 | { |
| 424 | this.OnError(ConverterTestType.XmlException, null, "The xml is invalid. Detail: '{0}'", e.Message); | 435 | this.OnError(ConverterTestType.XmlException, null, "The xml is invalid. Detail: '{0}'", e.Message); |
| 436 | document = null; | ||
| 425 | } | 437 | } |
| 426 | 438 | ||
| 427 | return null; | 439 | return document != null; |
| 428 | } | 440 | } |
| 429 | 441 | ||
| 430 | private void SaveDocument(XDocument document) | 442 | private bool SaveDocument(XDocument document) |
| 431 | { | 443 | { |
| 432 | var ignoreDeclarationError = this.IgnoreErrors.Contains(ConverterTestType.DeclarationPresent); | 444 | var ignoreDeclarationError = this.IgnoreErrors.Contains(ConverterTestType.DeclarationPresent); |
| 433 | 445 | ||
| @@ -437,11 +449,15 @@ namespace WixToolset.Converters | |||
| 437 | { | 449 | { |
| 438 | document.Save(writer); | 450 | document.Save(writer); |
| 439 | } | 451 | } |
| 452 | |||
| 453 | return true; | ||
| 440 | } | 454 | } |
| 441 | catch (UnauthorizedAccessException) | 455 | catch (UnauthorizedAccessException) |
| 442 | { | 456 | { |
| 443 | this.OnError(ConverterTestType.UnauthorizedAccessException, null, "Could not write to file."); | 457 | this.OnError(ConverterTestType.UnauthorizedAccessException, null, "Could not write to file."); |
| 444 | } | 458 | } |
| 459 | |||
| 460 | return false; | ||
| 445 | } | 461 | } |
| 446 | 462 | ||
| 447 | private void ConvertNodes(IEnumerable<XNode> nodes, int level) | 463 | private void ConvertNodes(IEnumerable<XNode> nodes, int level) |
| @@ -2129,6 +2145,14 @@ namespace WixToolset.Converters | |||
| 2129 | convertedAttribute = new XAttribute(ns.GetName(attribute.Name.LocalName), attribute.Value); | 2145 | convertedAttribute = new XAttribute(ns.GetName(attribute.Name.LocalName), attribute.Value); |
| 2130 | } | 2146 | } |
| 2131 | 2147 | ||
| 2148 | if (convertedAttribute != attribute) | ||
| 2149 | { | ||
| 2150 | foreach (var message in attribute.Annotations<Message>()) | ||
| 2151 | { | ||
| 2152 | convertedAttribute.AddAnnotation(message); | ||
| 2153 | } | ||
| 2154 | } | ||
| 2155 | |||
| 2132 | element.Add(convertedAttribute); | 2156 | element.Add(convertedAttribute); |
| 2133 | } | 2157 | } |
| 2134 | } | 2158 | } |
| @@ -2214,6 +2238,110 @@ namespace WixToolset.Converters | |||
| 2214 | } | 2238 | } |
| 2215 | } | 2239 | } |
| 2216 | 2240 | ||
| 2241 | private int ReportMessages(XDocument document, bool saved) | ||
| 2242 | { | ||
| 2243 | var conversionCount = this.ConversionMessages.Count; | ||
| 2244 | |||
| 2245 | // If the converted/formatted document was saved, update the source line numbers | ||
| 2246 | // in the messages since they will possibly be wrong. | ||
| 2247 | if (saved && conversionCount > 0) | ||
| 2248 | { | ||
| 2249 | var fixedupMessages = new HashSet<Message>(); | ||
| 2250 | |||
| 2251 | // Load the converted document so we can look up new line numbers for | ||
| 2252 | // messages. | ||
| 2253 | var convertedDocument = XDocument.Load(this.SourceFile, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 2254 | var convertedNavigator = convertedDocument.CreateNavigator(); | ||
| 2255 | |||
| 2256 | // Look through all nodes in the document and try to fix up their line numbers. | ||
| 2257 | foreach (var elements in document.Descendants()) | ||
| 2258 | { | ||
| 2259 | var fixedup = this.FixupMessageLineNumbers(elements, convertedNavigator); | ||
| 2260 | fixedupMessages.AddRange(fixedup); | ||
| 2261 | |||
| 2262 | // Attributes are not considered nodes so they must be enumerated independently. | ||
| 2263 | if (elements is XElement element) | ||
| 2264 | { | ||
| 2265 | foreach (var attribute in element.Attributes()) | ||
| 2266 | { | ||
| 2267 | fixedup = this.FixupMessageLineNumbers(attribute, convertedNavigator); | ||
| 2268 | fixedupMessages.AddRange(fixedup); | ||
| 2269 | } | ||
| 2270 | } | ||
| 2271 | } | ||
| 2272 | |||
| 2273 | // For any messages that couldn't be fixed up, remove their line numbers since they point at lines | ||
| 2274 | // that are possibly wrong after the conversion. | ||
| 2275 | for (var i = 0; i < this.ConversionMessages.Count; ++i) | ||
| 2276 | { | ||
| 2277 | var message = this.ConversionMessages[i]; | ||
| 2278 | |||
| 2279 | if (!fixedupMessages.Contains(message)) | ||
| 2280 | { | ||
| 2281 | this.ConversionMessages[i] = new Message(new SourceLineNumber(this.SourceFile), message.Level, message.Id, message.ResourceNameOrFormat, message.MessageArgs); | ||
| 2282 | } | ||
| 2283 | } | ||
| 2284 | } | ||
| 2285 | |||
| 2286 | foreach (var message in this.ConversionMessages) | ||
| 2287 | { | ||
| 2288 | this.Messaging.Write(message); | ||
| 2289 | } | ||
| 2290 | |||
| 2291 | return conversionCount; | ||
| 2292 | } | ||
| 2293 | |||
| 2294 | private IReadOnlyCollection<Message> FixupMessageLineNumbers(XObject obj, XPathNavigator savedDocument) | ||
| 2295 | { | ||
| 2296 | var messages = obj.Annotations<Message>().ToList(); | ||
| 2297 | |||
| 2298 | if (messages.Count == 0) | ||
| 2299 | { | ||
| 2300 | return Array.Empty<Message>(); | ||
| 2301 | } | ||
| 2302 | |||
| 2303 | // We can't fix up line numbers based on attributes but we can fix up using their parent element, so do so. | ||
| 2304 | if (obj is XAttribute attribute) | ||
| 2305 | { | ||
| 2306 | obj = attribute.Parent; | ||
| 2307 | } | ||
| 2308 | |||
| 2309 | var fixedupMessages = new List<Message>(); | ||
| 2310 | |||
| 2311 | var modifiedLineNumber = this.GetModifiedNodeLineNumber((XElement)obj, savedDocument); | ||
| 2312 | |||
| 2313 | foreach (var message in messages) | ||
| 2314 | { | ||
| 2315 | var fixedupMessage = message; | ||
| 2316 | |||
| 2317 | // If the line number wasn't modified, the existing message's source line nuber is correct | ||
| 2318 | // so skip creating a new one. | ||
| 2319 | if (modifiedLineNumber != null) | ||
| 2320 | { | ||
| 2321 | var index = this.ConversionMessages.IndexOf(message); | ||
| 2322 | |||
| 2323 | fixedupMessage = new Message(modifiedLineNumber, message.Level, message.Id, message.ResourceNameOrFormat, message.MessageArgs); | ||
| 2324 | |||
| 2325 | this.ConversionMessages[index] = fixedupMessage; | ||
| 2326 | } | ||
| 2327 | |||
| 2328 | fixedupMessages.Add(fixedupMessage); | ||
| 2329 | } | ||
| 2330 | |||
| 2331 | return fixedupMessages; | ||
| 2332 | } | ||
| 2333 | |||
| 2334 | private SourceLineNumber GetModifiedNodeLineNumber(XElement element, XPathNavigator savedDocument) | ||
| 2335 | { | ||
| 2336 | var xpathToOld = CalculateXPath(element); | ||
| 2337 | |||
| 2338 | var newNode = savedDocument.SelectSingleNode(xpathToOld); | ||
| 2339 | var newLineNumber = (newNode as IXmlLineInfo).LineNumber; | ||
| 2340 | |||
| 2341 | var oldLineNumber = (element as IXmlLineInfo)?.LineNumber; | ||
| 2342 | return (oldLineNumber != newLineNumber) ? new SourceLineNumber(this.SourceFile, newLineNumber) : null; | ||
| 2343 | } | ||
| 2344 | |||
| 2217 | /// <summary> | 2345 | /// <summary> |
| 2218 | /// Output an error message to the console. | 2346 | /// Output an error message to the console. |
| 2219 | /// </summary> | 2347 | /// </summary> |
| @@ -2250,10 +2378,8 @@ namespace WixToolset.Converters | |||
| 2250 | return false; | 2378 | return false; |
| 2251 | } | 2379 | } |
| 2252 | 2380 | ||
| 2253 | // Increase the message count. | 2381 | var sourceLine = SourceLineNumberForXmlLineInfo(this.SourceFile, node); |
| 2254 | this.Messages++; | ||
| 2255 | 2382 | ||
| 2256 | var sourceLine = (null == node) ? new SourceLineNumber(this.SourceFile ?? "wix.exe") : new SourceLineNumber(this.SourceFile, ((IXmlLineInfo)node).LineNumber); | ||
| 2257 | var prefix = String.Empty; | 2383 | var prefix = String.Empty; |
| 2258 | if (level == MessageLevel.Information) | 2384 | if (level == MessageLevel.Information) |
| 2259 | { | 2385 | { |
| @@ -2268,11 +2394,34 @@ namespace WixToolset.Converters | |||
| 2268 | 2394 | ||
| 2269 | var msg = new Message(sourceLine, level, (int)converterTestType, format, args); | 2395 | var msg = new Message(sourceLine, level, (int)converterTestType, format, args); |
| 2270 | 2396 | ||
| 2271 | this.Messaging.Write(msg); | 2397 | // Add the message as a node annotation so it could be possible to remap source line numbers |
| 2398 | // to their new locations after converting/formatting (since lines of code could be moved). | ||
| 2399 | node?.AddAnnotation(msg); | ||
| 2400 | this.ConversionMessages.Add(msg); | ||
| 2272 | 2401 | ||
| 2273 | return true; | 2402 | return true; |
| 2274 | } | 2403 | } |
| 2275 | 2404 | ||
| 2405 | private static string CalculateXPath(XElement element) | ||
| 2406 | { | ||
| 2407 | var builder = new StringBuilder(); | ||
| 2408 | |||
| 2409 | while (element != null) | ||
| 2410 | { | ||
| 2411 | var index = element.Parent?.Elements().TakeWhile(e => e != element).Count() ?? 0; | ||
| 2412 | builder.Insert(0, $"/*[{index + 1}]"); | ||
| 2413 | |||
| 2414 | element = element.Parent; | ||
| 2415 | } | ||
| 2416 | |||
| 2417 | return builder.ToString(); | ||
| 2418 | } | ||
| 2419 | |||
| 2420 | private static SourceLineNumber SourceLineNumberForXmlLineInfo(string sourceFile, IXmlLineInfo lineInfo) | ||
| 2421 | { | ||
| 2422 | return (lineInfo?.HasLineInfo() == true) ? new SourceLineNumber(sourceFile, lineInfo.LineNumber) : new SourceLineNumber(sourceFile ?? "wix.exe"); | ||
| 2423 | } | ||
| 2424 | |||
| 2276 | /// <summary> | 2425 | /// <summary> |
| 2277 | /// Return an identifier based on passed file/directory name | 2426 | /// Return an identifier based on passed file/directory name |
| 2278 | /// </summary> | 2427 | /// </summary> |
| @@ -2338,7 +2487,7 @@ namespace WixToolset.Converters | |||
| 2338 | comments = initialComments; | 2487 | comments = initialComments; |
| 2339 | var nonCommentNodes = new List<XNode>(); | 2488 | var nonCommentNodes = new List<XNode>(); |
| 2340 | 2489 | ||
| 2341 | foreach(var node in nodes) | 2490 | foreach (var node in nodes) |
| 2342 | { | 2491 | { |
| 2343 | if (XmlNodeType.Comment == node.NodeType) | 2492 | if (XmlNodeType.Comment == node.NodeType) |
| 2344 | { | 2493 | { |
diff --git a/src/wix/test/WixToolsetTest.Converters/ConverterFixture.cs b/src/wix/test/WixToolsetTest.Converters/ConverterFixture.cs index d186931b..cd6849d3 100644 --- a/src/wix/test/WixToolsetTest.Converters/ConverterFixture.cs +++ b/src/wix/test/WixToolsetTest.Converters/ConverterFixture.cs | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | namespace WixToolsetTest.Converters | 3 | namespace WixToolsetTest.Converters |
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using System.IO; | ||
| 7 | using System.Linq; | ||
| 6 | using System.Xml.Linq; | 8 | using System.Xml.Linq; |
| 7 | using WixBuildTools.TestSupport; | 9 | using WixBuildTools.TestSupport; |
| 8 | using WixToolset.Converters; | 10 | using WixToolset.Converters; |
| @@ -62,7 +64,7 @@ namespace WixToolsetTest.Converters | |||
| 62 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | 64 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); |
| 63 | 65 | ||
| 64 | var messaging = new MockMessaging(); | 66 | var messaging = new MockMessaging(); |
| 65 | var converter = new WixConverter(messaging, 2, ignoreErrors: new[] { "DeclarationPresent" } ); | 67 | var converter = new WixConverter(messaging, 2, ignoreErrors: new[] { "DeclarationPresent" }); |
| 66 | 68 | ||
| 67 | var errors = converter.ConvertDocument(document); | 69 | var errors = converter.ConvertDocument(document); |
| 68 | 70 | ||
| @@ -103,6 +105,40 @@ namespace WixToolsetTest.Converters | |||
| 103 | } | 105 | } |
| 104 | 106 | ||
| 105 | [Fact] | 107 | [Fact] |
| 108 | public void CanConvertMainNamespaceFromDisk() | ||
| 109 | { | ||
| 110 | var dataFolder = TestData.Get("TestData", "FixDeclarationAndNamespace"); | ||
| 111 | |||
| 112 | var expected = new[] | ||
| 113 | { | ||
| 114 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 115 | " <Fragment />", | ||
| 116 | "</Wix>", | ||
| 117 | }; | ||
| 118 | |||
| 119 | using (var fs = new TestDataFolderFileSystem()) | ||
| 120 | { | ||
| 121 | fs.Initialize(dataFolder); | ||
| 122 | var path = Path.Combine(fs.BaseFolder, "FixDeclarationAndNamespace.wxs"); | ||
| 123 | |||
| 124 | var messaging = new MockMessaging(); | ||
| 125 | var converter = new WixConverter(messaging, 2, null, null); | ||
| 126 | |||
| 127 | var errors = converter.ConvertFile(path, true); | ||
| 128 | |||
| 129 | var messages = messaging.Messages.Select(m => $"{Path.GetFileName(m.SourceLineNumbers.FileName)}({m.SourceLineNumbers.LineNumber}) {m.ToString()}").ToArray(); | ||
| 130 | WixAssert.CompareLineByLine(new[] | ||
| 131 | { | ||
| 132 | "FixDeclarationAndNamespace.wxs() [Converted] This file contains an XML declaration on the first line. (DeclarationPresent)", | ||
| 133 | "FixDeclarationAndNamespace.wxs(1) [Converted] The namespace 'http://schemas.microsoft.com/wix/2006/wi' is out of date. It must be 'http://wixtoolset.org/schemas/v4/wxs'. (XmlnsValueWrong)" | ||
| 134 | }, messages); | ||
| 135 | |||
| 136 | var actual = File.ReadAllLines(path); | ||
| 137 | WixAssert.CompareLineByLine(expected, actual); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | [Fact] | ||
| 106 | public void CanConvertNamedMainNamespace() | 142 | public void CanConvertNamedMainNamespace() |
| 107 | { | 143 | { |
| 108 | var parse = String.Join(Environment.NewLine, | 144 | var parse = String.Join(Environment.NewLine, |
diff --git a/src/wix/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs b/src/wix/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs index a8908df7..fdebc6b0 100644 --- a/src/wix/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs +++ b/src/wix/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs | |||
| @@ -85,9 +85,14 @@ namespace WixToolsetTest.Converters | |||
| 85 | 85 | ||
| 86 | var messaging = new MockMessaging(); | 86 | var messaging = new MockMessaging(); |
| 87 | var converter = new WixConverter(messaging, 4); | 87 | var converter = new WixConverter(messaging, 4); |
| 88 | var errors = converter.ConvertFile(targetFile, true); | 88 | var convertedCount = converter.ConvertFile(targetFile, true); |
| 89 | 89 | ||
| 90 | Assert.Single(messaging.Messages.Where(m => m.Id == 5/*WixConverter.ConverterTestType.UnauthorizedAccessException*/)); | 90 | var errors = messaging.Messages.Where(m => m.Level == WixToolset.Data.MessageLevel.Error).Select(m => m.ToString()).ToArray(); |
| 91 | WixAssert.CompareLineByLine(new[] | ||
| 92 | { | ||
| 93 | "Could not write to file. (UnauthorizedAccessException)" | ||
| 94 | }, errors); | ||
| 95 | Assert.Equal(10, convertedCount); | ||
| 91 | } | 96 | } |
| 92 | } | 97 | } |
| 93 | 98 | ||
diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/FixDeclarationAndNamespace/FixDeclarationAndNamespace.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/FixDeclarationAndNamespace/FixDeclarationAndNamespace.wxs new file mode 100644 index 00000000..a8923337 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/FixDeclarationAndNamespace/FixDeclarationAndNamespace.wxs | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | <?xml version='1.0' encoding='utf-8'?> | ||
| 2 | <Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'> | ||
| 3 | <Fragment /> | ||
| 4 | </Wix> | ||
