summaryrefslogtreecommitdiff
path: root/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs')
-rw-r--r--src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs153
1 files changed, 153 insertions, 0 deletions
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs
new file mode 100644
index 00000000..10156547
--- /dev/null
+++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs
@@ -0,0 +1,153 @@
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
3namespace WixBuildTools.TestSupport
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using System.Xml.Linq;
9 using WixBuildTools.TestSupport.XunitExtensions;
10 using Xunit;
11
12 public class WixAssert : Assert
13 {
14 public static void CompareLineByLine(string[] expectedLines, string[] actualLines)
15 {
16 var lineNumber = 0;
17
18 for (; lineNumber < expectedLines.Length && lineNumber < actualLines.Length; ++lineNumber)
19 {
20 WixAssert.StringEqual($"{lineNumber}: {expectedLines[lineNumber]}", $"{lineNumber}: {actualLines[lineNumber]}");
21 }
22
23 var additionalExpectedLines = expectedLines.Length > lineNumber ? String.Join(Environment.NewLine, expectedLines.Skip(lineNumber).Select((s, i) => $"{lineNumber + i}: {s}")) : $"Missing {actualLines.Length - lineNumber} lines";
24 var additionalActualLines = actualLines.Length > lineNumber ? String.Join(Environment.NewLine, actualLines.Skip(lineNumber).Select((s, i) => $"{lineNumber + i}: {s}")) : $"Missing {expectedLines.Length - lineNumber} lines";
25
26 WixAssert.StringEqual(additionalExpectedLines, additionalActualLines);
27 }
28
29 public static void CompareXml(XContainer xExpected, XContainer xActual)
30 {
31 var expecteds = xExpected.Descendants().Select(x => $"{x.Name.LocalName}:{String.Join(",", x.Attributes().OrderBy(a => a.Name.LocalName).Select(a => $"{a.Name.LocalName}={a.Value}"))}");
32 var actuals = xActual.Descendants().Select(x => $"{x.Name.LocalName}:{String.Join(",", x.Attributes().OrderBy(a => a.Name.LocalName).Select(a => $"{a.Name.LocalName}={a.Value}"))}");
33
34 CompareLineByLine(expecteds.OrderBy(s => s).ToArray(), actuals.OrderBy(s => s).ToArray());
35 }
36
37 public static void CompareXml(string expectedPath, string actualPath)
38 {
39 var expectedDoc = XDocument.Load(expectedPath, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
40 var actualDoc = XDocument.Load(actualPath, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
41
42 CompareXml(expectedDoc, actualDoc);
43 }
44
45 /// <summary>
46 /// Dynamically skips the test.
47 /// Requires that the test was marked with a fact attribute derived from <see cref="WixBuildTools.TestSupport.XunitExtensions.SkippableFactAttribute" />
48 /// or <see cref="WixBuildTools.TestSupport.XunitExtensions.SkippableTheoryAttribute" />
49 /// </summary>
50 public static void Skip(string message)
51 {
52 throw new SkipTestException(message);
53 }
54
55 public static void Succeeded(int hr, string format, params object[] formatArgs)
56 {
57 if (0 > hr)
58 {
59 throw new SucceededException(hr, String.Format(format, formatArgs));
60 }
61 }
62
63 public static void StringCollectionEmpty(IList<string> collection)
64 {
65 if (collection.Count > 0)
66 {
67 Assert.True(false, $"The collection was expected to be empty, but instead was [{Environment.NewLine}\"{String.Join($"\", {Environment.NewLine}\"", collection)}\"{Environment.NewLine}]");
68 }
69 }
70
71 public static void StringEqual(string expected, string actual, bool ignoreCase = false)
72 {
73 var comparer = ignoreCase ? StringObjectEqualityComparer.InvariantCultureIgnoreCase : StringObjectEqualityComparer.InvariantCulture;
74 Assert.Equal<object>(expected, actual, comparer);
75 }
76
77 public static void NotStringEqual(string expected, string actual, bool ignoreCase = false)
78 {
79 var comparer = ignoreCase ? StringObjectEqualityComparer.InvariantCultureIgnoreCase : StringObjectEqualityComparer.InvariantCulture;
80 Assert.NotEqual<object>(expected, actual, comparer);
81 }
82
83 private class StringObjectEqualityComparer : IEqualityComparer<object>
84 {
85 public static readonly StringObjectEqualityComparer InvariantCultureIgnoreCase = new StringObjectEqualityComparer(true);
86 public static readonly StringObjectEqualityComparer InvariantCulture = new StringObjectEqualityComparer(false);
87
88 private readonly StringComparer stringComparer;
89
90 public StringObjectEqualityComparer(bool ignoreCase)
91 {
92 this.stringComparer = ignoreCase ? StringComparer.InvariantCultureIgnoreCase : StringComparer.InvariantCulture;
93 }
94
95 public new bool Equals(object x, object y)
96 {
97 return this.stringComparer.Equals((string)x,(string)y);
98 }
99
100 public int GetHashCode(object obj)
101 {
102 return this.stringComparer.GetHashCode((string)obj);
103 }
104 }
105
106 // There appears to have been a bug in VC++, which might or might not have been partially
107 // or completely corrected. It was unable to disambiguate a call to:
108 // Xunit::Assert::Throws(System::Type^, System::Action^)
109 // from a call to:
110 // Xunit::Assert::Throws(System::Type^, System::Func<System::Object^>^)
111 // that implicitly ignores its return value.
112 //
113 // The ambiguity may have been reported by some versions of the compiler and not by others.
114 // Some versions of the compiler may not have emitted any code in this situation, making it
115 // appear that the test has passed when, in fact, it hasn't been run.
116 //
117 // This situation is not an issue for C#.
118 //
119 // The following method is used to isolate DUtilTests in order to overcome the above problem.
120
121 /// <summary>
122 /// This shim allows C++/CLR code to call the Xunit method with the same signature
123 /// without getting an ambiguous overload error. If the specified test code
124 /// fails to generate an exception of the exact specified type, an assertion
125 /// exception is thrown. Otherwise, execution flow proceeds as normal.
126 /// </summary>
127 /// <typeparam name="T">The type name of the expected exception.</typeparam>
128 /// <param name="testCode">An Action delegate to run the test code.</param>
129 public static new void Throws<T>(System.Action testCode)
130 where T : System.Exception
131 {
132 Xunit.Assert.Throws<T>(testCode);
133 }
134
135 // This shim has been tested, but is not currently used anywhere. It was provided
136 // at the same time as the preceding shim because it involved the same overload
137 // resolution conflict.
138
139 /// <summary>
140 /// This shim allows C++/CLR code to call the Xunit method with the same signature
141 /// without getting an ambiguous overload error. If the specified test code
142 /// fails to generate an exception of the exact specified type, an assertion
143 /// exception is thrown. Otherwise, execution flow proceeds as normal.
144 /// </summary>
145 /// <param name="exceptionType">The type object associated with exceptions of the expected type.</param>
146 /// <param name="testCode">An Action delegate to run the test code.</param>
147 /// <returns>An exception of a type other than the type specified, is such an exception is thrown.</returns>
148 public static new System.Exception Throws(System.Type exceptionType, System.Action testCode)
149 {
150 return Xunit.Assert.Throws(exceptionType, testCode);
151 }
152 }
153}