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