diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2022-05-13 11:40:45 -0500 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2022-05-13 12:35:15 -0500 |
| commit | 031991f32f059b64374e6d257cbe573304dd577f (patch) | |
| tree | 9d11ebb5d8595bf45c507f38d637b14915af7630 /src/internal/WixBuildTools.TestSupport/XunitExtensions | |
| parent | ad6d2636f60b04ee68656f99fb3bd56a86ba5983 (diff) | |
| download | wix-031991f32f059b64374e6d257cbe573304dd577f.tar.gz wix-031991f32f059b64374e6d257cbe573304dd577f.tar.bz2 wix-031991f32f059b64374e6d257cbe573304dd577f.zip | |
Add ability to skip tests at runtime, and skip long running cache tests
6665
Diffstat (limited to 'src/internal/WixBuildTools.TestSupport/XunitExtensions')
10 files changed, 397 insertions, 0 deletions
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkipTestException.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkipTestException.cs new file mode 100644 index 00000000..bd7d23f9 --- /dev/null +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkipTestException.cs | |||
| @@ -0,0 +1,15 @@ | |||
| 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 WixBuildTools.TestSupport.XunitExtensions | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | |||
| 7 | public class SkipTestException : Exception | ||
| 8 | { | ||
| 9 | public SkipTestException(string reason) | ||
| 10 | : base(reason) | ||
| 11 | { | ||
| 12 | |||
| 13 | } | ||
| 14 | } | ||
| 15 | } | ||
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactAttribute.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactAttribute.cs new file mode 100644 index 00000000..4974d489 --- /dev/null +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactAttribute.cs | |||
| @@ -0,0 +1,13 @@ | |||
| 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 WixBuildTools.TestSupport.XunitExtensions | ||
| 4 | { | ||
| 5 | using Xunit; | ||
| 6 | using Xunit.Sdk; | ||
| 7 | |||
| 8 | // https://github.com/xunit/samples.xunit/blob/5dc1d35a63c3394a8678ac466b882576a70f56f6/DynamicSkipExample | ||
| 9 | [XunitTestCaseDiscoverer("WixBuildTools.TestSupport.XunitExtensions.SkippableFactDiscoverer", "WixBuildTools.TestSupport")] | ||
| 10 | public class SkippableFactAttribute : FactAttribute | ||
| 11 | { | ||
| 12 | } | ||
| 13 | } | ||
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactDiscoverer.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactDiscoverer.cs new file mode 100644 index 00000000..b692c912 --- /dev/null +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactDiscoverer.cs | |||
| @@ -0,0 +1,23 @@ | |||
| 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 WixBuildTools.TestSupport.XunitExtensions | ||
| 4 | { | ||
| 5 | using System.Collections.Generic; | ||
| 6 | using Xunit.Abstractions; | ||
| 7 | using Xunit.Sdk; | ||
| 8 | |||
| 9 | public class SkippableFactDiscoverer : IXunitTestCaseDiscoverer | ||
| 10 | { | ||
| 11 | private IMessageSink DiagnosticMessageSink { get; } | ||
| 12 | |||
| 13 | public SkippableFactDiscoverer(IMessageSink diagnosticMessageSink) | ||
| 14 | { | ||
| 15 | this.DiagnosticMessageSink = diagnosticMessageSink; | ||
| 16 | } | ||
| 17 | |||
| 18 | public IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) | ||
| 19 | { | ||
| 20 | yield return new SkippableFactTestCase(this.DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod); | ||
| 21 | } | ||
| 22 | } | ||
| 23 | } | ||
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactMessageBus.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactMessageBus.cs new file mode 100644 index 00000000..6d01889e --- /dev/null +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactMessageBus.cs | |||
| @@ -0,0 +1,40 @@ | |||
| 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 WixBuildTools.TestSupport.XunitExtensions | ||
| 4 | { | ||
| 5 | using System.Linq; | ||
| 6 | using Xunit.Abstractions; | ||
| 7 | using Xunit.Sdk; | ||
| 8 | |||
| 9 | public class SkippableFactMessageBus : IMessageBus | ||
| 10 | { | ||
| 11 | private IMessageBus InnerBus { get; } | ||
| 12 | |||
| 13 | public SkippableFactMessageBus(IMessageBus innerBus) | ||
| 14 | { | ||
| 15 | this.InnerBus = innerBus; | ||
| 16 | } | ||
| 17 | |||
| 18 | public int DynamicallySkippedTestCount { get; private set; } | ||
| 19 | |||
| 20 | public void Dispose() | ||
| 21 | { | ||
| 22 | } | ||
| 23 | |||
| 24 | public bool QueueMessage(IMessageSinkMessage message) | ||
| 25 | { | ||
| 26 | if (message is ITestFailed testFailed) | ||
| 27 | { | ||
| 28 | var exceptionType = testFailed.ExceptionTypes.FirstOrDefault(); | ||
| 29 | if (exceptionType == typeof(SkipTestException).FullName) | ||
| 30 | { | ||
| 31 | ++this.DynamicallySkippedTestCount; | ||
| 32 | return this.InnerBus.QueueMessage(new TestSkipped(testFailed.Test, testFailed.Messages.FirstOrDefault())); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | // Nothing we care about, send it on its way | ||
| 37 | return this.InnerBus.QueueMessage(message); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactTestCase.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactTestCase.cs new file mode 100644 index 00000000..f13fec83 --- /dev/null +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableFactTestCase.cs | |||
| @@ -0,0 +1,40 @@ | |||
| 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 WixBuildTools.TestSupport.XunitExtensions | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.ComponentModel; | ||
| 7 | using System.Threading; | ||
| 8 | using System.Threading.Tasks; | ||
| 9 | using Xunit.Abstractions; | ||
| 10 | using Xunit.Sdk; | ||
| 11 | |||
| 12 | public class SkippableFactTestCase : XunitTestCase | ||
| 13 | { | ||
| 14 | [EditorBrowsable(EditorBrowsableState.Never)] | ||
| 15 | [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] | ||
| 16 | public SkippableFactTestCase() { } | ||
| 17 | |||
| 18 | public SkippableFactTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, object[] testMethodArguments = null) | ||
| 19 | : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) | ||
| 20 | { | ||
| 21 | } | ||
| 22 | |||
| 23 | public override async Task<RunSummary> RunAsync(IMessageSink diagnosticMessageSink, | ||
| 24 | IMessageBus messageBus, | ||
| 25 | object[] constructorArguments, | ||
| 26 | ExceptionAggregator aggregator, | ||
| 27 | CancellationTokenSource cancellationTokenSource) | ||
| 28 | { | ||
| 29 | var skipMessageBus = new SkippableFactMessageBus(messageBus); | ||
| 30 | var result = await base.RunAsync(diagnosticMessageSink, skipMessageBus, constructorArguments, aggregator, cancellationTokenSource); | ||
| 31 | if (skipMessageBus.DynamicallySkippedTestCount > 0) | ||
| 32 | { | ||
| 33 | result.Failed -= skipMessageBus.DynamicallySkippedTestCount; | ||
| 34 | result.Skipped += skipMessageBus.DynamicallySkippedTestCount; | ||
| 35 | } | ||
| 36 | |||
| 37 | return result; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableTheoryAttribute.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableTheoryAttribute.cs new file mode 100644 index 00000000..e026bb59 --- /dev/null +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableTheoryAttribute.cs | |||
| @@ -0,0 +1,12 @@ | |||
| 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 WixBuildTools.TestSupport.XunitExtensions | ||
| 4 | { | ||
| 5 | using Xunit; | ||
| 6 | using Xunit.Sdk; | ||
| 7 | |||
| 8 | [XunitTestCaseDiscoverer("WixBuildTools.TestSupport.XunitExtensions.SkippableFactDiscoverer", "WixBuildTools.TestSupport")] | ||
| 9 | public class SkippableTheoryAttribute : TheoryAttribute | ||
| 10 | { | ||
| 11 | } | ||
| 12 | } | ||
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableTheoryDiscoverer.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableTheoryDiscoverer.cs new file mode 100644 index 00000000..cf4e2b43 --- /dev/null +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableTheoryDiscoverer.cs | |||
| @@ -0,0 +1,41 @@ | |||
| 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 WixBuildTools.TestSupport.XunitExtensions | ||
| 4 | { | ||
| 5 | using System.Collections.Generic; | ||
| 6 | using Xunit.Abstractions; | ||
| 7 | using Xunit.Sdk; | ||
| 8 | |||
| 9 | public class SkippableTheoryDiscoverer : IXunitTestCaseDiscoverer | ||
| 10 | { | ||
| 11 | private IMessageSink DiagnosticMessageSink { get; } | ||
| 12 | private TheoryDiscoverer TheoryDiscoverer { get; } | ||
| 13 | |||
| 14 | public SkippableTheoryDiscoverer(IMessageSink diagnosticMessageSink) | ||
| 15 | { | ||
| 16 | this.DiagnosticMessageSink = diagnosticMessageSink; | ||
| 17 | |||
| 18 | this.TheoryDiscoverer = new TheoryDiscoverer(diagnosticMessageSink); | ||
| 19 | } | ||
| 20 | |||
| 21 | public IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) | ||
| 22 | { | ||
| 23 | var defaultMethodDisplay = discoveryOptions.MethodDisplayOrDefault(); | ||
| 24 | var defaultMethodDisplayOptions = discoveryOptions.MethodDisplayOptionsOrDefault(); | ||
| 25 | |||
| 26 | // Unlike fact discovery, the underlying algorithm for theories is complex, so we let the theory discoverer | ||
| 27 | // do its work, and do a little on-the-fly conversion into our own test cases. | ||
| 28 | foreach (var testCase in this.TheoryDiscoverer.Discover(discoveryOptions, testMethod, factAttribute)) | ||
| 29 | { | ||
| 30 | if (testCase is XunitTheoryTestCase) | ||
| 31 | { | ||
| 32 | yield return new SkippableTheoryTestCase(this.DiagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testCase.TestMethod); | ||
| 33 | } | ||
| 34 | else | ||
| 35 | { | ||
| 36 | yield return new SkippableFactTestCase(this.DiagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testCase.TestMethod, testCase.TestMethodArguments); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | ||
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableTheoryTestCase.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableTheoryTestCase.cs new file mode 100644 index 00000000..3299fe7e --- /dev/null +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SkippableTheoryTestCase.cs | |||
| @@ -0,0 +1,41 @@ | |||
| 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 WixBuildTools.TestSupport.XunitExtensions | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.ComponentModel; | ||
| 7 | using System.Threading; | ||
| 8 | using System.Threading.Tasks; | ||
| 9 | using Xunit.Abstractions; | ||
| 10 | using Xunit.Sdk; | ||
| 11 | |||
| 12 | public class SkippableTheoryTestCase : XunitTheoryTestCase | ||
| 13 | { | ||
| 14 | [EditorBrowsable(EditorBrowsableState.Never)] | ||
| 15 | [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] | ||
| 16 | public SkippableTheoryTestCase() { } | ||
| 17 | |||
| 18 | public SkippableTheoryTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod) | ||
| 19 | : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod) | ||
| 20 | { | ||
| 21 | } | ||
| 22 | |||
| 23 | public override async Task<RunSummary> RunAsync(IMessageSink diagnosticMessageSink, | ||
| 24 | IMessageBus messageBus, | ||
| 25 | object[] constructorArguments, | ||
| 26 | ExceptionAggregator aggregator, | ||
| 27 | CancellationTokenSource cancellationTokenSource) | ||
| 28 | { | ||
| 29 | // Duplicated code from SkippableFactTestCase. I'm sure we could find a way to de-dup with some thought. | ||
| 30 | var skipMessageBus = new SkippableFactMessageBus(messageBus); | ||
| 31 | var result = await base.RunAsync(diagnosticMessageSink, skipMessageBus, constructorArguments, aggregator, cancellationTokenSource); | ||
| 32 | if (skipMessageBus.DynamicallySkippedTestCount > 0) | ||
| 33 | { | ||
| 34 | result.Failed -= skipMessageBus.DynamicallySkippedTestCount; | ||
| 35 | result.Skipped += skipMessageBus.DynamicallySkippedTestCount; | ||
| 36 | } | ||
| 37 | |||
| 38 | return result; | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | ||
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SucceededException.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SucceededException.cs new file mode 100644 index 00000000..704fba28 --- /dev/null +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SucceededException.cs | |||
| @@ -0,0 +1,19 @@ | |||
| 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 WixBuildTools.TestSupport | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using Xunit.Sdk; | ||
| 7 | |||
| 8 | public class SucceededException : XunitException | ||
| 9 | { | ||
| 10 | public SucceededException(int hr, string userMessage) | ||
| 11 | : base(String.Format("WixAssert.Succeeded() Failure\r\n" + | ||
| 12 | "HRESULT: 0x{0:X8}\r\n" + | ||
| 13 | "Message: {1}", | ||
| 14 | hr, userMessage)) | ||
| 15 | { | ||
| 16 | this.HResult = hr; | ||
| 17 | } | ||
| 18 | } | ||
| 19 | } | ||
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 | |||
| 3 | namespace 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 | } | ||
