|
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Xunit;
using Xunit.Sdk;
public class EqualityAssertsTests
{
public class Equal
{
public class Intrinsics
{
[Fact]
public void Equal()
{
Assert.Equal(42, 42);
}
[Fact]
public void NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(42, 2112));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: 42" + Environment.NewLine +
"Actual: 2112",
ex.Message
);
}
[Fact]
public void StringsPassViaObjectEqualAreNotFormattedOrTruncated()
{
var ex = Record.Exception(
() => Assert.Equal<object>(
$"This is a long{Environment.NewLine}string with{Environment.NewLine}new lines",
$"This is a long{Environment.NewLine}string with embedded{Environment.NewLine}new lines"
)
);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: This is a long" + Environment.NewLine +
" string with" + Environment.NewLine +
" new lines" + Environment.NewLine +
"Actual: This is a long" + Environment.NewLine +
" string with embedded" + Environment.NewLine +
" new lines",
ex.Message
);
}
}
public class WithComparer
{
[Fact]
public void GuardClause()
{
Assert.Throws<ArgumentNullException>("comparer", () => Assert.Equal(1, 2, default(IEqualityComparer<int>)!));
}
[Fact]
public void Equal()
{
Assert.Equal(42, 21, new Comparer<int>(true));
}
[Fact]
public void NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(42, 42, new Comparer<int>(false)));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: 42" + Environment.NewLine +
"Actual: 42",
ex.Message
);
}
class Comparer<T> : IEqualityComparer<T>
{
readonly bool result;
public Comparer(bool result)
{
this.result = result;
}
public bool Equals(T? x, T? y) => result;
public int GetHashCode(T obj) => throw new NotImplementedException();
}
[Fact]
public void NonEnumerable_WithThrow_RecordsInnerException()
{
var ex = Record.Exception(() => Assert.Equal(42, 2112, new ThrowingIntComparer()));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Exception thrown during comparison" + Environment.NewLine +
"Expected: 42" + Environment.NewLine +
"Actual: 2112",
ex.Message
);
Assert.IsType<DivideByZeroException>(ex.InnerException);
}
public class ThrowingIntComparer : IEqualityComparer<int>
{
public bool Equals(int x, int y) =>
throw new DivideByZeroException();
public int GetHashCode(int obj) =>
throw new NotImplementedException();
}
[Fact]
public void Enumerable_WithThrow_RecordsInnerException()
{
var ex = Record.Exception(() => Assert.Equal(new[] { 1, 2 }, new[] { 1, 3 }, new ThrowingEnumerableComparer()));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Exception thrown during comparison" + Environment.NewLine +
"Expected: [1, 2]" + Environment.NewLine +
"Actual: [1, 3]",
ex.Message
);
Assert.IsType<DivideByZeroException>(ex.InnerException);
}
public class ThrowingEnumerableComparer : IEqualityComparer<IEnumerable<int>>
{
public bool Equals(IEnumerable<int>? x, IEnumerable<int>? y) =>
throw new DivideByZeroException();
public int GetHashCode(IEnumerable<int> obj) =>
throw new NotImplementedException();
}
}
public class WithFunc
{
[Fact]
public void GuardClause()
{
Assert.Throws<ArgumentNullException>("comparer", () => Assert.Equal(1, 2, default(Func<int, int, bool>)!));
}
[Fact]
public void Equal()
{
Assert.Equal(42, 21, (x, y) => true);
}
[Fact]
public void NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(42, 42, (x, y) => false));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: 42" + Environment.NewLine +
"Actual: 42",
ex.Message
);
}
[Fact]
public void NonEnumerable_WithThrow_RecordsInnerException()
{
var ex = Record.Exception(() => Assert.Equal(42, 2112, (e, a) => throw new DivideByZeroException()));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Exception thrown during comparison" + Environment.NewLine +
"Expected: 42" + Environment.NewLine +
"Actual: 2112",
ex.Message
);
Assert.IsType<DivideByZeroException>(ex.InnerException);
}
[Fact]
public void Enumerable_WithThrow_RecordsInnerException()
{
var ex = Record.Exception(
() => Assert.Equal(
new[] { 1, 2 },
new[] { 1, 3 },
(IEnumerable<int> e, IEnumerable<int> a) => throw new DivideByZeroException()
)
);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Exception thrown during comparison" + Environment.NewLine +
"Expected: [1, 2]" + Environment.NewLine +
"Actual: [1, 3]",
ex.Message
);
Assert.IsType<DivideByZeroException>(ex.InnerException);
}
}
public class Comparable
{
[Fact]
public void Equal()
{
var obj1 = new SpyComparable(0);
var obj2 = new SpyComparable(0);
Assert.Equal(obj1, obj2);
Assert.True(obj1.CompareCalled);
}
[Fact]
public void NotEqual()
{
var obj1 = new SpyComparable(-1);
var obj2 = new SpyComparable(0);
var ex = Record.Exception(() => Assert.Equal(obj1, obj2));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: SpyComparable { CompareCalled = True }" + Environment.NewLine +
"Actual: SpyComparable { CompareCalled = False }",
ex.Message
);
}
[Fact]
public void NonGeneric_SameType_Equal()
{
var expected = new MultiComparable(1);
var actual = new MultiComparable(1);
Assert.Equal(expected, actual);
Assert.Equal(expected, (IComparable)actual);
Assert.Equal(expected, (object)actual);
}
[Fact]
public void NonGeneric_SameType_NotEqual()
{
var expected = new MultiComparable(1);
var actual = new MultiComparable(2);
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: MultiComparable { Value = 1 }" + Environment.NewLine +
"Actual: MultiComparable { Value = 2 }",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (IComparable)actual));
assertFailure(() => Assert.Equal(expected, (object)actual));
}
[Fact]
public void NonGeneric_DifferentType_Equal()
{
var expected = new MultiComparable(1);
var actual = 1;
Assert.Equal(expected, (IComparable)actual);
Assert.Equal(expected, (object)actual);
}
[Fact]
public void NonGeneric_DifferentType_NotEqual()
{
var expected = new MultiComparable(1);
var actual = 2;
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: MultiComparable { Value = 1 }" + Environment.NewLine +
"Actual: 2",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, (IComparable)actual));
assertFailure(() => Assert.Equal(expected, (object)actual));
}
[Fact]
public void Generic_Equal()
{
var obj1 = new SpyComparable_Generic();
var obj2 = new SpyComparable_Generic();
Assert.Equal(obj1, obj2);
Assert.True(obj1.CompareCalled);
}
[Fact]
public void Generic_NotEqual()
{
var obj1 = new SpyComparable_Generic(-1);
var obj2 = new SpyComparable_Generic();
var ex = Record.Exception(() => Assert.Equal(obj1, obj2));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: SpyComparable_Generic { CompareCalled = True }" + Environment.NewLine +
"Actual: SpyComparable_Generic { CompareCalled = False }",
ex.Message
);
}
[Fact]
public void SubClass_SubClass_Equal()
{
var expected = new ComparableSubClassA(1);
var actual = new ComparableSubClassB(1);
Assert.Equal<ComparableBaseClass>(expected, actual);
}
[Fact]
public void SubClass_SubClass_NotEqual()
{
var expected = new ComparableSubClassA(1);
var actual = new ComparableSubClassB(2);
var ex = Record.Exception(() => Assert.Equal<ComparableBaseClass>(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: ComparableSubClassA { Value = 1 }" + Environment.NewLine +
"Actual: ComparableSubClassB { Value = 2 }",
ex.Message
);
}
[Fact]
public void BaseClass_SubClass_Equal()
{
var expected = new ComparableBaseClass(1);
var actual = new ComparableSubClassA(1);
Assert.Equal(expected, actual);
}
[Fact]
public void BaseClass_SubClass_NotEqual()
{
var expected = new ComparableBaseClass(1);
var actual = new ComparableSubClassA(2);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: ComparableBaseClass { Value = 1 }" + Environment.NewLine +
"Actual: ComparableSubClassA { Value = 2 }",
ex.Message
);
}
[Fact]
public void SubClass_BaseClass_Equal()
{
var expected = new ComparableSubClassA(1);
var actual = new ComparableBaseClass(1);
Assert.Equal(expected, actual);
}
[Fact]
public void SubClass_BaseClass_NotEqual()
{
var expected = new ComparableSubClassA(1);
var actual = new ComparableBaseClass(2);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: ComparableSubClassA { Value = 1 }" + Environment.NewLine +
"Actual: ComparableBaseClass { Value = 2 }",
ex.Message
);
}
[Fact]
public void Generic_ThrowsException_Equal()
{
var expected = new ComparableThrower(1);
var actual = new ComparableThrower(1);
Assert.Equal(expected, actual);
Assert.Equal(expected, (IComparable<ComparableThrower>)actual);
Assert.Equal(expected, (object)actual);
}
[Fact]
public void Generic_ThrowsException_NotEqual()
{
var expected = new ComparableThrower(1);
var actual = new ComparableThrower(2);
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: ComparableThrower { Value = 1 }" + Environment.NewLine +
"Actual: ComparableThrower { Value = 2 }",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (IComparable<ComparableThrower>)actual));
assertFailure(() => Assert.Equal(expected, (object)actual));
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void DifferentTypes_ImplicitImplementation_Equal()
{
object expected = new ImplicitIComparableExpected(1);
object actual = new IntWrapper(1);
Assert.Equal(expected, actual);
}
[Fact]
public void DifferentTypes_ImplicitImplementation_NotEqual()
{
object expected = new ImplicitIComparableExpected(1);
object actual = new IntWrapper(2);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: ImplicitIComparableExpected { Value = 1 }" + Environment.NewLine +
"Actual: IntWrapper { Value = 2 }",
ex.Message
);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void DifferentTypes_ExplicitImplementation_Equal()
{
object expected = new ExplicitIComparableActual(1);
object actual = new IntWrapper(1);
Assert.Equal(expected, actual);
}
[Fact]
public void DifferentTypes_ExplicitImplementation_NotEqual()
{
object expected = new ExplicitIComparableActual(1);
object actual = new IntWrapper(2);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: ExplicitIComparableActual { Value = 1 }" + Environment.NewLine +
"Actual: IntWrapper { Value = 2 }",
ex.Message
);
}
[Fact]
public void DifferentTypes_Throws_Equal()
{
object expected = new IComparableActualThrower(1);
object actual = new IntWrapper(1);
Assert.Equal(expected, actual);
}
[Fact]
public void DifferentTypes_Throws_NotEqual()
{
object expected = new IComparableActualThrower(1);
object actual = new IntWrapper(2);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: IComparableActualThrower { Value = 1 }" + Environment.NewLine +
"Actual: IntWrapper { Value = 2 }",
ex.Message
);
}
}
public class NotComparable
{
[Fact]
public void Equal()
{
var nco1 = new NonComparableObject();
var nco2 = new NonComparableObject();
Assert.Equal(nco1, nco2);
}
[Fact]
public void NotEqual()
{
var nco1 = new NonComparableObject(false);
var nco2 = new NonComparableObject();
var ex = Record.Exception(() => Assert.Equal(nco1, nco2));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: NonComparableObject { }" + Environment.NewLine +
"Actual: NonComparableObject { }",
ex.Message
);
}
}
public class Equatable
{
[Fact]
public void Equal()
{
var obj1 = new SpyEquatable();
var obj2 = new SpyEquatable();
Assert.Equal(obj1, obj2);
Assert.True(obj1.Equals__Called);
Assert.Same(obj2, obj1.Equals_Other);
}
[Fact]
public void NotEqual()
{
var obj1 = new SpyEquatable(false);
var obj2 = new SpyEquatable();
var ex = Record.Exception(() => Assert.Equal(obj1, obj2));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: SpyEquatable { Equals__Called = True, Equals_Other = SpyEquatable { Equals__Called = False, Equals_Other = null } }" + Environment.NewLine +
"Actual: SpyEquatable { Equals__Called = False, Equals_Other = null }",
ex.Message
);
}
[Fact]
public void SubClass_SubClass_Equal()
{
var expected = new EquatableSubClassA(1);
var actual = new EquatableSubClassB(1);
Assert.Equal<EquatableBaseClass>(expected, actual);
}
[Fact]
public void SubClass_SubClass_NotEqual()
{
var expected = new EquatableSubClassA(1);
var actual = new EquatableSubClassB(2);
var ex = Record.Exception(() => Assert.Equal<EquatableBaseClass>(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: EquatableSubClassA { Value = 1 }" + Environment.NewLine +
"Actual: EquatableSubClassB { Value = 2 }",
ex.Message
);
}
[Fact]
public void BaseClass_SubClass_Equal()
{
var expected = new EquatableBaseClass(1);
var actual = new EquatableSubClassA(1);
Assert.Equal(expected, actual);
}
[Fact]
public void BaseClass_SubClass_NotEqual()
{
var expected = new EquatableBaseClass(1);
var actual = new EquatableSubClassA(2);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: EquatableBaseClass { Value = 1 }" + Environment.NewLine +
"Actual: EquatableSubClassA { Value = 2 }",
ex.Message
);
}
[Fact]
public void SubClass_BaseClass_Equal()
{
var expected = new EquatableSubClassA(1);
var actual = new EquatableBaseClass(1);
Assert.Equal(expected, actual);
}
[Fact]
public void SubClass_BaseClass_NotEqual()
{
var expected = new EquatableSubClassA(1);
var actual = new EquatableBaseClass(2);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: EquatableSubClassA { Value = 1 }" + Environment.NewLine +
"Actual: EquatableBaseClass { Value = 2 }",
ex.Message
);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void DifferentTypes_ImplicitImplementation_Equal()
{
object expected = new ImplicitIEquatableExpected(1);
object actual = new IntWrapper(1);
Assert.Equal(expected, actual);
}
[Fact]
public void DifferentTypes_ImplicitImplementation_NotEqual()
{
object expected = new ImplicitIEquatableExpected(1);
object actual = new IntWrapper(2);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: ImplicitIEquatableExpected { Value = 1 }" + Environment.NewLine +
"Actual: IntWrapper { Value = 2 }",
ex.Message
);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void DifferentTypes_ExplicitImplementation_Equal()
{
object expected = new ExplicitIEquatableExpected(1);
object actual = new IntWrapper(1);
Assert.Equal(expected, actual);
}
[Fact]
public void DifferentTypes_ExplicitImplementation_NotEqual()
{
object expected = new ExplicitIEquatableExpected(1);
object actual = new IntWrapper(2);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: ExplicitIEquatableExpected { Value = 1 }" + Environment.NewLine +
"Actual: IntWrapper { Value = 2 }",
ex.Message
);
}
}
public class StructuralEquatable
{
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void Equal()
{
var expected = new Tuple<StringWrapper>(new StringWrapper("a"));
var actual = new Tuple<StringWrapper>(new StringWrapper("a"));
Assert.Equal(expected, actual);
Assert.Equal(expected, (IStructuralEquatable)actual);
Assert.Equal(expected, (object)actual);
}
[Fact]
public void NotEqual()
{
var expected = new Tuple<StringWrapper>(new StringWrapper("a"));
var actual = new Tuple<StringWrapper>(new StringWrapper("b"));
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: Tuple (StringWrapper { Value = \"a\" })" + Environment.NewLine +
"Actual: Tuple (StringWrapper { Value = \"b\" })",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (IStructuralEquatable)actual));
assertFailure(() => Assert.Equal(expected, (object)actual));
}
[Fact]
public void ExpectedNull_ActualNull()
{
var expected = new Tuple<StringWrapper?>(null);
var actual = new Tuple<StringWrapper?>(null);
Assert.Equal(expected, actual);
Assert.Equal(expected, (IStructuralEquatable)actual);
Assert.Equal(expected, (object)actual);
}
[Fact]
public void ExpectedNull_ActualNonNull()
{
var expected = new Tuple<StringWrapper?>(null);
var actual = new Tuple<StringWrapper?>(new StringWrapper("a"));
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: Tuple (null)" + Environment.NewLine +
"Actual: Tuple (StringWrapper { Value = \"a\" })",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (IStructuralEquatable)actual));
assertFailure(() => Assert.Equal(expected, (object)actual));
}
[Fact]
public void _ExpectedNonNull_ActualNull()
{
var expected = new Tuple<StringWrapper?>(new StringWrapper("a"));
var actual = new Tuple<StringWrapper?>(null);
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: Tuple (StringWrapper { Value = \"a\" })" + Environment.NewLine +
"Actual: Tuple (null)",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (IStructuralEquatable)actual));
assertFailure(() => Assert.Equal(expected, (object)actual));
}
}
public class Collections
{
[Fact]
public void IReadOnlyCollection_IEnumerable_Equal()
{
var expected = new string[] { "foo", "bar" };
var actual = new ReadOnlyCollection<string>(expected);
Assert.Equal(expected, (IReadOnlyCollection<string>)actual);
Assert.Equal(expected, (object)actual);
}
[Fact]
public void IReadOnlyCollection_IEnumerable_NotEqual()
{
var expected = new string[] { "foo", "bar" };
var actual = new ReadOnlyCollection<string>(new[] { "bar", "foo" });
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
" ↓ (pos 0)" + Environment.NewLine +
"Expected: string[] [\"foo\", \"bar\"]" + Environment.NewLine +
"Actual: ReadOnlyCollection<string> [\"bar\", \"foo\"]" + Environment.NewLine +
" ↑ (pos 0)",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, (IReadOnlyCollection<string>)actual));
assertFailure(() => Assert.Equal(expected, (object)actual));
}
[Fact]
public void CollectionDepth_Equal()
{
var x = new List<object> { new List<object> { new List<object> { 1 } } };
var y = new List<object> { new List<object> { new List<object> { 1 } } };
Assert.Equal(x, y);
}
[Fact]
public void CollectionDepth_NotEqual()
{
var x = new List<object> { new List<object> { new List<object> { 1 } } };
var y = new List<object> { new List<object> { new List<object> { 2 } } };
var ex = Record.Exception(() => Assert.Equal(x, y));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
" ↓ (pos 0)" + Environment.NewLine +
"Expected: [[[1]]]" + Environment.NewLine +
"Actual: [[[2]]]" + Environment.NewLine +
" ↑ (pos 0)",
ex.Message
);
}
[Fact]
public void StringArray_ObjectArray_Equal()
{
var expected = new string[] { "foo", "bar" };
var actual = new object[] { "foo", "bar" };
Assert.Equal(expected, actual);
Assert.Equal(expected, (object)actual);
}
[Fact]
public void StringArray_ObjectArray_NotEqual()
{
var expected = new string[] { "foo", "bar" };
var actual = new object[] { "foo", "baz" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
" ↓ (pos 1)" + Environment.NewLine +
"Expected: string[] [\"foo\", \"bar\"]" + Environment.NewLine +
"Actual: object[] [\"foo\", \"baz\"]" + Environment.NewLine +
" ↑ (pos 1)",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (object)actual));
}
[Fact]
public void MultidimensionalArrays_Equal()
{
var expected = new int[,] { { 1 }, { 2 } };
var actual = new int[,] { { 1 }, { 2 } };
Assert.Equal(expected, actual);
}
[Fact]
public void MultidimensionalArrays_NotEqual()
{
var expected = new int[,] { { 1, 2 } };
var actual = new int[,] { { 1 }, { 2 } };
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
// TODO: Would be better to have formatting that preserves the ranks instead of
// flattening, which happens because multi-dimensional arrays enumerate flatly
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
"Expected: [1, 2]" + Environment.NewLine +
"Actual: [1, 2]",
ex.Message
);
}
[Fact]
public void NonZeroBoundedArrays_Equal()
{
var expected = Array.CreateInstance(typeof(int), new[] { 1 }, new[] { 1 });
expected.SetValue(42, 1);
var actual = Array.CreateInstance(typeof(int), new[] { 1 }, new[] { 1 });
actual.SetValue(42, 1);
Assert.Equal(expected, actual);
}
[Fact]
public void NonZeroBoundedArrays_NotEqual()
{
var expected = Array.CreateInstance(typeof(int), new[] { 1 }, new[] { 1 });
expected.SetValue(42, 1);
var actual = Array.CreateInstance(typeof(int), new[] { 1 }, new[] { 0 });
actual.SetValue(42, 0);
var ex = Record.Exception(() => Assert.Equal(expected, (object)actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
"Expected: int[*] [42]" + Environment.NewLine +
"Actual: int[] [42]",
ex.Message
);
}
[Fact]
public void PrintPointersWithCompatibleComparers()
{
var expected = new[] { 1, 2, 3, 4, 5 };
var actual = new[] { 1, 2, 0, 4, 5 };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
" ↓ (pos 2)" + Environment.NewLine +
"Expected: [1, 2, 3, 4, 5]" + Environment.NewLine +
"Actual: [1, 2, 0, 4, 5]" + Environment.NewLine +
" ↑ (pos 2)",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, actual, EqualityComparer<IEnumerable<int>>.Default));
}
[Fact]
public void CustomComparerWithSafeEnumerable()
{
var expected = new[] { 1, 2, 3, 4, 5 };
var actual = new[] { 1, 2, 0, 4, 5 };
var ex = Record.Exception(() => Assert.Equal(expected, actual, new MyComparer()));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
"Expected: [1, 2, 3, 4, 5]" + Environment.NewLine +
"Actual: [1, 2, 0, 4, 5]",
ex.Message
);
}
[Fact]
public void CustomComparerWithUnsafeEnumerable()
{
var ex = Record.Exception(() => Assert.Equal(new UnsafeEnumerable(), new[] { 1, 2, 3 }, new MyComparer()));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
$"Expected: UnsafeEnumerable [{ArgumentFormatter.Ellipsis}]" + Environment.NewLine +
"Actual: int[] [1, 2, 3]",
ex.Message
);
}
class UnsafeEnumerable : IEnumerable
{
public IEnumerator GetEnumerator()
{
while (true)
yield return 1;
}
}
class MyComparer : IEqualityComparer<IEnumerable>
{
public bool Equals(IEnumerable? x, IEnumerable? y)
=> false;
public int GetHashCode([DisallowNull] IEnumerable obj) =>
throw new NotImplementedException();
}
[Fact]
public void CollectionWithIEquatable_Equal()
{
var expected = new EnumerableEquatable<int> { 42, 2112 };
var actual = new EnumerableEquatable<int> { 2112, 42 };
Assert.Equal(expected, actual);
}
[Fact]
public void CollectionWithIEquatable_NotEqual()
{
var expected = new EnumerableEquatable<int> { 42, 2112 };
var actual = new EnumerableEquatable<int> { 2112, 2600 };
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
// No pointers because it's relying on IEquatable<>
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
"Expected: [42, 2112]" + Environment.NewLine +
"Actual: [2112, 2600]",
ex.Message
);
}
public sealed class EnumerableEquatable<T> :
IEnumerable<T>, IEquatable<EnumerableEquatable<T>>
{
List<T> values = new();
public void Add(T value) => values.Add(value);
public bool Equals(EnumerableEquatable<T>? other)
{
if (other == null)
return false;
return !values.Except(other.values).Any() && !other.values.Except(values).Any();
}
public IEnumerator<T> GetEnumerator() => values.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
public class Dictionaries
{
[Fact]
public void SameTypes_Equal()
{
var expected = new Dictionary<string, string> { ["foo"] = "bar" };
var actual = new Dictionary<string, string> { ["foo"] = "bar" };
Assert.Equal(expected, actual);
Assert.Equal(expected, (IDictionary)actual);
Assert.Equal(expected, (object)actual);
}
[Fact]
public void SameTypes_NotEqual()
{
var expected = new Dictionary<string, string> { ["foo"] = "bar" };
var actual = new Dictionary<string, string> { ["foo"] = "baz" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Dictionaries differ" + Environment.NewLine +
"Expected: [[\"foo\"] = \"bar\"]" + Environment.NewLine +
"Actual: [[\"foo\"] = \"baz\"]",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (IDictionary)actual));
assertFailure(() => Assert.Equal(expected, (object)actual));
}
[Fact]
public void DifferentTypes_Equal()
{
var expected = new Dictionary<string, string> { ["foo"] = "bar" };
var actual = new ConcurrentDictionary<string, string>(expected);
Assert.Equal(expected, (IDictionary)actual);
Assert.Equal(expected, (object)actual);
}
[Fact]
public void DifferentTypes_NotEqual()
{
var expected = new Dictionary<string, string> { ["foo"] = "bar" };
var actual = new ConcurrentDictionary<string, string> { ["foo"] = "baz" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
"Expected: Dictionary<string, string> [[\"foo\"] = \"bar\"]" + Environment.NewLine +
"Actual: ConcurrentDictionary<string, string> [[\"foo\"] = \"baz\"]",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, (IDictionary)actual));
assertFailure(() => Assert.Equal(expected, (object)actual));
}
[Fact]
public void NullValue_Equal()
{
var expected = new Dictionary<string, int?> { { "two", null } };
var actual = new Dictionary<string, int?> { { "two", null } };
Assert.Equal(expected, actual);
}
[Fact]
public void NullValue_NotEqual()
{
var expected = new Dictionary<string, int?> { { "two", null } };
var actual = new Dictionary<string, int?> { { "two", 1 } };
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Dictionaries differ" + Environment.NewLine +
"Expected: [[\"two\"] = null]" + Environment.NewLine +
"Actual: [[\"two\"] = 1]",
ex.Message
);
}
}
public class HashSets
{
[Fact]
public static void InOrder_Equal()
{
var expected = new HashSet<int> { 1, 2, 3 };
var actual = new HashSet<int> { 1, 2, 3 };
Assert.Equal(expected, actual);
}
[Fact]
public static void InOrder_NotEqual()
{
var expected = new HashSet<int> { 1, 2, 3 };
var actual = new HashSet<int> { 1, 2, 4 };
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: HashSets differ" + Environment.NewLine +
"Expected: [1, 2, 3]" + Environment.NewLine +
"Actual: [1, 2, 4]",
ex.Message
);
}
[Fact]
public static void OutOfOrder_Equal()
{
var expected = new HashSet<int> { 1, 2, 3 };
var actual = new HashSet<int> { 2, 3, 1 };
Assert.Equal(expected, actual);
}
[Fact]
public static void OutOfOrder_NotEqual()
{
var expected = new HashSet<int> { 1, 2, 3 };
var actual = new HashSet<int> { 2, 4, 1 };
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: HashSets differ" + Environment.NewLine +
"Expected: [1, 2, 3]" + Environment.NewLine +
"Actual: [2, 4, 1]",
ex.Message
);
}
[Fact]
public static void ExpectedLarger()
{
var expected = new HashSet<int> { 1, 2, 3 };
var actual = new HashSet<int> { 1, 2 };
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: HashSets differ" + Environment.NewLine +
"Expected: [1, 2, 3]" + Environment.NewLine +
"Actual: [1, 2]",
ex.Message
);
}
[Fact]
public static void ActualLarger()
{
var expected = new HashSet<int> { 1, 2 };
var actual = new HashSet<int> { 1, 2, 3 };
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: HashSets differ" + Environment.NewLine +
"Expected: [1, 2]" + Environment.NewLine +
"Actual: [1, 2, 3]",
ex.Message
);
}
[Fact]
public void DifferentTypes_Equal()
{
var expected = new HashSet<string> { "bar", "foo" };
var actual = new SortedSet<string> { "foo", "bar" };
Assert.Equal(expected, actual);
Assert.Equal(expected, (ISet<string>)actual);
#pragma warning disable xUnit2027
Assert.Equal(expected, (object)actual);
#pragma warning restore xUnit2027
}
[Fact]
public void DifferentTypes_NotEqual()
{
object expected = new HashSet<int> { 42 };
object actual = new HashSet<long> { 42L };
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: HashSets differ" + Environment.NewLine +
"Expected: HashSet<int> [42]" + Environment.NewLine +
"Actual: HashSet<long> [42]",
ex.Message
);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void ComparerFunc_Throws()
{
var expected = new HashSet<string> { "bar" };
var actual = new HashSet<string> { "baz" };
#pragma warning disable xUnit2026
var ex = Record.Exception(() => Assert.Equal(expected, actual, (string l, string r) => true));
#pragma warning restore xUnit2026
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: During comparison of two collections, GetHashCode was called, but only a comparison function was provided. This typically indicates trying to compare two sets with an item comparison function, which is not supported. For more information, see https://xunit.net/docs/hash-sets-vs-linear-containers",
ex.Message
);
}
}
public class Sets
{
[Fact]
public void InOrder_Equal()
{
var expected = new NonGenericSet { "bar", "foo" };
var actual = new NonGenericSet { "bar", "foo" };
Assert.Equal(expected, actual);
Assert.Equal(expected, (ISet<string>)actual);
#pragma warning disable xUnit2027
Assert.Equal(expected, (object)actual);
#pragma warning restore xUnit2027
}
[Fact]
public void InOrder_NotEqual()
{
var expected = new NonGenericSet { "bar", "foo" };
var actual = new NonGenericSet { "bar", "baz" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Sets differ" + Environment.NewLine +
"Expected: [\"bar\", \"foo\"]" + Environment.NewLine +
"Actual: [\"bar\", \"baz\"]",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (ISet<string>)actual));
#pragma warning disable xUnit2027
assertFailure(() => Assert.Equal(expected, (object)actual));
#pragma warning restore xUnit2027
}
[Fact]
public void OutOfOrder_Equal()
{
var expected = new NonGenericSet { "bar", "foo" };
var actual = new NonGenericSet { "foo", "bar" };
Assert.Equal(expected, actual);
Assert.Equal(expected, (ISet<string>)actual);
#pragma warning disable xUnit2027
Assert.Equal(expected, (object)actual);
#pragma warning restore xUnit2027
}
[Fact]
public void OutOfOrder_NotEqual()
{
var expected = new NonGenericSet { "bar", "foo" };
var actual = new NonGenericSet { "foo", "baz" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Sets differ" + Environment.NewLine +
"Expected: [\"bar\", \"foo\"]" + Environment.NewLine +
"Actual: [\"foo\", \"baz\"]",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (ISet<string>)actual));
#pragma warning disable xUnit2027
assertFailure(() => Assert.Equal(expected, (object)actual));
#pragma warning restore xUnit2027
}
[Fact]
public void DifferentContents()
{
var expected = new NonGenericSet { "bar" };
var actual = new NonGenericSet { "bar", "foo" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Sets differ" + Environment.NewLine +
"Expected: [\"bar\"]" + Environment.NewLine +
"Actual: [\"bar\", \"foo\"]",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (ISet<string>)actual));
#pragma warning disable xUnit2027
assertFailure(() => Assert.Equal(expected, (object)actual));
#pragma warning restore xUnit2027
}
[Fact]
public void DifferentTypes_Equal()
{
var expected = new NonGenericSet { "bar" };
var actual = new HashSet<string> { "bar" };
Assert.Equal(expected, actual);
Assert.Equal(expected, (ISet<string>)actual);
#pragma warning disable xUnit2027
Assert.Equal(expected, (object)actual);
#pragma warning restore xUnit2027
}
[Fact]
public void DifferentTypes_NotEqual()
{
var expected = new NonGenericSet { "bar" };
var actual = new HashSet<string> { "baz" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Sets differ" + Environment.NewLine +
"Expected: NonGenericSet [\"bar\"]" + Environment.NewLine +
"Actual: HashSet<string> [\"baz\"]",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (ISet<string>)actual));
#pragma warning disable xUnit2027
assertFailure(() => Assert.Equal(expected, (object)actual));
#pragma warning restore xUnit2027
}
[Fact]
public void TwoGenericSubClass_Equal()
{
var expected = new TwoGenericSet<string, int> { "foo", "bar" };
var actual = new TwoGenericSet<string, int> { "foo", "bar" };
Assert.Equal(expected, actual);
Assert.Equal(expected, (ISet<string>)actual);
#pragma warning disable xUnit2027
Assert.Equal(expected, (object)actual);
#pragma warning restore xUnit2027
}
[Fact]
public void TwoGenericSubClass_NotEqual()
{
var expected = new TwoGenericSet<string, int> { "foo", "bar" };
var actual = new TwoGenericSet<string, int> { "foo", "baz" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Sets differ" + Environment.NewLine +
"Expected: [\"foo\", \"bar\"]" + Environment.NewLine +
"Actual: [\"foo\", \"baz\"]",
ex.Message
);
}
assertFailure(() => Assert.Equal(expected, actual));
assertFailure(() => Assert.Equal(expected, (ISet<string>)actual));
#pragma warning disable xUnit2027
assertFailure(() => Assert.Equal(expected, (object)actual));
#pragma warning restore xUnit2027
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void ComparerFunc_Throws()
{
var expected = new NonGenericSet { "bar" };
var actual = new HashSet<string> { "baz" };
#pragma warning disable xUnit2026
var ex = Record.Exception(() => Assert.Equal(expected, actual, (string l, string r) => true));
#pragma warning restore xUnit2026
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: During comparison of two collections, GetHashCode was called, but only a comparison function was provided. This typically indicates trying to compare two sets with an item comparison function, which is not supported. For more information, see https://xunit.net/docs/hash-sets-vs-linear-containers",
ex.Message
);
}
}
public class KeyValuePair
{
[Fact]
public void CollectionKeys_Equal()
{
// Different concrete collection types in the key slot, per https://github.com/xunit/xunit/issues/2850
var expected = new KeyValuePair<IEnumerable<string>, int>(new List<string> { "Key1", "Key2" }, 42);
var actual = new KeyValuePair<IEnumerable<string>, int>(new string[] { "Key1", "Key2" }, 42);
Assert.Equal(expected, actual);
}
[Fact]
public void CollectionKeys_NotEqual()
{
// Different concrete collection types in the key slot, per https://github.com/xunit/xunit/issues/2850
var expected = new KeyValuePair<IEnumerable<string>, int>(new List<string> { "Key1", "Key2" }, 42);
var actual = new KeyValuePair<IEnumerable<string>, int>(new string[] { "Key1", "Key3" }, 42);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: [[\"Key1\", \"Key2\"]] = 42" + Environment.NewLine +
"Actual: [[\"Key1\", \"Key3\"]] = 42",
ex.Message
);
}
[Fact]
public void CollectionValues_Equal()
{
// Different concrete collection types in the value slot, per https://github.com/xunit/xunit/issues/2850
var expected = new KeyValuePair<string, IEnumerable<string>>("Key1", new List<string> { "Value1a", "Value1b" });
var actual = new KeyValuePair<string, IEnumerable<string>>("Key1", new string[] { "Value1a", "Value1b" });
Assert.Equal(expected, actual);
}
[Fact]
public void CollectionValues_NotEqual()
{
// Different concrete collection types in the value slot, per https://github.com/xunit/xunit/issues/2850
var expected = new KeyValuePair<string, IEnumerable<string>>("Key1", new List<string> { "Value1a", "Value1b" });
var actual = new KeyValuePair<string, IEnumerable<string>>("Key1", new string[] { "Value1a", "Value2a" });
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: [\"Key1\"] = [\"Value1a\", \"Value1b\"]" + Environment.NewLine +
"Actual: [\"Key1\"] = [\"Value1a\", \"Value2a\"]",
ex.Message
);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void EquatableKeys_Equal()
{
var expected = new KeyValuePair<EquatableObject, int>(new() { Char = 'a' }, 42);
var actual = new KeyValuePair<EquatableObject, int>(new() { Char = 'a' }, 42);
Assert.Equal(expected, actual);
}
[Fact]
public void EquatableKeys_NotEqual()
{
var expected = new KeyValuePair<EquatableObject, int>(new() { Char = 'a' }, 42);
var actual = new KeyValuePair<EquatableObject, int>(new() { Char = 'b' }, 42);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: [EquatableObject { Char = 'a' }] = 42" + Environment.NewLine +
"Actual: [EquatableObject { Char = 'b' }] = 42",
ex.Message
);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void EquatableValues_Equal()
{
var expected = new KeyValuePair<string, EquatableObject>("Key1", new() { Char = 'a' });
var actual = new KeyValuePair<string, EquatableObject>("Key1", new() { Char = 'a' });
Assert.Equal(expected, actual);
}
[Fact]
public void EquatableValues_NotEqual()
{
var expected = new KeyValuePair<string, EquatableObject>("Key1", new() { Char = 'a' });
var actual = new KeyValuePair<string, EquatableObject>("Key1", new() { Char = 'b' });
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
"Expected: [\"Key1\"] = EquatableObject { Char = 'a' }" + Environment.NewLine +
"Actual: [\"Key1\"] = EquatableObject { Char = 'b' }",
ex.Message
);
}
public class EquatableObject : IEquatable<EquatableObject>
{
public char Char { get; set; }
public bool Equals(EquatableObject? other) =>
other != null && other.Char == Char;
}
}
public class DoubleEnumerationPrevention
{
[Fact]
public static void EnumeratesOnlyOnce_Equal()
{
var expected = new RunOnceEnumerable<int>(new[] { 1, 2, 3, 4, 5 });
var actual = new RunOnceEnumerable<int>(new[] { 1, 2, 3, 4, 5 });
Assert.Equal(expected, actual);
}
[Fact]
public static void EnumeratesOnlyOnce_NotEqual()
{
var expected = new RunOnceEnumerable<int>(new[] { 1, 2, 3, 4, 5 });
var actual = new RunOnceEnumerable<int>(new[] { 1, 2, 3, 4, 5, 6 });
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Collections differ" + Environment.NewLine +
$"Expected: [{ArgumentFormatter.Ellipsis}, 2, 3, 4, 5]" + Environment.NewLine +
$"Actual: [{ArgumentFormatter.Ellipsis}, 2, 3, 4, 5, 6]" + Environment.NewLine +
" ↑ (pos 5)",
ex.Message
);
}
}
}
public class Equal_DateTime
{
public class WithoutPrecision
{
[Fact]
public void Equal()
{
var expected = new DateTime(2023, 2, 11, 15, 4, 0);
var actual = new DateTime(2023, 2, 11, 15, 4, 0);
Assert.Equal(expected, actual);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NotEqual()
{
var expected = new DateTime(2023, 2, 11, 15, 4, 0);
var actual = new DateTime(2023, 2, 11, 15, 5, 0);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values differ" + Environment.NewLine +
$"Expected: {ArgumentFormatter.Format(expected)}" + Environment.NewLine +
$"Actual: {ArgumentFormatter.Format(actual)}",
ex.Message
);
}
}
public class WithPrecision
{
[Fact]
public void InRange()
{
var date1 = new DateTime(2023, 2, 11, 15, 4, 0);
var date2 = new DateTime(2023, 2, 11, 15, 5, 0);
var precision = TimeSpan.FromMinutes(1);
Assert.Equal(date1, date2, precision); // expected earlier than actual
Assert.Equal(date2, date1, precision); // expected later than actual
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void OutOfRange()
{
var date1 = new DateTime(2023, 2, 11, 15, 4, 0);
var date2 = new DateTime(2023, 2, 11, 15, 6, 0);
var precision = TimeSpan.FromMinutes(1);
var difference = TimeSpan.FromMinutes(2);
// expected earlier than actual
var ex = Record.Exception(() => Assert.Equal(date1, date2, precision));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values differ" + Environment.NewLine +
$"Expected: {ArgumentFormatter.Format(date1)}" + Environment.NewLine +
$"Actual: {ArgumentFormatter.Format(date2)} (difference {difference} is larger than {precision})",
ex.Message
);
// expected later than actual
var ex2 = Record.Exception(() => Assert.Equal(date2, date1, precision));
Assert.IsType<EqualException>(ex2);
Assert.Equal(
$"Assert.Equal() Failure: Values differ" + Environment.NewLine +
$"Expected: {ArgumentFormatter.Format(date2)}" + Environment.NewLine +
$"Actual: {ArgumentFormatter.Format(date1)} (difference {difference} is larger than {precision})",
ex2.Message
);
}
}
}
public class Equal_DateTimeOffset
{
public class WithoutPrecision_SameTimeZone
{
[Fact]
public void Equal()
{
var expected = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.Zero);
var actual = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.Zero);
Assert.Equal(expected, actual);
Assert.Equal(expected, actual);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NotEqual()
{
var expected = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.Zero);
var actual = new DateTimeOffset(2023, 2, 11, 15, 5, 0, TimeSpan.Zero);
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values differ" + Environment.NewLine +
$"Expected: {ArgumentFormatter.Format(expected)}" + Environment.NewLine +
$"Actual: {ArgumentFormatter.Format(actual)}",
ex.Message
);
}
}
public class WithoutPrecision_DifferentTimeZone
{
[Fact]
public void Equal()
{
var expected = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.Zero);
var actual = new DateTimeOffset(2023, 2, 11, 16, 4, 0, TimeSpan.FromHours(1));
Assert.Equal(expected, actual);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NotEqual()
{
var expected = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.Zero);
var actual = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.FromHours(1));
var ex = Record.Exception(() => Assert.Equal(expected, actual));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values differ" + Environment.NewLine +
$"Expected: {ArgumentFormatter.Format(expected)}" + Environment.NewLine +
$"Actual: {ArgumentFormatter.Format(actual)}",
ex.Message
);
}
}
public class WithPrecision_SameTimeZone
{
[Fact]
public void InRange()
{
var date1 = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.Zero);
var date2 = new DateTimeOffset(2023, 2, 11, 15, 5, 0, TimeSpan.Zero);
var precision = TimeSpan.FromMinutes(1);
Assert.Equal(date1, date2, precision); // expected earlier than actual
Assert.Equal(date2, date1, precision); // expected later than actual
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void OutOfRange()
{
var date1 = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.Zero);
var date2 = new DateTimeOffset(2023, 2, 11, 15, 6, 0, TimeSpan.Zero);
var precision = TimeSpan.FromMinutes(1);
var difference = TimeSpan.FromMinutes(2);
// expected earlier than actual
var ex = Record.Exception(() => Assert.Equal(date1, date2, precision));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values differ" + Environment.NewLine +
$"Expected: {ArgumentFormatter.Format(date1)}" + Environment.NewLine +
$"Actual: {ArgumentFormatter.Format(date2)} (difference {difference} is larger than {precision})",
ex.Message
);
// expected later than actual
var ex2 = Record.Exception(() => Assert.Equal(date2, date1, precision));
Assert.IsType<EqualException>(ex2);
Assert.Equal(
$"Assert.Equal() Failure: Values differ" + Environment.NewLine +
$"Expected: {ArgumentFormatter.Format(date2)}" + Environment.NewLine +
$"Actual: {ArgumentFormatter.Format(date1)} (difference {difference} is larger than {precision})",
ex2.Message
);
}
}
public class WithPrecision_DifferentTimeZone
{
[Fact]
public void InRange()
{
var date1 = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.Zero);
var date2 = new DateTimeOffset(2023, 2, 11, 16, 5, 0, TimeSpan.FromHours(1));
var precision = TimeSpan.FromMinutes(1);
Assert.Equal(date1, date2, precision); // expected earlier than actual
Assert.Equal(date2, date1, precision); // expected later than actual
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void OutOfRange()
{
var date1 = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.Zero);
var date2 = new DateTimeOffset(2023, 2, 11, 15, 4, 0, TimeSpan.FromHours(1));
var precision = TimeSpan.FromMinutes(1);
var difference = TimeSpan.FromHours(1);
// expected earlier than actual
var ex = Record.Exception(() => Assert.Equal(date1, date2, precision));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values differ" + Environment.NewLine +
$"Expected: {ArgumentFormatter.Format(date1)}" + Environment.NewLine +
$"Actual: {ArgumentFormatter.Format(date2)} (difference {difference} is larger than {precision})",
ex.Message
);
// expected later than actual
var ex2 = Record.Exception(() => Assert.Equal(date2, date1, precision));
Assert.IsType<EqualException>(ex2);
Assert.Equal(
$"Assert.Equal() Failure: Values differ" + Environment.NewLine +
$"Expected: {ArgumentFormatter.Format(date2)}" + Environment.NewLine +
$"Actual: {ArgumentFormatter.Format(date1)} (difference {difference} is larger than {precision})",
ex2.Message
);
}
}
}
public class Equal_Decimal
{
[Fact]
public void Equal()
{
Assert.Equal(0.11111M, 0.11444M, 2);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(0.11111M, 0.11444M, 3));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values differ" + Environment.NewLine +
$"Expected: {0.111M} (rounded from {0.11111M})" + Environment.NewLine +
$"Actual: {0.114M} (rounded from {0.11444M})",
ex.Message
);
}
}
public class Equal_Double
{
public class WithPrecision
{
[Fact]
public void Equal()
{
Assert.Equal(0.11111, 0.11444, 2);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(0.11111, 0.11444, 3));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values are not within 3 decimal places" + Environment.NewLine +
$"Expected: {0.111:G17} (rounded from {0.11111:G17})" + Environment.NewLine +
$"Actual: {0.114:G17} (rounded from {0.11444:G17})",
ex.Message
);
}
}
public class WithMidPointRounding
{
[Fact]
public void Equal()
{
Assert.Equal(10.565, 10.566, 2, MidpointRounding.AwayFromZero);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(0.11113, 0.11115, 4, MidpointRounding.ToEven));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values are not within 4 decimal places" + Environment.NewLine +
$"Expected: {0.1111:G17} (rounded from {0.11113:G17})" + Environment.NewLine +
$"Actual: {0.1112:G17} (rounded from {0.11115:G17})",
ex.Message
);
}
}
public class WithTolerance
{
[Fact]
public void GuardClause()
{
var ex = Record.Exception(() => Assert.Equal(0.0, 1.0, double.NegativeInfinity));
var argEx = Assert.IsType<ArgumentException>(ex);
Assert.StartsWith("Tolerance must be greater than or equal to zero", ex.Message);
Assert.Equal("tolerance", argEx.ParamName);
}
[Fact]
public void Equal()
{
Assert.Equal(10.566, 10.565, 0.01);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(0.11113, 0.11115, 0.00001));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values are not within tolerance {0.00001:G17}" + Environment.NewLine +
$"Expected: {0.11113:G17}" + Environment.NewLine +
$"Actual: {0.11115:G17}",
ex.Message
);
}
[Fact]
public void NaN_Equal()
{
Assert.Equal(double.NaN, double.NaN, 1000.0);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NaN_NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(20210102.2208, double.NaN, 20000000.0));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values are not within tolerance {20000000.0:G17}" + Environment.NewLine +
$"Expected: {20210102.2208:G17}" + Environment.NewLine +
$"Actual: NaN",
ex.Message
);
}
[Fact]
public void InfiniteTolerance_Equal()
{
Assert.Equal(double.MinValue, double.MaxValue, double.PositiveInfinity);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void PositiveInfinity_NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(double.PositiveInfinity, 77.7, 1.0));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values are not within tolerance {1.0:G17}" + Environment.NewLine +
$"Expected: {double.PositiveInfinity}" + Environment.NewLine +
$"Actual: {77.7:G17}",
ex.Message
);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NegativeInfinity_NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(0.0, double.NegativeInfinity, 1.0));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values are not within tolerance {1.0:G17}" + Environment.NewLine +
$"Expected: {0.0:G17}" + Environment.NewLine +
$"Actual: {double.NegativeInfinity}",
ex.Message
);
}
}
}
public class Equal_Float
{
public class WithPrecision
{
[Fact]
public void Equal()
{
Assert.Equal(0.11111f, 0.11444f, 2);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(0.11111f, 0.11444f, 3));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values are not within 3 decimal places" + Environment.NewLine +
$"Expected: {0.111:G9} (rounded from {0.11111f:G9})" + Environment.NewLine +
$"Actual: {0.114:G9} (rounded from {0.11444f:G9})",
ex.Message
);
}
}
public class WithMidPointRounding
{
[Fact]
public void Equal()
{
Assert.Equal(10.5655f, 10.5666f, 2, MidpointRounding.AwayFromZero);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(0.111133f, 0.111155f, 4, MidpointRounding.ToEven));
Assert.IsType<EqualException>(ex);
Assert.Equal(
"Assert.Equal() Failure: Values are not within 4 decimal places" + Environment.NewLine +
$"Expected: {0.1111:G9} (rounded from {0.111133f:G9})" + Environment.NewLine +
$"Actual: {0.1112:G9} (rounded from {0.111155f:G9})",
ex.Message
);
}
}
public class WithTolerance
{
[Fact]
public void GuardClause()
{
var ex = Record.Exception(() => Assert.Equal(0.0f, 1.0f, float.NegativeInfinity));
var argEx = Assert.IsType<ArgumentException>(ex);
Assert.StartsWith("Tolerance must be greater than or equal to zero", ex.Message);
Assert.Equal("tolerance", argEx.ParamName);
}
[Fact]
public void Equal()
{
Assert.Equal(10.569f, 10.562f, 0.01f);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(0.11113f, 0.11115f, 0.00001f));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values are not within tolerance {0.00001f:G9}" + Environment.NewLine +
$"Expected: {0.11113f:G9}" + Environment.NewLine +
$"Actual: {0.11115f:G9}",
ex.Message
);
}
[Fact]
public void NaN_Equal()
{
Assert.Equal(float.NaN, float.NaN, 1000.0f);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NaN_NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(20210102.2208f, float.NaN, 20000000.0f));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values are not within tolerance {20000000.0f:G9}" + Environment.NewLine +
$"Expected: {20210102.2208f:G9}" + Environment.NewLine +
$"Actual: NaN",
ex.Message
);
}
[Fact]
public void InfiniteTolerance_Equal()
{
Assert.Equal(float.MinValue, float.MaxValue, float.PositiveInfinity);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void PositiveInfinity_NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(float.PositiveInfinity, 77.7f, 1.0f));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values are not within tolerance {1.0f:G9}" + Environment.NewLine +
$"Expected: {float.PositiveInfinity}" + Environment.NewLine +
$"Actual: {77.7f:G9}",
ex.Message
);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NegativeInfinity_NotEqual()
{
var ex = Record.Exception(() => Assert.Equal(0.0f, float.NegativeInfinity, 1.0f));
Assert.IsType<EqualException>(ex);
Assert.Equal(
$"Assert.Equal() Failure: Values are not within tolerance {1.0f:G9}" + Environment.NewLine +
$"Expected: {0.0f:G9}" + Environment.NewLine +
$"Actual: {float.NegativeInfinity}",
ex.Message
);
}
}
}
public class NotEqual
{
public class Intrinsics
{
[Fact]
public void EqualValues()
{
var ex = Record.Exception(() => Assert.NotEqual(42, 42));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not 42" + Environment.NewLine +
"Actual: 42",
ex.Message
);
}
[Fact]
public void UnequalValues()
{
Assert.NotEqual(42, 2112);
}
}
public class WithComparer
{
[Fact]
public void GuardClause()
{
Assert.Throws<ArgumentNullException>("comparer", () => Assert.NotEqual(1, 2, default(IEqualityComparer<int>)!));
}
[Fact]
public void Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(42, 21, new Comparer<int>(true)));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not 42" + Environment.NewLine +
"Actual: 21",
ex.Message
);
}
[Fact]
public void NotEqual()
{
Assert.NotEqual(42, 42, new Comparer<int>(false));
}
class Comparer<T> : IEqualityComparer<T>
{
readonly bool result;
public Comparer(bool result)
{
this.result = result;
}
public bool Equals(T? x, T? y) => result;
public int GetHashCode(T obj) => throw new NotImplementedException();
}
[Fact]
public void NonEnumerable_WithThrow_RecordsInnerException()
{
var ex = Record.Exception(() => Assert.NotEqual(42, 42, new ThrowingIntComparer()));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Exception thrown during comparison" + Environment.NewLine +
"Expected: Not 42" + Environment.NewLine +
"Actual: 42",
ex.Message
);
Assert.IsType<DivideByZeroException>(ex.InnerException);
}
public class ThrowingIntComparer : IEqualityComparer<int>
{
public bool Equals(int x, int y) =>
throw new DivideByZeroException();
public int GetHashCode(int obj) =>
throw new NotImplementedException();
}
[Fact]
public void Enumerable_WithThrow_RecordsInnerException()
{
var ex = Record.Exception(() => Assert.NotEqual(new[] { 1, 2 }, new[] { 1, 2 }, new ThrowingEnumerableComparer()));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Exception thrown during comparison" + Environment.NewLine +
"Expected: Not [1, 2]" + Environment.NewLine +
"Actual: [1, 2]",
ex.Message
);
Assert.IsType<DivideByZeroException>(ex.InnerException);
}
public class ThrowingEnumerableComparer : IEqualityComparer<IEnumerable<int>>
{
public bool Equals(IEnumerable<int>? x, IEnumerable<int>? y) =>
throw new DivideByZeroException();
public int GetHashCode(IEnumerable<int> obj) =>
throw new NotImplementedException();
}
[Fact]
public void Strings_WithThrow_RecordsInnerException()
{
var ex = Record.Exception(() => Assert.NotEqual("42", "42", new ThrowingStringComparer()));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Exception thrown during comparison" + Environment.NewLine +
"Expected: Not \"42\"" + Environment.NewLine +
"Actual: \"42\"",
ex.Message
);
Assert.IsType<DivideByZeroException>(ex.InnerException);
}
public class ThrowingStringComparer : IEqualityComparer<string>
{
public bool Equals(string? x, string? y) =>
throw new DivideByZeroException();
public int GetHashCode(string obj) =>
throw new NotImplementedException();
}
}
public class WithFunc
{
[Fact]
public void GuardClause()
{
Assert.Throws<ArgumentNullException>("comparer", () => Assert.NotEqual(1, 2, default(Func<int, int, bool>)!));
}
[Fact]
public void Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(42, 21, (x, y) => true));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not 42" + Environment.NewLine +
"Actual: 21",
ex.Message
);
}
[Fact]
public void NotEqual()
{
Assert.NotEqual(42, 42, (x, y) => false);
}
[Fact]
public void NonEnumerable_WithThrow_RecordsInnerException()
{
var ex = Record.Exception(() => Assert.NotEqual(42, 42, (e, a) => throw new DivideByZeroException()));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Exception thrown during comparison" + Environment.NewLine +
"Expected: Not 42" + Environment.NewLine +
"Actual: 42",
ex.Message
);
Assert.IsType<DivideByZeroException>(ex.InnerException);
}
[Fact]
public void Enumerable_WithThrow_RecordsInnerException()
{
var ex = Record.Exception(
() => Assert.NotEqual(
new[] { 1, 2 },
new[] { 1, 2 },
(IEnumerable<int> e, IEnumerable<int> a) => throw new DivideByZeroException()
)
);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Exception thrown during comparison" + Environment.NewLine +
"Expected: Not [1, 2]" + Environment.NewLine +
"Actual: [1, 2]",
ex.Message
);
Assert.IsType<DivideByZeroException>(ex.InnerException);
}
[Fact]
public void Strings_WithThrow_RecordsInnerException()
{
var ex = Record.Exception(() => Assert.NotEqual("42", "42", (e, a) => throw new DivideByZeroException()));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Exception thrown during comparison" + Environment.NewLine +
"Expected: Not \"42\"" + Environment.NewLine +
"Actual: \"42\"",
ex.Message
);
Assert.IsType<DivideByZeroException>(ex.InnerException);
}
}
public class Comparable
{
[Fact]
public void Equal()
{
var obj1 = new SpyComparable(0);
var obj2 = new SpyComparable(0);
var ex = Record.Exception(() => Assert.NotEqual(obj1, obj2));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not SpyComparable { CompareCalled = True }" + Environment.NewLine +
"Actual: SpyComparable { CompareCalled = False }",
ex.Message
);
}
[Fact]
public void NotEqual()
{
var obj1 = new SpyComparable(-1);
var obj2 = new SpyComparable(0);
Assert.NotEqual(obj1, obj2);
Assert.True(obj1.CompareCalled);
}
[Fact]
public void NonGeneric_SameType_Equal()
{
var expected = new MultiComparable(1);
var actual = new MultiComparable(1);
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not MultiComparable { Value = 1 }" + Environment.NewLine +
"Actual: MultiComparable { Value = 1 }",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, actual));
assertFailure(() => Assert.NotEqual(expected, (IComparable)actual));
assertFailure(() => Assert.NotEqual(expected, (object)actual));
}
[Fact]
public void NonGeneric_SameType_NotEqual()
{
var expected = new MultiComparable(1);
var actual = new MultiComparable(2);
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (IComparable)actual);
Assert.NotEqual(expected, (object)actual);
}
[Fact]
public void NonGeneric_DifferentType_Equal()
{
var expected = new MultiComparable(1);
var actual = 1;
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not MultiComparable { Value = 1 }" + Environment.NewLine +
"Actual: 1",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, (IComparable)actual));
assertFailure(() => Assert.NotEqual(expected, (object)actual));
}
[Fact]
public void NonGeneric_DifferentType_NotEqual()
{
var expected = new MultiComparable(1);
var actual = 2;
Assert.NotEqual(expected, (IComparable)actual);
Assert.NotEqual(expected, (object)actual);
}
[Fact]
public void Generic_Equal()
{
var obj1 = new SpyComparable_Generic();
var obj2 = new SpyComparable_Generic();
var ex = Record.Exception(() => Assert.NotEqual(obj1, obj2));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not SpyComparable_Generic { CompareCalled = True }" + Environment.NewLine +
"Actual: SpyComparable_Generic { CompareCalled = False }",
ex.Message
);
}
[Fact]
public void Generic_NotEqual()
{
var obj1 = new SpyComparable_Generic(-1);
var obj2 = new SpyComparable_Generic();
Assert.NotEqual(obj1, obj2);
Assert.True(obj1.CompareCalled);
}
[Fact]
public void SubClass_SubClass_Equal()
{
var expected = new ComparableSubClassA(1);
var actual = new ComparableSubClassB(1);
var ex = Record.Exception(() => Assert.NotEqual<ComparableBaseClass>(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not ComparableSubClassA { Value = 1 }" + Environment.NewLine +
"Actual: ComparableSubClassB { Value = 1 }",
ex.Message
);
}
[Fact]
public void SubClass_SubClass_NotEqual()
{
var expected = new ComparableSubClassA(1);
var actual = new ComparableSubClassB(2);
Assert.NotEqual<ComparableBaseClass>(expected, actual);
}
[Fact]
public void BaseClass_SubClass_Equal()
{
var expected = new ComparableBaseClass(1);
var actual = new ComparableSubClassA(1);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not ComparableBaseClass { Value = 1 }" + Environment.NewLine +
"Actual: ComparableSubClassA { Value = 1 }",
ex.Message
);
}
[Fact]
public void BaseClass_SubClass_NotEqual()
{
var expected = new ComparableBaseClass(1);
var actual = new ComparableSubClassA(2);
Assert.NotEqual(expected, actual);
}
[Fact]
public void SubClass_BaseClass_Equal()
{
var expected = new ComparableSubClassA(1);
var actual = new ComparableBaseClass(1);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not ComparableSubClassA { Value = 1 }" + Environment.NewLine +
"Actual: ComparableBaseClass { Value = 1 }",
ex.Message
);
}
[Fact]
public void SubClass_BaseClass_NotEqual()
{
var expected = new ComparableSubClassA(1);
var actual = new ComparableBaseClass(2);
Assert.NotEqual(expected, actual);
}
[Fact]
public void Generic_ThrowsException_Equal()
{
var expected = new ComparableThrower(1);
var actual = new ComparableThrower(1);
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not ComparableThrower { Value = 1 }" + Environment.NewLine +
"Actual: ComparableThrower { Value = 1 }",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, actual));
assertFailure(() => Assert.NotEqual(expected, (IComparable<ComparableThrower>)actual));
assertFailure(() => Assert.NotEqual(expected, (object)actual));
}
[Fact]
public void Generic_ThrowsException_NotEqual()
{
var expected = new ComparableThrower(1);
var actual = new ComparableThrower(2);
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (IComparable<ComparableThrower>)actual);
Assert.NotEqual(expected, (object)actual);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void DifferentTypes_ImplicitImplementation_Equal()
{
object expected = new ImplicitIComparableExpected(1);
object actual = new IntWrapper(1);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not ImplicitIComparableExpected { Value = 1 }" + Environment.NewLine +
"Actual: IntWrapper { Value = 1 }",
ex.Message
);
}
[Fact]
public void DifferentTypes_ImplicitImplementation_NotEqual()
{
object expected = new ImplicitIComparableExpected(1);
object actual = new IntWrapper(2);
Assert.NotEqual(expected, actual);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void DifferentTypes_ExplicitImplementation_Equal()
{
object expected = new ExplicitIComparableActual(1);
object actual = new IntWrapper(1);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not ExplicitIComparableActual { Value = 1 }" + Environment.NewLine +
"Actual: IntWrapper { Value = 1 }",
ex.Message
);
}
[Fact]
public void DifferentTypes_ExplicitImplementation_NotEqual()
{
object expected = new ExplicitIComparableActual(1);
object actual = new IntWrapper(2);
Assert.NotEqual(expected, actual);
}
[Fact]
public void DifferentTypes_Throws_Equal()
{
object expected = new IComparableActualThrower(1);
object actual = new IntWrapper(1);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not IComparableActualThrower { Value = 1 }" + Environment.NewLine +
"Actual: IntWrapper { Value = 1 }",
ex.Message
);
}
[Fact]
public void DifferentTypes_Throws_NotEqual()
{
object expected = new IComparableActualThrower(1);
object actual = new IntWrapper(2);
Assert.NotEqual(expected, actual);
}
}
public class NotComparable
{
[Fact]
public void Equal()
{
var nco1 = new NonComparableObject();
var nco2 = new NonComparableObject();
var ex = Record.Exception(() => Assert.NotEqual(nco1, nco2));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not NonComparableObject { }" + Environment.NewLine +
"Actual: NonComparableObject { }",
ex.Message
);
}
[Fact]
public void NotEqual()
{
var nco1 = new NonComparableObject(false);
var nco2 = new NonComparableObject();
Assert.NotEqual(nco1, nco2);
}
}
public class Equatable
{
[Fact]
public void Equal()
{
var obj1 = new SpyEquatable();
var obj2 = new SpyEquatable();
var ex = Record.Exception(() => Assert.NotEqual(obj1, obj2));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not SpyEquatable { Equals__Called = True, Equals_Other = SpyEquatable { Equals__Called = False, Equals_Other = null } }" + Environment.NewLine +
"Actual: SpyEquatable { Equals__Called = False, Equals_Other = null }",
ex.Message
);
}
[Fact]
public void NotEqual()
{
var obj1 = new SpyEquatable(false);
var obj2 = new SpyEquatable();
Assert.NotEqual(obj1, obj2);
Assert.True(obj1.Equals__Called);
Assert.Same(obj2, obj1.Equals_Other);
}
[Fact]
public void SubClass_SubClass_Equal()
{
var expected = new EquatableSubClassA(1);
var actual = new EquatableSubClassB(1);
var ex = Record.Exception(() => Assert.NotEqual<EquatableBaseClass>(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not EquatableSubClassA { Value = 1 }" + Environment.NewLine +
"Actual: EquatableSubClassB { Value = 1 }",
ex.Message
);
}
[Fact]
public void SubClass_SubClass_NotEqual()
{
var expected = new EquatableSubClassA(1);
var actual = new EquatableSubClassB(2);
Assert.NotEqual<EquatableBaseClass>(expected, actual);
}
[Fact]
public void BaseClass_SubClass_Equal()
{
var expected = new EquatableBaseClass(1);
var actual = new EquatableSubClassA(1);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not EquatableBaseClass { Value = 1 }" + Environment.NewLine +
"Actual: EquatableSubClassA { Value = 1 }",
ex.Message
);
}
[Fact]
public void BaseClass_SubClass_NotEqual()
{
var expected = new EquatableBaseClass(1);
var actual = new EquatableSubClassA(2);
Assert.NotEqual(expected, actual);
}
[Fact]
public void SubClass_BaseClass_Equal()
{
var expected = new EquatableSubClassA(1);
var actual = new EquatableBaseClass(1);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not EquatableSubClassA { Value = 1 }" + Environment.NewLine +
"Actual: EquatableBaseClass { Value = 1 }",
ex.Message
);
}
[Fact]
public void SubClass_BaseClass_NotEqual()
{
var expected = new EquatableSubClassA(1);
var actual = new EquatableBaseClass(2);
Assert.NotEqual(expected, actual);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void DifferentTypes_ImplicitImplementation_Equal()
{
object expected = new ImplicitIEquatableExpected(1);
object actual = new IntWrapper(1);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not ImplicitIEquatableExpected { Value = 1 }" + Environment.NewLine +
"Actual: IntWrapper { Value = 1 }",
ex.Message
);
}
[Fact]
public void DifferentTypes_ImplicitImplementation_NotEqual()
{
object expected = new ImplicitIEquatableExpected(1);
object actual = new IntWrapper(2);
Assert.NotEqual(expected, actual);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void DifferentTypes_ExplicitImplementation_Equal()
{
object expected = new ExplicitIEquatableExpected(1);
object actual = new IntWrapper(1);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not ExplicitIEquatableExpected { Value = 1 }" + Environment.NewLine +
"Actual: IntWrapper { Value = 1 }",
ex.Message
);
}
[Fact]
public void DifferentTypes_ExplicitImplementation_NotEqual()
{
object expected = new ExplicitIEquatableExpected(1);
object actual = new IntWrapper(2);
Assert.NotEqual(expected, actual);
}
}
public class StructuralEquatable
{
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void Equal()
{
var expected = new Tuple<StringWrapper>(new StringWrapper("a"));
var actual = new Tuple<StringWrapper>(new StringWrapper("a"));
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not Tuple (StringWrapper { Value = \"a\" })" + Environment.NewLine +
"Actual: Tuple (StringWrapper { Value = \"a\" })",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, actual));
assertFailure(() => Assert.NotEqual(expected, (IStructuralEquatable)actual));
assertFailure(() => Assert.NotEqual(expected, (object)actual));
}
[Fact]
public void NotEqual()
{
var expected = new Tuple<StringWrapper>(new StringWrapper("a"));
var actual = new Tuple<StringWrapper>(new StringWrapper("b"));
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (IStructuralEquatable)actual);
Assert.NotEqual(expected, (object)actual);
}
[Fact]
public void ExpectedNull_ActualNull()
{
var expected = new Tuple<StringWrapper?>(null);
var actual = new Tuple<StringWrapper?>(null);
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not Tuple (null)" + Environment.NewLine +
"Actual: Tuple (null)",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, actual));
assertFailure(() => Assert.NotEqual(expected, (IStructuralEquatable)actual));
assertFailure(() => Assert.NotEqual(expected, (object)actual));
}
[Fact]
public void ExpectedNull_ActualNonNull()
{
var expected = new Tuple<StringWrapper?>(null);
var actual = new Tuple<StringWrapper?>(new StringWrapper("a"));
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (IStructuralEquatable)actual);
Assert.NotEqual(expected, (object)actual);
}
[Fact]
public void ExpectedNonNull_ActualNull()
{
var expected = new Tuple<StringWrapper?>(new StringWrapper("a"));
var actual = new Tuple<StringWrapper?>(null);
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (IStructuralEquatable)actual);
Assert.NotEqual(expected, (object)actual);
}
}
public class Collections
{
[Fact]
public void IReadOnlyCollection_IEnumerable_Equal()
{
var expected = new string[] { "foo", "bar" };
var actual = new ReadOnlyCollection<string>(expected);
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Collections are equal" + Environment.NewLine +
"Expected: Not string[] [\"foo\", \"bar\"]" + Environment.NewLine +
"Actual: ReadOnlyCollection<string> [\"foo\", \"bar\"]",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, (IReadOnlyCollection<string>)actual));
assertFailure(() => Assert.NotEqual(expected, (object)actual));
}
[Fact]
public void IReadOnlyCollection_IEnumerable_NotEqual()
{
var expected = new string[] { "foo", "bar" };
var actual = new ReadOnlyCollection<string>(new[] { "bar", "foo" });
Assert.NotEqual(expected, (IReadOnlyCollection<string>)actual);
Assert.NotEqual(expected, (object)actual);
}
[Fact]
public void CollectionDepth_Equal()
{
var x = new List<object> { new List<object> { new List<object> { 1 } } };
var y = new List<object> { new List<object> { new List<object> { 1 } } };
var ex = Record.Exception(() => Assert.NotEqual(x, y));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Collections are equal" + Environment.NewLine +
"Expected: Not [[[1]]]" + Environment.NewLine +
"Actual: [[[1]]]",
ex.Message
);
}
[Fact]
public void CollectionDepth_NotEqual()
{
var x = new List<object> { new List<object> { new List<object> { 1 } } };
var y = new List<object> { new List<object> { new List<object> { 2 } } };
Assert.NotEqual(x, y);
}
[Fact]
public void StringArray_ObjectArray_Equal()
{
var expected = new string[] { "foo", "bar" };
var actual = new object[] { "foo", "bar" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Collections are equal" + Environment.NewLine +
"Expected: Not string[] [\"foo\", \"bar\"]" + Environment.NewLine +
"Actual: object[] [\"foo\", \"bar\"]",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, actual));
assertFailure(() => Assert.NotEqual(expected, (object)actual));
}
[Fact]
public void StringArray_ObjectArray_NotEqual()
{
var expected = new string[] { "foo", "bar" };
var actual = new object[] { "foo", "baz" };
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (object)actual);
}
[Fact]
public void MultidimensionalArrays_Equal()
{
var expected = new int[,] { { 1 }, { 2 } };
var actual = new int[,] { { 1 }, { 2 } };
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
// TODO: Would be better to have formatting that preserves the ranks instead of
// flattening, which happens because multi-dimensional arrays enumerate flatly
Assert.Equal<object>(
"Assert.NotEqual() Failure: Collections are equal" + Environment.NewLine +
"Expected: Not [1, 2]" + Environment.NewLine +
"Actual: [1, 2]",
ex.Message
);
}
[Fact]
public void MultidimensionalArrays_NotEqual()
{
var expected = new int[,] { { 1, 2 } };
var actual = new int[,] { { 1 }, { 2 } };
Assert.NotEqual(expected, actual);
}
[Fact]
public void NonZeroBoundedArrays_Equal()
{
var expected = Array.CreateInstance(typeof(int), new[] { 1 }, new[] { 1 });
expected.SetValue(42, 1);
var actual = Array.CreateInstance(typeof(int), new[] { 1 }, new[] { 1 });
actual.SetValue(42, 1);
var ex = Record.Exception(() => Assert.NotEqual(expected, (object)actual));
Assert.IsType<NotEqualException>(ex);
// TODO: Would be better to have formatting that shows the non-zero bounds
Assert.Equal(
"Assert.NotEqual() Failure: Collections are equal" + Environment.NewLine +
"Expected: Not [42]" + Environment.NewLine +
"Actual: [42]",
ex.Message
);
}
[Fact]
public void NonZeroBoundedArrays_NotEqual()
{
var expected = Array.CreateInstance(typeof(int), new[] { 1 }, new[] { 1 });
expected.SetValue(42, 1);
var actual = Array.CreateInstance(typeof(int), new[] { 1 }, new[] { 0 });
actual.SetValue(42, 0);
Assert.NotEqual(expected, actual);
}
[Fact]
public void CollectionWithIEquatable_Equal()
{
var expected = new EnumerableEquatable<int> { 42, 2112 };
var actual = new EnumerableEquatable<int> { 2112, 42 };
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Collections are equal" + Environment.NewLine +
"Expected: Not [42, 2112]" + Environment.NewLine +
"Actual: [2112, 42]",
ex.Message
);
}
[Fact]
public void CollectionWithIEquatable_NotEqual()
{
var expected = new EnumerableEquatable<int> { 42, 2112 };
var actual = new EnumerableEquatable<int> { 2112, 2600 };
Assert.NotEqual(expected, actual);
}
public sealed class EnumerableEquatable<T> :
IEnumerable<T>, IEquatable<EnumerableEquatable<T>>
{
List<T> values = new();
public void Add(T value) => values.Add(value);
public bool Equals(EnumerableEquatable<T>? other)
{
if (other == null)
return false;
return !values.Except(other.values).Any() && !other.values.Except(values).Any();
}
public IEnumerator<T> GetEnumerator() => values.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
public class Dictionaries
{
[Fact]
public void SameTypes_Equal()
{
var expected = new Dictionary<string, string> { ["foo"] = "bar" };
var actual = new Dictionary<string, string> { ["foo"] = "bar" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Dictionaries are equal" + Environment.NewLine +
"Expected: Not [[\"foo\"] = \"bar\"]" + Environment.NewLine +
"Actual: [[\"foo\"] = \"bar\"]",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, actual));
assertFailure(() => Assert.NotEqual(expected, (IDictionary)actual));
assertFailure(() => Assert.NotEqual(expected, (object)actual));
}
[Fact]
public void SameTypes_NotEqual()
{
var expected = new Dictionary<string, string> { ["foo"] = "bar" };
var actual = new Dictionary<string, string> { ["foo"] = "baz" };
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (IDictionary)actual);
Assert.NotEqual(expected, (object)actual);
}
[Fact]
public void DifferentTypes_Equal()
{
var expected = new Dictionary<string, string> { ["foo"] = "bar" };
var actual = new ConcurrentDictionary<string, string>(expected);
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Collections are equal" + Environment.NewLine +
"Expected: Not Dictionary<string, string> [[\"foo\"] = \"bar\"]" + Environment.NewLine +
"Actual: ConcurrentDictionary<string, string> [[\"foo\"] = \"bar\"]",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, (IDictionary)actual));
assertFailure(() => Assert.NotEqual(expected, (object)actual));
}
[Fact]
public void DifferentTypes_NotEqual()
{
var expected = new Dictionary<string, string> { ["foo"] = "bar" };
var actual = new ConcurrentDictionary<string, string> { ["foo"] = "baz" };
Assert.NotEqual(expected, (IDictionary)actual);
Assert.NotEqual(expected, (object)actual);
}
[Fact]
public void NullValue_Equal()
{
var expected = new Dictionary<string, int?> { { "two", null } };
var actual = new Dictionary<string, int?> { { "two", null } };
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Dictionaries are equal" + Environment.NewLine +
"Expected: Not [[\"two\"] = null]" + Environment.NewLine +
"Actual: [[\"two\"] = null]",
ex.Message
);
}
[Fact]
public void NullValue_NotEqual()
{
var expected = new Dictionary<string, int?> { { "two", null } };
var actual = new Dictionary<string, int?> { { "two", 1 } };
Assert.NotEqual(expected, actual);
}
}
public class HashSets
{
[Fact]
public static void InOrder_Equal()
{
var expected = new HashSet<int> { 1, 2, 3 };
var actual = new HashSet<int> { 1, 2, 3 };
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: HashSets are equal" + Environment.NewLine +
"Expected: Not [1, 2, 3]" + Environment.NewLine +
"Actual: [1, 2, 3]",
ex.Message
);
}
[Fact]
public static void InOrder_NotEqual()
{
var expected = new HashSet<int> { 1, 2, 3 };
var actual = new HashSet<int> { 1, 2, 4 };
Assert.NotEqual(expected, actual);
}
[Fact]
public static void OutOfOrder_Equal()
{
var expected = new HashSet<int> { 1, 2, 3 };
var actual = new HashSet<int> { 2, 3, 1 };
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: HashSets are equal" + Environment.NewLine +
"Expected: Not [1, 2, 3]" + Environment.NewLine +
"Actual: [2, 3, 1]",
ex.Message
);
}
[Fact]
public static void OutOfOrder_NotEqual()
{
var expected = new HashSet<int> { 1, 2, 3 };
var actual = new HashSet<int> { 2, 4, 1 };
Assert.NotEqual(expected, actual);
}
[Fact]
public void DifferentTypes_Equal()
{
var expected = new HashSet<string> { "bar", "foo" };
var actual = new SortedSet<string> { "foo", "bar" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Sets are equal" + Environment.NewLine +
"Expected: Not HashSet<string> [\"bar\", \"foo\"]" + Environment.NewLine +
"Actual: SortedSet<string> [\"bar\", \"foo\"]",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, (ISet<string>)actual));
#pragma warning disable xUnit2027
assertFailure(() => Assert.NotEqual(expected, (object)actual));
#pragma warning restore xUnit2027
}
[Fact]
public void DifferentTypes_NotEqual()
{
object expected = new HashSet<int> { 42 };
object actual = new HashSet<long> { 42L };
Assert.NotEqual(expected, actual);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void ComparerFunc_Throws()
{
var expected = new HashSet<string> { "bar" };
var actual = new HashSet<string> { "baz" };
#pragma warning disable xUnit2026
var ex = Record.Exception(() => Assert.NotEqual(expected, actual, (string l, string r) => false));
#pragma warning restore xUnit2026
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: During comparison of two collections, GetHashCode was called, but only a comparison function was provided. This typically indicates trying to compare two sets with an item comparison function, which is not supported. For more information, see https://xunit.net/docs/hash-sets-vs-linear-containers",
ex.Message
);
}
}
public class Sets
{
[Fact]
public void InOrder_Equal()
{
var expected = new NonGenericSet { "bar", "foo" };
var actual = new NonGenericSet { "bar", "foo" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Sets are equal" + Environment.NewLine +
"Expected: Not [\"bar\", \"foo\"]" + Environment.NewLine +
"Actual: [\"bar\", \"foo\"]",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, actual));
assertFailure(() => Assert.NotEqual(expected, (ISet<string>)actual));
#pragma warning disable xUnit2027
assertFailure(() => Assert.NotEqual(expected, (object)actual));
#pragma warning restore xUnit2027
}
[Fact]
public void InOrder_NotEqual()
{
var expected = new NonGenericSet { "bar", "foo" };
var actual = new NonGenericSet { "bar", "baz" };
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (ISet<string>)actual);
#pragma warning disable xUnit2027
Assert.NotEqual(expected, (object)actual);
#pragma warning restore xUnit2027
}
[Fact]
public void OutOfOrder_Equal()
{
var expected = new NonGenericSet { "bar", "foo" };
var actual = new NonGenericSet { "foo", "bar" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Sets are equal" + Environment.NewLine +
"Expected: Not [\"bar\", \"foo\"]" + Environment.NewLine +
"Actual: [\"foo\", \"bar\"]",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, actual));
assertFailure(() => Assert.NotEqual(expected, (ISet<string>)actual));
#pragma warning disable xUnit2027
assertFailure(() => Assert.NotEqual(expected, (object)actual));
#pragma warning restore xUnit2027
}
[Fact]
public void OutOfOrder_NotEqual()
{
var expected = new NonGenericSet { "bar", "foo" };
var actual = new NonGenericSet { "foo", "baz" };
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (ISet<string>)actual);
#pragma warning disable xUnit2027
Assert.NotEqual(expected, (object)actual);
#pragma warning restore xUnit2027
}
[Fact]
public void DifferentContents()
{
var expected = new NonGenericSet { "bar" };
var actual = new NonGenericSet { "bar", "foo" };
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (ISet<string>)actual);
#pragma warning disable xUnit2027
Assert.NotEqual(expected, (object)actual);
#pragma warning restore xUnit2027
}
[Fact]
public void DifferentTypes_Equal()
{
var expected = new NonGenericSet { "bar" };
var actual = new HashSet<string> { "bar" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Sets are equal" + Environment.NewLine +
"Expected: Not NonGenericSet [\"bar\"]" + Environment.NewLine +
"Actual: HashSet<string> [\"bar\"]",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, actual));
assertFailure(() => Assert.NotEqual(expected, (ISet<string>)actual));
#pragma warning disable xUnit2027
assertFailure(() => Assert.NotEqual(expected, (object)actual));
#pragma warning restore xUnit2027
}
[Fact]
public void DifferentTypes_NotEqual()
{
var expected = new NonGenericSet { "bar" };
var actual = new HashSet<string> { "baz" };
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (ISet<string>)actual);
#pragma warning disable xUnit2027
Assert.NotEqual(expected, (object)actual);
#pragma warning restore xUnit2027
}
[Fact]
public void TwoGenericSubClass_Equal()
{
var expected = new TwoGenericSet<string, int> { "foo", "bar" };
var actual = new TwoGenericSet<string, int> { "foo", "bar" };
void assertFailure(Action action)
{
var ex = Record.Exception(action);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Sets are equal" + Environment.NewLine +
"Expected: Not [\"foo\", \"bar\"]" + Environment.NewLine +
"Actual: [\"foo\", \"bar\"]",
ex.Message
);
}
assertFailure(() => Assert.NotEqual(expected, actual));
assertFailure(() => Assert.NotEqual(expected, (ISet<string>)actual));
#pragma warning disable xUnit2027
assertFailure(() => Assert.NotEqual(expected, (object)actual));
#pragma warning restore xUnit2027
}
[Fact]
public void TwoGenericSubClass_NotEqual()
{
var expected = new TwoGenericSet<string, int> { "foo", "bar" };
var actual = new TwoGenericSet<string, int> { "foo", "baz" };
Assert.NotEqual(expected, actual);
Assert.NotEqual(expected, (ISet<string>)actual);
#pragma warning disable xUnit2027
Assert.NotEqual(expected, (object)actual);
#pragma warning restore xUnit2027
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void ComparerFunc_Throws()
{
var expected = new NonGenericSet { "bar" };
var actual = new HashSet<string> { "baz" };
#pragma warning disable xUnit2026
var ex = Record.Exception(() => Assert.NotEqual(expected, actual, (string l, string r) => false));
#pragma warning restore xUnit2026
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: During comparison of two collections, GetHashCode was called, but only a comparison function was provided. This typically indicates trying to compare two sets with an item comparison function, which is not supported. For more information, see https://xunit.net/docs/hash-sets-vs-linear-containers",
ex.Message
);
}
}
public class Strings
{
[Fact]
public void Equal()
{
var ex = Record.Exception(() => Assert.NotEqual("actual", "actual"));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
@"Assert.NotEqual() Failure: Strings are equal" + Environment.NewLine +
@"Expected: Not ""actual""" + Environment.NewLine +
@"Actual: ""actual""",
ex.Message
);
}
[Fact]
public void NotEqual()
{
Assert.NotEqual("foo", "bar");
}
[Fact]
public void Truncation()
{
var ex = Record.Exception(
() => Assert.NotEqual(
"This is a long string so that we can test truncation behavior",
"This is a long string so that we can test truncation behavior"
)
);
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Strings are equal" + Environment.NewLine +
@"Expected: Not ""This is a long string so that we can test truncati""···" + Environment.NewLine +
@"Actual: ""This is a long string so that we can test truncati""···",
ex.Message
);
}
}
public class KeyValuePair
{
[Fact]
public void CollectionKeys_Equal()
{
// Different concrete collection types in the key slot, per https://github.com/xunit/xunit/issues/2850
var expected = new KeyValuePair<IEnumerable<string>, int>(new List<string> { "Key1", "Key2" }, 42);
var actual = new KeyValuePair<IEnumerable<string>, int>(new string[] { "Key1", "Key2" }, 42);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not [[\"Key1\", \"Key2\"]] = 42" + Environment.NewLine +
"Actual: [[\"Key1\", \"Key2\"]] = 42",
ex.Message
);
}
[Fact]
public void CollectionKeys_NotEqual()
{
// Different concrete collection types in the key slot, per https://github.com/xunit/xunit/issues/2850
var expected = new KeyValuePair<IEnumerable<string>, int>(new List<string> { "Key1", "Key2" }, 42);
var actual = new KeyValuePair<IEnumerable<string>, int>(new string[] { "Key1", "Key3" }, 42);
Assert.NotEqual(expected, actual);
}
[Fact]
public void CollectionValues_Equal()
{
// Different concrete collection types in the key slot, per https://github.com/xunit/xunit/issues/2850
var expected = new KeyValuePair<string, IEnumerable<string>>("Key1", new List<string> { "Value1a", "Value1b" });
var actual = new KeyValuePair<string, IEnumerable<string>>("Key1", new string[] { "Value1a", "Value1b" });
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not [\"Key1\"] = [\"Value1a\", \"Value1b\"]" + Environment.NewLine +
"Actual: [\"Key1\"] = [\"Value1a\", \"Value1b\"]",
ex.Message
);
}
[Fact]
public void CollectionValues_NotEqual()
{
// Different concrete collection types in the key slot, per https://github.com/xunit/xunit/issues/2850
var expected = new KeyValuePair<string, IEnumerable<string>>("Key1", new List<string> { "Value1a", "Value1b" });
var actual = new KeyValuePair<string, IEnumerable<string>>("Key1", new string[] { "Value1a", "Value2a" });
Assert.NotEqual(expected, actual);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void EquatableKeys_Equal()
{
var expected = new KeyValuePair<EquatableObject, int>(new() { Char = 'a' }, 42);
var actual = new KeyValuePair<EquatableObject, int>(new() { Char = 'a' }, 42);
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not [EquatableObject { Char = 'a' }] = 42" + Environment.NewLine +
"Actual: [EquatableObject { Char = 'a' }] = 42",
ex.Message
);
}
[Fact]
public void EquatableKeys_NotEqual()
{
var expected = new KeyValuePair<EquatableObject, int>(new() { Char = 'a' }, 42);
var actual = new KeyValuePair<EquatableObject, int>(new() { Char = 'b' }, 42);
Assert.NotEqual(expected, actual);
}
#if XUNIT_AOT
[Fact(Skip = "Not supported with AOT")]
#else
[Fact]
#endif
public void EquatableValues_Equal()
{
var expected = new KeyValuePair<string, EquatableObject>("Key1", new() { Char = 'a' });
var actual = new KeyValuePair<string, EquatableObject>("Key1", new() { Char = 'a' });
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not [\"Key1\"] = EquatableObject { Char = 'a' }" + Environment.NewLine +
"Actual: [\"Key1\"] = EquatableObject { Char = 'a' }",
ex.Message
);
}
[Fact]
public void EquatableValues_NotEqual()
{
var expected = new KeyValuePair<string, EquatableObject>("Key1", new() { Char = 'a' });
var actual = new KeyValuePair<string, EquatableObject>("Key1", new() { Char = 'b' });
Assert.NotEqual(expected, actual);
}
public class EquatableObject : IEquatable<EquatableObject>
{
public char Char { get; set; }
public bool Equals(EquatableObject? other) =>
other != null && other.Char == Char;
}
}
public class DoubleEnumerationPrevention
{
[Fact]
public static void EnumeratesOnlyOnce_Equal()
{
var expected = new RunOnceEnumerable<int>(new[] { 1, 2, 3, 4, 5 });
var actual = new RunOnceEnumerable<int>(new[] { 1, 2, 3, 4, 5 });
var ex = Record.Exception(() => Assert.NotEqual(expected, actual));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Collections are equal" + Environment.NewLine +
"Expected: Not [1, 2, 3, 4, 5]" + Environment.NewLine +
"Actual: [1, 2, 3, 4, 5]",
ex.Message
);
}
[Fact]
public static void EnumeratesOnlyOnce_NotEqual()
{
var expected = new RunOnceEnumerable<int>(new[] { 1, 2, 3, 4, 5 });
var actual = new RunOnceEnumerable<int>(new[] { 1, 2, 3, 4, 5, 6 });
Assert.NotEqual(expected, actual);
}
}
}
public class NotEqual_Decimal
{
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(0.11111M, 0.11444M, 2));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are equal" + Environment.NewLine +
$"Expected: Not {0.11M} (rounded from {0.11111})" + Environment.NewLine +
$"Actual: {0.11M} (rounded from {0.11444})",
ex.Message
);
}
[Fact]
public void NotEqual()
{
Assert.NotEqual(0.11111M, 0.11444M, 3);
}
}
public class NotEqual_Double
{
public class WithPrecision
{
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(0.11111, 0.11444, 2));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are within 2 decimal places" + Environment.NewLine +
$"Expected: Not {0.11:G17} (rounded from {0.11111:G17})" + Environment.NewLine +
$"Actual: {0.11:G17} (rounded from {0.11444:G17})",
ex.Message
);
}
[Fact]
public void NotEqual()
{
Assert.NotEqual(0.11111, 0.11444, 3);
}
}
public class WithMidPointRounding
{
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(10.565, 10.566, 2, MidpointRounding.AwayFromZero));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
$"Assert.NotEqual() Failure: Values are within 2 decimal places" + Environment.NewLine +
$"Expected: Not {10.57:G17} (rounded from {10.565:G17})" + Environment.NewLine +
$"Actual: {10.57:G17} (rounded from {10.566:G17})",
ex.Message
);
}
[Fact]
public void NotEqual()
{
Assert.NotEqual(0.11113, 0.11115, 4, MidpointRounding.ToEven);
}
}
public class WithTolerance
{
[Fact]
public void GuardClause()
{
var ex = Record.Exception(() => Assert.NotEqual(0.0, 1.0, double.NegativeInfinity));
var argEx = Assert.IsType<ArgumentException>(ex);
Assert.StartsWith("Tolerance must be greater than or equal to zero", ex.Message);
Assert.Equal("tolerance", argEx.ParamName);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(10.566, 10.565, 0.01));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
$"Assert.NotEqual() Failure: Values are within tolerance {0.01:G17}" + Environment.NewLine +
$"Expected: Not {10.566:G17}" + Environment.NewLine +
$"Actual: {10.565:G17}",
ex.Message
);
}
[Fact]
public void NotEqual()
{
Assert.NotEqual(0.11113, 0.11115, 0.00001);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NaN_Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(double.NaN, double.NaN, 1000.0));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
$"Assert.NotEqual() Failure: Values are within tolerance {1000.0:G17}" + Environment.NewLine +
$"Expected: Not {double.NaN}" + Environment.NewLine +
$"Actual: {double.NaN}",
ex.Message
);
}
[Fact]
public void NaN_NotEqual()
{
Assert.NotEqual(20210102.2208, double.NaN, 20000000.0);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void InfiniteTolerance_Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(double.MinValue, double.MaxValue, double.PositiveInfinity));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
$"Assert.NotEqual() Failure: Values are within tolerance {double.PositiveInfinity}" + Environment.NewLine +
$"Expected: Not {double.MinValue:G17}" + Environment.NewLine +
$"Actual: {double.MaxValue:G17}",
ex.Message
);
}
[Fact]
public void PositiveInfinity_NotEqual()
{
Assert.NotEqual(double.PositiveInfinity, 77.7, 1.0);
}
[Fact]
public void NegativeInfinity_NotEqual()
{
Assert.NotEqual(0.0, double.NegativeInfinity, 1.0);
}
}
}
public class NotEqual_Float
{
public class WithPrecision
{
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(0.11111f, 0.11444f, 2));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are within 2 decimal places" + Environment.NewLine +
$"Expected: Not {0.11:G9} (rounded from {0.11111f:G9})" + Environment.NewLine +
$"Actual: {0.11:G9} (rounded from {0.11444f:G9})",
ex.Message
);
}
[Fact]
public void NotEqual()
{
Assert.NotEqual(0.11111f, 0.11444f, 3);
}
}
public class WithMidPointRounding
{
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(10.5655f, 10.5666f, 2, MidpointRounding.AwayFromZero));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
"Assert.NotEqual() Failure: Values are within 2 decimal places" + Environment.NewLine +
$"Expected: Not {10.57:G9} (rounded from {10.5655f:G9})" + Environment.NewLine +
$"Actual: {10.57:G9} (rounded from {10.5666f:G9})",
ex.Message
);
}
[Fact]
public void NotEqual()
{
Assert.NotEqual(0.111133f, 0.111155f, 4, MidpointRounding.ToEven);
}
}
public class WithTolerance
{
[Fact]
public void GuardClause()
{
var ex = Record.Exception(() => Assert.NotEqual(0.0f, 1.0f, float.NegativeInfinity));
var argEx = Assert.IsType<ArgumentException>(ex);
Assert.StartsWith("Tolerance must be greater than or equal to zero", ex.Message);
Assert.Equal("tolerance", argEx.ParamName);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(10.569f, 10.562f, 0.01f));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
$"Assert.NotEqual() Failure: Values are within tolerance {0.01f:G9}" + Environment.NewLine +
$"Expected: Not {10.569f:G9}" + Environment.NewLine +
$"Actual: {10.562f:G9}",
ex.Message
);
}
[Fact]
public void NotEqual()
{
Assert.NotEqual(0.11113f, 0.11115f, 0.00001f);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void NaN_Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(float.NaN, float.NaN, 1000.0f));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
$"Assert.NotEqual() Failure: Values are within tolerance {1000.0f:G9}" + Environment.NewLine +
"Expected: Not NaN" + Environment.NewLine +
"Actual: NaN",
ex.Message
);
}
[Fact]
public void NaN_NotEqual()
{
Assert.NotEqual(20210102.2208f, float.NaN, 20000000.0f);
}
#if XUNIT_AOT
[Fact]
#else
[CulturedFact]
#endif
public void InfiniteTolerance_Equal()
{
var ex = Record.Exception(() => Assert.NotEqual(float.MinValue, float.MaxValue, float.PositiveInfinity));
Assert.IsType<NotEqualException>(ex);
Assert.Equal(
$"Assert.NotEqual() Failure: Values are within tolerance {float.PositiveInfinity}" + Environment.NewLine +
$"Expected: Not {float.MinValue:G9}" + Environment.NewLine +
$"Actual: {float.MaxValue:G9}",
ex.Message
);
}
[Fact]
public void PositiveInfinity_NotEqual()
{
Assert.NotEqual(float.PositiveInfinity, 77.7f, 1.0f);
}
[Fact]
public void NegativeInfinity_NotEqual()
{
Assert.NotEqual(0.0f, float.NegativeInfinity, 1.0f);
}
}
}
public class NotStrictEqual
{
[Fact]
public static void Equal()
{
var ex = Record.Exception(() => Assert.NotStrictEqual("actual", "actual"));
Assert.IsType<NotStrictEqualException>(ex);
Assert.Equal(
"Assert.NotStrictEqual() Failure: Values are equal" + Environment.NewLine +
@"Expected: Not ""actual""" + Environment.NewLine +
@"Actual: ""actual""",
ex.Message
);
}
[Fact]
public static void NotEqual_Strings()
{
Assert.NotStrictEqual("bob", "jim");
}
[Fact]
public static void NotEqual_Classes()
{
Assert.NotStrictEqual(new EnumerableClass("ploeh"), new EnumerableClass("fnaah"));
}
[Fact]
public static void DifferentTypes_Equal()
{
var ex = Record.Exception(() => Assert.NotStrictEqual(new DerivedClass(), new BaseClass()));
Assert.IsType<NotStrictEqualException>(ex);
Assert.Equal(
"Assert.NotStrictEqual() Failure: Values are equal" + Environment.NewLine +
"Expected: Not DerivedClass { }" + Environment.NewLine +
"Actual: BaseClass { }",
ex.Message
);
}
}
public class StrictEqual
{
[Fact]
public static void Equal()
{
#pragma warning disable xUnit2006 // Do not use invalid string equality check
Assert.StrictEqual("actual", "actual");
#pragma warning restore xUnit2006 // Do not use invalid string equality check
}
[Fact]
public static void NotEqual_Strings()
{
#pragma warning disable xUnit2006 // Do not use invalid string equality check
var ex = Record.Exception(() => Assert.StrictEqual("bob", "jim"));
#pragma warning restore xUnit2006 // Do not use invalid string equality check
Assert.IsType<StrictEqualException>(ex);
Assert.Equal(
"Assert.StrictEqual() Failure: Values differ" + Environment.NewLine +
@"Expected: ""bob""" + Environment.NewLine +
@"Actual: ""jim""",
ex.Message
);
}
[Fact]
public static void NotEqual_Classes()
{
var ex = Record.Exception(() => Assert.StrictEqual(new EnumerableClass("ploeh"), new EnumerableClass("fnaah")));
Assert.IsType<StrictEqualException>(ex);
Assert.Equal(
"Assert.StrictEqual() Failure: Values differ" + Environment.NewLine +
$"Expected: [{ArgumentFormatter.Ellipsis}]" + Environment.NewLine +
$"Actual: [{ArgumentFormatter.Ellipsis}]",
ex.Message
);
}
[Fact]
public static void DifferentTypes_Equal()
{
Assert.StrictEqual(new DerivedClass(), new BaseClass());
}
}
class BaseClass { }
class DerivedClass : BaseClass
{
public override bool Equals(object? obj) =>
obj is BaseClass || base.Equals(obj);
public override int GetHashCode() => 0;
}
class EnumerableClass : IEnumerable<BaseClass>
{
private readonly IEnumerable<BaseClass> bars;
public EnumerableClass(string _, params BaseClass[] bars)
{
this.bars = bars;
}
public IEnumerator<BaseClass> GetEnumerator() => bars.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
class MultiComparable : IComparable
{
public int Value { get; }
public MultiComparable(int value)
{
Value = value;
}
public int CompareTo(object? obj)
{
if (obj is int intObj)
return Value.CompareTo(intObj);
else if (obj is MultiComparable multiObj)
return Value.CompareTo(multiObj.Value);
throw new InvalidOperationException();
}
}
class ComparableBaseClass : IComparable<ComparableBaseClass>
{
public int Value { get; }
public ComparableBaseClass(int value)
{
Value = value;
}
public int CompareTo(ComparableBaseClass? other) => Value.CompareTo(other!.Value);
}
class ComparableSubClassA : ComparableBaseClass
{
public ComparableSubClassA(int value) : base(value)
{ }
}
class ComparableSubClassB : ComparableBaseClass
{
public ComparableSubClassB(int value) : base(value)
{ }
}
class ComparableThrower : IComparable<ComparableThrower>
{
public int Value { get; }
public ComparableThrower(int value)
{
Value = value;
}
public int CompareTo(ComparableThrower? other)
{
throw new InvalidOperationException();
}
public override bool Equals(object? obj) => Value == ((ComparableThrower?)obj)!.Value;
public override int GetHashCode() => Value;
}
class EquatableBaseClass : IEquatable<EquatableBaseClass>
{
public int Value { get; }
public EquatableBaseClass(int value)
{
Value = value;
}
public bool Equals(EquatableBaseClass? other) => Value == other!.Value;
}
class EquatableSubClassA : EquatableBaseClass
{
public EquatableSubClassA(int value) : base(value) { }
}
class EquatableSubClassB : EquatableBaseClass
{
public EquatableSubClassB(int value) : base(value) { }
}
class StringWrapper : IEquatable<StringWrapper>
{
public string Value { get; }
public StringWrapper(string value)
{
Value = value;
}
bool IEquatable<StringWrapper>.Equals(StringWrapper? other) => Value == other!.Value;
}
class NonGenericSet : HashSet<string> { }
class TwoGenericSet<T, U> : HashSet<T> { }
class ImplicitIEquatableExpected : IEquatable<IntWrapper>
{
public int Value { get; }
public ImplicitIEquatableExpected(int value)
{
Value = value;
}
public bool Equals(IntWrapper? other) => Value == other!.Value;
}
class ExplicitIEquatableExpected : IEquatable<IntWrapper>
{
public int Value { get; }
public ExplicitIEquatableExpected(int value)
{
Value = value;
}
bool IEquatable<IntWrapper>.Equals(IntWrapper? other) => Value == other!.Value;
}
class ImplicitIComparableExpected : IComparable<IntWrapper>
{
public int Value { get; }
public ImplicitIComparableExpected(int value)
{
Value = value;
}
public int CompareTo(IntWrapper? other) => Value.CompareTo(other!.Value);
}
class ExplicitIComparableActual : IComparable<IntWrapper>
{
public int Value { get; }
public ExplicitIComparableActual(int value)
{
Value = value;
}
int IComparable<IntWrapper>.CompareTo(IntWrapper? other) => Value.CompareTo(other!.Value);
}
class IComparableActualThrower : IComparable<IntWrapper>
{
public int Value { get; }
public IComparableActualThrower(int value)
{
Value = value;
}
public int CompareTo(IntWrapper? other)
{
throw new NotSupportedException();
}
public override bool Equals(object? obj) => Value == ((IntWrapper?)obj)!.Value;
public override int GetHashCode() => Value;
}
class IntWrapper
{
public int Value { get; }
public IntWrapper(int value)
{
Value = value;
}
}
class SpyComparable : IComparable
{
readonly int result;
public bool CompareCalled;
public SpyComparable(int result)
{
this.result = result;
}
public int CompareTo(object? obj)
{
CompareCalled = true;
return result;
}
}
class SpyComparable_Generic : IComparable<SpyComparable_Generic>
{
int result;
public bool CompareCalled;
public SpyComparable_Generic(int result = 0)
{
this.result = result;
}
public int CompareTo(SpyComparable_Generic? other)
{
CompareCalled = true;
return result;
}
}
class SpyEquatable : IEquatable<SpyEquatable>
{
bool result;
public bool Equals__Called;
public SpyEquatable? Equals_Other;
public SpyEquatable(bool result = true)
{
this.result = result;
}
public bool Equals(SpyEquatable? other)
{
Equals__Called = true;
Equals_Other = other;
return result;
}
}
class NonComparableObject
{
bool result;
public NonComparableObject(bool result = true)
{
this.result = result;
}
public override bool Equals(object? obj) => result;
public override int GetHashCode() => 42;
}
sealed class RunOnceEnumerable<T> : IEnumerable<T>
{
private bool _called;
public RunOnceEnumerable(IEnumerable<T> source)
{
Source = source;
}
public IEnumerable<T> Source { get; }
public IEnumerator<T> GetEnumerator()
{
Assert.False(_called, "GetEnumerator() was called more than once");
_called = true;
return Source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
|