Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid a direct xunit dependency due to binary compatibility concerns #1145

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@
<PackageTags>Roslyn Test Verifiers for xUnit</PackageTags>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="xunit.assert" Version="2.3.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.CodeAnalysis.Analyzer.Testing\Microsoft.CodeAnalysis.Analyzer.Testing.csproj" />
</ItemGroup>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
Microsoft.CodeAnalysis.Testing.Verifiers.EmptyWithMessageException
Microsoft.CodeAnalysis.Testing.Verifiers.EmptyWithMessageException.EmptyWithMessageException(System.Collections.IEnumerable collection, string userMessage) -> void
Microsoft.CodeAnalysis.Testing.Verifiers.EqualWithMessageException
Microsoft.CodeAnalysis.Testing.Verifiers.EqualWithMessageException.EqualWithMessageException(object expected, object actual, string userMessage) -> void
Microsoft.CodeAnalysis.Testing.Verifiers.EqualWithMessageException.EqualWithMessageException(string expected, string actual, int expectedIndex, int actualIndex, string userMessage) -> void
Microsoft.CodeAnalysis.Testing.Verifiers.NotEmptyWithMessageException
Microsoft.CodeAnalysis.Testing.Verifiers.NotEmptyWithMessageException.NotEmptyWithMessageException(string userMessage) -> void
Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier
Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier.Context.get -> System.Collections.Immutable.ImmutableStack<string>
Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier.XUnitVerifier() -> void
Expand All @@ -19,6 +12,3 @@ virtual Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier.NotEmpty<T>(strin
virtual Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier.PushContext(string context) -> Microsoft.CodeAnalysis.Testing.IVerifier
virtual Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier.SequenceEqual<T>(System.Collections.Generic.IEnumerable<T> expected, System.Collections.Generic.IEnumerable<T> actual, System.Collections.Generic.IEqualityComparer<T> equalityComparer = null, string message = null) -> void
virtual Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier.True(bool assert, string message = null) -> void
override Microsoft.CodeAnalysis.Testing.Verifiers.EmptyWithMessageException.Message.get -> string
override Microsoft.CodeAnalysis.Testing.Verifiers.EqualWithMessageException.Message.get -> string
override Microsoft.CodeAnalysis.Testing.Verifiers.NotEmptyWithMessageException.Message.get -> string
Original file line number Diff line number Diff line change
Expand Up @@ -7,119 +7,73 @@
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Xunit;

namespace Microsoft.CodeAnalysis.Testing.Verifiers
{
public class XUnitVerifier : IVerifier
{
private readonly DefaultVerifier _defaultVerifer;

public XUnitVerifier()
: this(ImmutableStack<string>.Empty)
: this(ImmutableStack<string>.Empty, new DefaultVerifier())
{
}

protected XUnitVerifier(ImmutableStack<string> context)
{
Context = context ?? throw new ArgumentNullException(nameof(context));
}

protected ImmutableStack<string> Context { get; }

public virtual void Empty<T>(string collectionName, IEnumerable<T> collection)
{
using (var enumerator = collection.GetEnumerator())
// Construct an equivalent DefaultVerifier from the provided context
var defaultVerifier = new DefaultVerifier();
foreach (var frame in context.Reverse())
{
if (enumerator.MoveNext())
{
throw new EmptyWithMessageException(collection, CreateMessage($"'{collectionName}' is not empty"));
}
defaultVerifier = (DefaultVerifier)defaultVerifier.PushContext(frame);
}

_defaultVerifer = defaultVerifier;
}

public virtual void Equal<T>(T expected, T actual, string? message = null)
private XUnitVerifier(ImmutableStack<string> context, DefaultVerifier defaultVerifier)
{
if (message is null && Context.IsEmpty)
{
Assert.Equal(expected, actual);
}
else
{
if (!EqualityComparer<T>.Default.Equals(expected, actual))
{
throw new EqualWithMessageException(expected, actual, CreateMessage(message));
}
}
Context = context;
_defaultVerifer = defaultVerifier;
}

protected ImmutableStack<string> Context { get; }

public virtual void Empty<T>(string collectionName, IEnumerable<T> collection)
=> _defaultVerifer.Empty(collectionName, collection);

public virtual void Equal<T>(T expected, T actual, string? message = null)
=> _defaultVerifer.Equal(expected, actual, message);

public virtual void True([DoesNotReturnIf(false)] bool assert, string? message = null)
{
if (message is null && Context.IsEmpty)
{
Assert.True(assert);
}
else
{
Assert.True(assert, CreateMessage(message));
}
}
=> _defaultVerifer.True(assert, message);

public virtual void False([DoesNotReturnIf(true)] bool assert, string? message = null)
{
if (message is null && Context.IsEmpty)
{
Assert.False(assert);
}
else
{
Assert.False(assert, CreateMessage(message));
}
}
=> _defaultVerifer.False(assert, message);

[DoesNotReturn]
public virtual void Fail(string? message = null)
{
if (message is null && Context.IsEmpty)
{
Assert.True(false);
}
else
{
Assert.True(false, CreateMessage(message));
}

throw ExceptionUtilities.Unreachable;
}
=> _defaultVerifer.Fail(message);

public virtual void LanguageIsSupported(string language)
{
Assert.False(language != LanguageNames.CSharp && language != LanguageNames.VisualBasic, CreateMessage($"Unsupported Language: '{language}'"));
}
=> _defaultVerifer.LanguageIsSupported(language);

public virtual void NotEmpty<T>(string collectionName, IEnumerable<T> collection)
{
using (var enumerator = collection.GetEnumerator())
{
if (!enumerator.MoveNext())
{
throw new NotEmptyWithMessageException(CreateMessage($"'{collectionName}' is empty"));
}
}
}
=> _defaultVerifer.NotEmpty(collectionName, collection);

public virtual void SequenceEqual<T>(IEnumerable<T> expected, IEnumerable<T> actual, IEqualityComparer<T>? equalityComparer = null, string? message = null)
=> _defaultVerifer.SequenceEqual(expected, actual, equalityComparer, message);

public virtual IVerifier PushContext(string context)
{
var comparer = new SequenceEqualEnumerableEqualityComparer<T>(equalityComparer);
var areEqual = comparer.Equals(expected, actual);
if (!areEqual)
if (GetType() != typeof(XUnitVerifier))
{
throw new EqualWithMessageException(expected, actual, CreateMessage(message));
throw new InvalidOperationException($"'{nameof(PushContext)}' must be overridden to support types derived from '{typeof(XUnitVerifier)}'");
}
}

public virtual IVerifier PushContext(string context)
{
Assert.IsType<XUnitVerifier>(this);
return new XUnitVerifier(Context.Push(context));
return new XUnitVerifier(Context.Push(context), (DefaultVerifier)_defaultVerifer.PushContext(context));
}

protected virtual string CreateMessage(string? message)
Expand All @@ -131,41 +85,5 @@ protected virtual string CreateMessage(string? message)

return message ?? string.Empty;
}

private sealed class SequenceEqualEnumerableEqualityComparer<T> : IEqualityComparer<IEnumerable<T>?>
{
private readonly IEqualityComparer<T> _itemEqualityComparer;

public SequenceEqualEnumerableEqualityComparer(IEqualityComparer<T>? itemEqualityComparer)
{
_itemEqualityComparer = itemEqualityComparer ?? EqualityComparer<T>.Default;
}

public bool Equals(IEnumerable<T>? x, IEnumerable<T>? y)
{
if (ReferenceEquals(x, y)) { return true; }
if (x is null || y is null) { return false; }

return x.SequenceEqual(y, _itemEqualityComparer);
}

public int GetHashCode(IEnumerable<T>? obj)
{
if (obj is null)
{
return 0;
}

// From System.Tuple
//
// The suppression is required due to an invalid contract in IEqualityComparer<T>
// https://github.com/dotnet/runtime/issues/30998
return obj
.Select(item => _itemEqualityComparer.GetHashCode(item!))
.Aggregate(
0,
(aggHash, nextHash) => ((aggHash << 5) + aggHash) ^ nextHash);
}
}
}
}
Loading