From 546d33925c0826807fc947927bd5203d350d2459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Thu, 14 May 2026 22:09:36 +0200 Subject: [PATCH 1/6] Add Assert.AllItemsAreNotNull/AreUnique/AreInstancesOfType Mirror the CollectionAssert.AllItems* APIs onto Assert per RFC 012. Adds: - Assert.AllItemsAreNotNull (generic + non-generic IEnumerable) - Assert.AllItemsAreUnique (generic + non-generic, both with optional comparer) - Assert.AllItemsAreInstancesOfType (generic + non-generic Type) All produce structured assertion messages including evidence (null indices / duplicates / mismatches), source collection, optional comparer, and expression-based call site. Notes: - NonGenericEqualityComparerAdapter is duplicated with PR #8234 (Assert.IsSubsetOf); will be deduped post-merge. --- .../Assert.AllItemsAreInstancesOfType.cs | 147 +++++ .../Assertions/Assert.AllItemsAreNotNull.cs | 105 ++++ .../Assertions/Assert.AllItemsAreUnique.cs | 229 ++++++++ .../PublicAPI/PublicAPI.Unshipped.txt | 8 + .../Resources/FrameworkMessages.resx | 9 + .../Resources/xlf/FrameworkMessages.cs.xlf | 15 + .../Resources/xlf/FrameworkMessages.de.xlf | 15 + .../Resources/xlf/FrameworkMessages.es.xlf | 15 + .../Resources/xlf/FrameworkMessages.fr.xlf | 15 + .../Resources/xlf/FrameworkMessages.it.xlf | 15 + .../Resources/xlf/FrameworkMessages.ja.xlf | 15 + .../Resources/xlf/FrameworkMessages.ko.xlf | 15 + .../Resources/xlf/FrameworkMessages.pl.xlf | 15 + .../Resources/xlf/FrameworkMessages.pt-BR.xlf | 15 + .../Resources/xlf/FrameworkMessages.ru.xlf | 15 + .../Resources/xlf/FrameworkMessages.tr.xlf | 15 + .../xlf/FrameworkMessages.zh-Hans.xlf | 15 + .../xlf/FrameworkMessages.zh-Hant.xlf | 15 + .../Assertions/AssertTests.AllItems.cs | 508 ++++++++++++++++++ 19 files changed, 1201 insertions(+) create mode 100644 src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs create mode 100644 src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreNotNull.cs create mode 100644 src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs create mode 100644 test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs b/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs new file mode 100644 index 0000000000..e3b7b186ff --- /dev/null +++ b/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs @@ -0,0 +1,147 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +/// +/// A collection of helper classes to test various conditions within +/// unit tests. If the condition being tested is not met, an exception +/// is thrown. +/// +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters +#pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads +public sealed partial class Assert +{ + #region AllItemsAreInstancesOfType + + /// + /// Tests whether all elements in the specified collection are instances of the + /// expected type and throws an exception if the expected type is not in the + /// inheritance hierarchy of one or more of the elements. + /// + /// + /// The collection containing elements the test expects to be of the specified type. + /// + /// + /// The expected type of each element of . + /// + /// + /// The message to include in the exception when an element in + /// is not an instance of . The message is shown in + /// test results. + /// + /// + /// The syntactic expression of collection as given by the compiler via caller argument expression. + /// Users shouldn't pass a value for this parameter. + /// + /// + /// The syntactic expression of expectedType as given by the compiler via caller argument expression. + /// Users shouldn't pass a value for this parameter. + /// + /// + /// Thrown if or is null, + /// or some elements of do not inherit from / implement + /// . + /// + public static void AllItemsAreInstancesOfType([NotNull] IEnumerable? collection, [NotNull] Type? expectedType, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "", [CallerArgumentExpression(nameof(expectedType))] string expectedTypeExpression = "") + { + CheckParameterNotNull(collection, "Assert.AllItemsAreInstancesOfType", "collection"); + CheckParameterNotNull(expectedType, "Assert.AllItemsAreInstancesOfType", "expectedType"); + AllItemsAreInstancesOfTypeImpl(collection, expectedType, genericTypeArgumentName: null, message, collectionExpression, expectedTypeExpression); + } + + /// + /// Tests whether all elements in the specified collection are instances of the + /// expected type and throws an exception if the expected type is not in the + /// inheritance hierarchy of one or more of the elements. + /// + /// The type each element of is expected to be. + /// + /// The collection containing elements the test expects to be of the specified type. + /// + /// + /// The message to include in the exception when an element in + /// is not an instance of . The message is shown in + /// test results. + /// + /// + /// The syntactic expression of collection as given by the compiler via caller argument expression. + /// Users shouldn't pass a value for this parameter. + /// + /// + /// Thrown if is null or some elements of + /// do not inherit from / implement . + /// + public static void AllItemsAreInstancesOfType([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + { + CheckParameterNotNull(collection, "Assert.AllItemsAreInstancesOfType", "collection"); + AllItemsAreInstancesOfTypeImpl(collection, typeof(TExpected), genericTypeArgumentName: "TExpected", message, collectionExpression, expectedTypeExpression: null); + } + + private static void AllItemsAreInstancesOfTypeImpl(IEnumerable collection, Type expectedType, string? genericTypeArgumentName, string? message, string collectionExpression, string? expectedTypeExpression) + { + List snapshot = [.. collection.Cast()]; + List? mismatchIndices = null; + List? mismatchTypes = null; + for (int i = 0; i < snapshot.Count; i++) + { + object? element = snapshot[i]; + if (element is not null && !expectedType.IsInstanceOfType(element)) + { + mismatchIndices ??= []; + mismatchTypes ??= []; + mismatchIndices.Add(i); + mismatchTypes.Add(element.GetType()); + } + } + + if (mismatchIndices is not null) + { + ReportAssertAllItemsAreInstancesOfTypeFailed(snapshot, expectedType, mismatchIndices, mismatchTypes!, genericTypeArgumentName, message, collectionExpression, expectedTypeExpression); + } + } + + [DoesNotReturn] + private static void ReportAssertAllItemsAreInstancesOfTypeFailed(IEnumerable collection, Type expectedType, List mismatchIndices, List mismatchTypes, string? genericTypeArgumentName, string? message, string collectionExpression, string? expectedTypeExpression) + { + string collectionText = AssertionValueRenderer.RenderValue(collection); + string expectedTypeText = $"{expectedType} (or derived)"; + + StringBuilder mismatchesBuilder = new(); + mismatchesBuilder.Append('['); + for (int i = 0; i < mismatchIndices.Count; i++) + { + if (i > 0) + { + mismatchesBuilder.Append(", "); + } + + mismatchesBuilder.Append("index ").Append(mismatchIndices[i]).Append(": ").Append(mismatchTypes[i]); + } + + mismatchesBuilder.Append(']'); + + EvidenceBlock evidence = EvidenceBlock.Create() + .AddLine("expected type:", expectedTypeText) + .AddLine("mismatches:", mismatchesBuilder.ToString()) + .AddLine("collection:", collectionText); + + string assertionMethodName = genericTypeArgumentName is null + ? "Assert.AllItemsAreInstancesOfType" + : $"Assert.AllItemsAreInstancesOfType<{genericTypeArgumentName}>"; + + string? callSite = genericTypeArgumentName is null + ? FormatCallSiteExpression(assertionMethodName, collectionExpression, expectedTypeExpression!, "", "") + : FormatCallSiteExpression(assertionMethodName, collectionExpression, ""); + + StructuredAssertionMessage structured = new(FrameworkMessages.AllItemsAreInstancesOfTypeFailedSummary); + structured.WithUserMessage(message); + structured.WithEvidence(evidence); + structured.WithExpectedAndActual(expectedText: null, actualText: collectionText); + structured.WithCallSiteExpression(callSite); + + ReportAssertFailed(structured); + } + + #endregion // AllItemsAreInstancesOfType +} diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreNotNull.cs b/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreNotNull.cs new file mode 100644 index 0000000000..2f33ef5d91 --- /dev/null +++ b/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreNotNull.cs @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +/// +/// A collection of helper classes to test various conditions within +/// unit tests. If the condition being tested is not met, an exception +/// is thrown. +/// +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters +#pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads +public sealed partial class Assert +{ + #region AllItemsAreNotNull + + /// + /// Tests whether all items in the specified collection are non-null and throws + /// an exception if any element is null. + /// + /// + /// The collection in which to search for null elements. + /// + /// + /// The message to include in the exception when contains + /// a null element. The message is shown in test results. + /// + /// + /// The syntactic expression of collection as given by the compiler via caller argument expression. + /// Users shouldn't pass a value for this parameter. + /// + /// + /// Thrown if is null or contains at least one null element. + /// + public static void AllItemsAreNotNull([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + { + CheckParameterNotNull(collection, "Assert.AllItemsAreNotNull", "collection"); + AllItemsAreNotNullImpl(collection.Cast(), message, collectionExpression); + } + + /// + /// Tests whether all items in the specified collection are non-null and throws + /// an exception if any element is null. + /// + /// The type of the collection items. + /// + /// The collection in which to search for null elements. + /// + /// + /// The message to include in the exception when contains + /// a null element. The message is shown in test results. + /// + /// + /// The syntactic expression of collection as given by the compiler via caller argument expression. + /// Users shouldn't pass a value for this parameter. + /// + /// + /// Thrown if is null or contains at least one null element. + /// + public static void AllItemsAreNotNull([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + { + CheckParameterNotNull(collection, "Assert.AllItemsAreNotNull", "collection"); + AllItemsAreNotNullImpl(collection, message, collectionExpression); + } + + private static void AllItemsAreNotNullImpl(IEnumerable collection, string? message, string collectionExpression) + { + List snapshot = collection is List list ? list : [.. collection]; + List? nullIndices = null; + for (int i = 0; i < snapshot.Count; i++) + { + if (snapshot[i] is null) + { + nullIndices ??= []; + nullIndices.Add(i); + } + } + + if (nullIndices is not null) + { + ReportAssertAllItemsAreNotNullFailed(snapshot, nullIndices, message, collectionExpression); + } + } + + [DoesNotReturn] + private static void ReportAssertAllItemsAreNotNullFailed(IEnumerable collection, List nullIndices, string? message, string collectionExpression) + { + string collectionText = AssertionValueRenderer.RenderValue(collection); + string nullIndicesText = AssertionValueRenderer.RenderValue(nullIndices); + + EvidenceBlock evidence = EvidenceBlock.Create() + .AddLine("null indices:", nullIndicesText) + .AddLine("collection:", collectionText); + + StructuredAssertionMessage structured = new(FrameworkMessages.AllItemsAreNotNullFailedSummary); + structured.WithUserMessage(message); + structured.WithEvidence(evidence); + structured.WithExpectedAndActual(expectedText: null, actualText: collectionText); + structured.WithCallSiteExpression(FormatCallSiteExpression("Assert.AllItemsAreNotNull", collectionExpression, "")); + + ReportAssertFailed(structured); + } + + #endregion // AllItemsAreNotNull +} diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs b/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs new file mode 100644 index 0000000000..cec1215e3d --- /dev/null +++ b/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs @@ -0,0 +1,229 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestTools.UnitTesting; + +/// +/// A collection of helper classes to test various conditions within +/// unit tests. If the condition being tested is not met, an exception +/// is thrown. +/// +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters +#pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads +public sealed partial class Assert +{ + #region AllItemsAreUnique + + /// + /// Tests whether all items in the specified collection are unique and throws + /// an exception if any two elements in the collection are equal. + /// + /// The type of the collection items. + /// + /// The collection in which to search for duplicate elements. + /// + /// + /// The message to include in the exception when contains + /// at least one duplicate element. The message is shown in test results. + /// + /// + /// The syntactic expression of collection as given by the compiler via caller argument expression. + /// Users shouldn't pass a value for this parameter. + /// + /// + /// Thrown if is null or contains at least one duplicate element. + /// + public static void AllItemsAreUnique([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + { + CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); + AllItemsAreUniqueImpl(collection, EqualityComparer.Default, comparerName: null, message, collectionExpression); + } + + /// + /// Tests whether all items in the specified collection are unique using the + /// supplied and throws an exception if any two + /// elements in the collection are equal. + /// + /// The type of the collection items. + /// + /// The collection in which to search for duplicate elements. + /// + /// + /// The equality comparer to use when comparing elements. + /// + /// + /// The message to include in the exception when contains + /// at least one duplicate element. The message is shown in test results. + /// + /// + /// The syntactic expression of collection as given by the compiler via caller argument expression. + /// Users shouldn't pass a value for this parameter. + /// + /// + /// Thrown if is null or contains at least one duplicate element. + /// + public static void AllItemsAreUnique([NotNull] IEnumerable? collection, [NotNull] IEqualityComparer? comparer, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + { + CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); + CheckParameterNotNull(comparer, "Assert.AllItemsAreUnique", "comparer"); + AllItemsAreUniqueImpl(collection, comparer, comparer.GetType().Name, message, collectionExpression); + } + + /// + /// Tests whether all items in the specified collection are unique and throws + /// an exception if any two elements in the collection are equal. + /// + /// + /// The collection in which to search for duplicate elements. + /// + /// + /// The message to include in the exception when contains + /// at least one duplicate element. The message is shown in test results. + /// + /// + /// The syntactic expression of collection as given by the compiler via caller argument expression. + /// Users shouldn't pass a value for this parameter. + /// + /// + /// Thrown if is null or contains at least one duplicate element. + /// + public static void AllItemsAreUnique([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + { + CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); + AllItemsAreUniqueImpl(collection.Cast(), EqualityComparer.Default, comparerName: null, message, collectionExpression); + } + + /// + /// Tests whether all items in the specified collection are unique using the + /// supplied and throws an exception if any two + /// elements in the collection are equal. + /// + /// + /// The collection in which to search for duplicate elements. + /// + /// + /// The equality comparer to use when comparing elements. + /// + /// + /// The message to include in the exception when contains + /// at least one duplicate element. The message is shown in test results. + /// + /// + /// The syntactic expression of collection as given by the compiler via caller argument expression. + /// Users shouldn't pass a value for this parameter. + /// + /// + /// Thrown if is null or contains at least one duplicate element. + /// + public static void AllItemsAreUnique([NotNull] IEnumerable? collection, [NotNull] IEqualityComparer? comparer, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + { + CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); + CheckParameterNotNull(comparer, "Assert.AllItemsAreUnique", "comparer"); + AllItemsAreUniqueImpl(collection.Cast(), new NonGenericEqualityComparerAdapter(comparer), comparer.GetType().Name, message, collectionExpression); + } + +#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. + private static void AllItemsAreUniqueImpl(IEnumerable collection, IEqualityComparer comparer, string? comparerName, string? message, string collectionExpression) + { + List snapshot = collection is List list ? list : [.. collection]; + +#pragma warning disable IDE0028 // Collection initialization can be simplified - target-typed new with constructor argument is preferred over collection expression here + HashSet seen = new(comparer); +#pragma warning restore IDE0028 + + bool seenNull = false; + List? duplicates = null; + HashSet? duplicatesSeen = null; + bool nullDuplicateRecorded = false; + + foreach (T item in snapshot) + { + if (item is null) + { + if (!seenNull) + { + seenNull = true; + continue; + } + + if (!nullDuplicateRecorded) + { + duplicates ??= []; + duplicates.Add(default!); + nullDuplicateRecorded = true; + } + + continue; + } + + if (!seen.Add(item)) + { +#pragma warning disable IDE0028 + duplicatesSeen ??= new HashSet(comparer); +#pragma warning restore IDE0028 + if (duplicatesSeen.Add(item)) + { + duplicates ??= []; + duplicates.Add(item); + } + } + } + + if (duplicates is not null) + { + ReportAssertAllItemsAreUniqueFailed(snapshot, duplicates, comparerName, message, collectionExpression); + } + } +#pragma warning restore CS8714 + + [DoesNotReturn] + private static void ReportAssertAllItemsAreUniqueFailed(IEnumerable collection, List duplicates, string? comparerName, string? message, string collectionExpression) + { + string collectionText = AssertionValueRenderer.RenderValue(collection); + string duplicatesText = AssertionValueRenderer.RenderValue(duplicates); + + EvidenceBlock evidence = EvidenceBlock.Create() + .AddLine("duplicates:", duplicatesText) + .AddLine("collection:", collectionText); + + if (comparerName is not null) + { + evidence.AddLine("comparer:", comparerName); + } + + StructuredAssertionMessage structured = new(FrameworkMessages.AllItemsAreUniqueFailedSummary); + structured.WithUserMessage(message); + structured.WithEvidence(evidence); + structured.WithExpectedAndActual(expectedText: null, actualText: collectionText); + structured.WithCallSiteExpression(BuildCallSiteWithComparerForCollection("Assert.AllItemsAreUnique", collectionExpression, comparerName is not null)); + + ReportAssertFailed(structured); + } + + private static string? BuildCallSiteWithComparerForCollection(string assertionMethodName, string collectionExpression, bool hasComparer) + { + string? callSite = FormatCallSiteExpression(assertionMethodName, collectionExpression, ""); + if (callSite is null || !hasComparer) + { + return callSite; + } + + // FormatCallSiteExpression has no overload accepting a third argument expression; insert + // the placeholder so the rendered call-site reflects the overload that was actually invoked. + return string.Concat(callSite.Substring(0, callSite.Length - 1), ", )"); + } + + #endregion // AllItemsAreUnique + + private sealed class NonGenericEqualityComparerAdapter : IEqualityComparer + { + private readonly IEqualityComparer _comparer; + + public NonGenericEqualityComparerAdapter(IEqualityComparer comparer) + => _comparer = comparer; + + public new bool Equals(object? x, object? y) => _comparer.Equals(x, y); + + public int GetHashCode(object? obj) => obj is null ? 0 : _comparer.GetHashCode(obj); + } +} diff --git a/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt b/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt index cc143fac2e..cd3a63ec3a 100644 --- a/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt @@ -2,3 +2,11 @@ [MSTESTEXP]static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Scope() -> System.IDisposable! Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException.ActualText.get -> string? Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException.ExpectedText.get -> string? +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreInstancesOfType(System.Collections.IEnumerable? collection, System.Type? expectedType, string? message = "", string! collectionExpression = "", string! expectedTypeExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreInstancesOfType(System.Collections.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreNotNull(System.Collections.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreNotNull(System.Collections.Generic.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreUnique(System.Collections.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreUnique(System.Collections.IEnumerable? collection, System.Collections.IEqualityComparer? comparer, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreUnique(System.Collections.Generic.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreUnique(System.Collections.Generic.IEnumerable? collection, System.Collections.Generic.IEqualityComparer? comparer, string? message = "", string! collectionExpression = "") -> void diff --git a/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx b/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx index 691f3edab7..8f2b449887 100644 --- a/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx +++ b/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx @@ -420,4 +420,13 @@ Actual: {2} Expected value to not be null. + + Expected all items in collection to be non-null. + + + Expected all items in collection to be unique. + + + Expected all items in collection to be instances of the specified type. + diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf index 4ad5deac23..90883b9e16 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf @@ -12,11 +12,26 @@ Očekávaná kolekce obsahuje {1} výskyt(ů) <{2}>. Aktuální kolekce obsahuje {3} výskyt(ů). {0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} Byla nalezena duplicitní položka:<{1}>. {0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} Očekáváno:<{1}>. Aktuálně:<{2}>. {0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf index f61ee46c58..12d6076e36 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf @@ -12,11 +12,26 @@ Die erwartete Sammlung enthält {1} Vorkommen von <{2}>. Die tatsächliche Sammlung enthält {3} Vorkommen. {0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} Doppeltes Element gefunden: <{1}>. {0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} Erwartet:<{1}>. Tatsächlich:<{2}>. {0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf index 94a5797fc0..255a30cbf9 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf @@ -12,11 +12,26 @@ Apariciones que contiene la colección esperada: {1} de <{2}>. Apariciones que contiene la colección real: {3}. {0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} Se encontró un elemento duplicado:<{1}>. {0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} Se esperaba <{1}>, pero es <{2}>. {0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf index 00d78302f3..4cabcea255 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf @@ -12,11 +12,26 @@ La collection attendue contient {1} occurrence(s) de <{2}>. La collection réelle contient {3} occurrence(s). {0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} Un élément dupliqué a été trouvé : <{1}>. {0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} Attendu : <{1}>, Réel : <{2}>. {0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf index 80b0b1b715..86ffdd9aa6 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf @@ -12,11 +12,26 @@ La raccolta prevista contiene {1} occorrenza/e di <{2}>. La raccolta effettiva contiene {3} occorrenza/e. {0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} Rilevato elemento duplicato:<{1}>. {0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} Previsto:<{1}>. Effettivo:<{2}>. {0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf index ee5344f86b..e724769c2e 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf @@ -12,11 +12,26 @@ 予期されたコレクションでは、<{2}> が {1} 回発生します。実際のコレクションでは、{3} 回発生します。{0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} 重複する項目が見つかりました:<{1}>。{0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} <{1}> が必要ですが、<{2}> が指定されました。{0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf index e1d64ff123..c78fe91d9a 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf @@ -12,11 +12,26 @@ 필요한 컬렉션에 <{2}>은(는) {1}개가 포함되어야 하는데 실제 컬렉션에는 {3}개가 포함되어 있습니다. {0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} 중복된 항목이 있습니다. <{1}>. {0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} 예상 값: <{1}>. 실제 값: <{2}>. {0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf index b09f5eb893..aff015dc21 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf @@ -12,11 +12,26 @@ Oczekiwana kolekcja zawiera {1} wystąpień <{2}>. Bieżąca kolekcja zawiera {3} wystąpień. {0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} Znaleziono duplikat:<{1}>. {0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} Oczekiwana:<{1}>. Rzeczywista:<{2}>. {0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf index 3fdabfe37d..123529e2bf 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf @@ -12,11 +12,26 @@ A coleção esperada contém {1} ocorrência(s) de <{2}>. A coleção real contém {3} ocorrência(s). {0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} Item duplicado encontrado:<{1}>. {0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} Esperado:<{1}>. Real:<{2}>. {0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf index 8262985ee7..372cc841ee 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf @@ -12,11 +12,26 @@ Ожидаемый набор содержит следующее число событий <{2}>: {1}. Фактический набор содержит число событий: {3}. {0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} Обнаружен совпадающий элемент: <{1}>. {0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} Ожидается: <{1}>. Фактически: <{2}>. {0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf index 8420e144a3..8d1c20fbc7 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf @@ -12,11 +12,26 @@ Beklenen koleksiyon {1} <{2}> örneği içerir. Gerçek koleksiyon {3} örnek içerir. {0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} Yinelenen öğe bulundu:<{1}>. {0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} Beklenen:<{1}>. Gerçek:<{2}>. {0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf index 0b7558f104..030cf342f1 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf @@ -12,11 +12,26 @@ 所需集合包含 <{2}> 的 {1} 个匹配项。实际集合包含 {3} 个匹配项。{0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} 找到了重复项: <{1}>。{0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} 应为: <{1}>,实际为: <{2}>。{0} diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf index cc658d8057..46309a25bd 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf @@ -12,11 +12,26 @@ 預期在集合中包含 {1} 項 <{2}>,但實際的集合卻有 {3} 項。{0} + + Expected all items in collection to be instances of the specified type. + Expected all items in collection to be instances of the specified type. + + + + Expected all items in collection to be non-null. + Expected all items in collection to be non-null. + + Duplicate item found:<{1}>. {0} 找到重複的項目: <{1}>。{0} + + Expected all items in collection to be unique. + Expected all items in collection to be unique. + + Expected:<{1}>. Actual:<{2}>. {0} 預期: <{1}>。實際: <{2}>。{0} diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs new file mode 100644 index 0000000000..3269d87b62 --- /dev/null +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs @@ -0,0 +1,508 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections; + +using AwesomeAssertions; + +using TestFramework.ForTestingMSTest; + +namespace Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests; + +public partial class AssertTests : TestContainer +{ + #region AllItemsAreNotNull + + public void AllItemsAreNotNull_Generic_NoNulls_ShouldPass() + => Assert.AllItemsAreNotNull(new[] { "a", "b", "c" }); + + public void AllItemsAreNotNull_Generic_Empty_ShouldPass() + => Assert.AllItemsAreNotNull(Array.Empty()); + + public void AllItemsAreNotNull_Generic_ValueTypes_ShouldPass() + => Assert.AllItemsAreNotNull(new[] { 1, 2, 3 }); + + public void AllItemsAreNotNull_Generic_HasNull_ShouldFail() + { + Action action = () => Assert.AllItemsAreNotNull(new[] { "a", null, "b", null }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be non-null. + + null indices: [1, 3] + collection: ["a", null, "b", null] + + Assert.AllItemsAreNotNull(new[] { "a", null, "b", null }) + """); + } + + public void AllItemsAreNotNull_Generic_WithUserMessage_ShouldFail() + { + Action action = () => Assert.AllItemsAreNotNull(new[] { "a", null }, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be non-null. + User-provided message + + null indices: [1] + collection: ["a", null] + + Assert.AllItemsAreNotNull(new[] { "a", null }) + """); + } + + public void AllItemsAreNotNull_Generic_NullCollection_ShouldFail() + { + Action action = () => Assert.AllItemsAreNotNull((IEnumerable?)null); + action.Should().Throw() + .WithMessage("Assert.AllItemsAreNotNull failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AllItemsAreNotNull_NonGeneric_NoNulls_ShouldPass() + { + ArrayList list = ["a", "b", "c"]; + Assert.AllItemsAreNotNull(list); + } + + public void AllItemsAreNotNull_NonGeneric_HasNull_ShouldFail() + { + ArrayList list = ["a", null, "b"]; + Action action = () => Assert.AllItemsAreNotNull(list); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be non-null. + + null indices: [1] + collection: ["a", null, "b"] + + Assert.AllItemsAreNotNull(list) + """); + } + + public void AllItemsAreNotNull_NonGeneric_NullCollection_ShouldFail() + { + Action action = () => Assert.AllItemsAreNotNull(null); + action.Should().Throw() + .WithMessage("Assert.AllItemsAreNotNull failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AllItemsAreNotNull_NonGeneric_WithUserMessage_ShouldFail() + { + ArrayList list = ["a", null]; + Action action = () => Assert.AllItemsAreNotNull(list, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be non-null. + User-provided message + + null indices: [1] + collection: ["a", null] + + Assert.AllItemsAreNotNull(list) + """); + } + + public void AllItemsAreNotNull_Generic_NullableValueType_HasNull_ShouldFail() + { + Action action = () => Assert.AllItemsAreNotNull(new int?[] { 1, null, 3 }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be non-null. + + null indices: [1] + collection: [1, null, 3] + + Assert.AllItemsAreNotNull(new int?[] { 1, null, 3 }) + """); + } + + public void AllItemsAreNotNull_Generic_LazyEnumerable_HasNull_ShouldFail() + { + static IEnumerable Lazy() + { + yield return "a"; + yield return null; + yield return "b"; + } + + Action action = () => Assert.AllItemsAreNotNull(Lazy()); + action.Should().Throw() + .WithMessage("*null indices: [1]*collection:*"); + } + + #endregion // AllItemsAreNotNull + + #region AllItemsAreUnique + + public void AllItemsAreUnique_Generic_AllUnique_ShouldPass() + => Assert.AllItemsAreUnique(new[] { 1, 2, 3 }); + + public void AllItemsAreUnique_Generic_Empty_ShouldPass() + => Assert.AllItemsAreUnique(Array.Empty()); + + public void AllItemsAreUnique_Generic_SingleNull_ShouldPass() + => Assert.AllItemsAreUnique(new string?[] { "a", null, "b" }); + + public void AllItemsAreUnique_Generic_HasDuplicate_ShouldFail() + { + Action action = () => Assert.AllItemsAreUnique(new[] { 1, 2, 3, 4, 3 }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + + duplicates: [3] + collection: [1, 2, 3, 4, 3] + + Assert.AllItemsAreUnique(new[] { 1, 2, 3, 4, 3 }) + """); + } + + public void AllItemsAreUnique_Generic_HasMultipleDuplicates_ShouldFail() + { + Action action = () => Assert.AllItemsAreUnique(new[] { 1, 2, 3, 2, 1, 1 }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + + duplicates: [2, 1] + collection: [1, 2, 3, 2, 1, 1] + + Assert.AllItemsAreUnique(new[] { 1, 2, 3, 2, 1, 1 }) + """); + } + + public void AllItemsAreUnique_Generic_NullDuplicate_ShouldFail() + { + Action action = () => Assert.AllItemsAreUnique(new string?[] { "a", null, "b", null }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + + duplicates: [null] + collection: ["a", null, "b", null] + + Assert.AllItemsAreUnique(new string?[] { "a", null, "b", null }) + """); + } + + public void AllItemsAreUnique_Generic_WithUserMessage_ShouldFail() + { + Action action = () => Assert.AllItemsAreUnique(new[] { 1, 1 }, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + User-provided message + + duplicates: [1] + collection: [1, 1] + + Assert.AllItemsAreUnique(new[] { 1, 1 }) + """); + } + + public void AllItemsAreUnique_Generic_WithComparer_AllUnique_ShouldPass() + => Assert.AllItemsAreUnique(new[] { "a", "B", "c" }, StringComparer.OrdinalIgnoreCase); + + public void AllItemsAreUnique_Generic_WithComparer_HasDuplicate_ShouldFail() + { + Action action = () => Assert.AllItemsAreUnique(new[] { "A", "B", "a" }, StringComparer.OrdinalIgnoreCase); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + + duplicates: ["a"] + collection: ["A", "B", "a"] + comparer: OrdinalIgnoreCaseComparer + + Assert.AllItemsAreUnique(new[] { "A", "B", "a" }, ) + """); + } + + public void AllItemsAreUnique_Generic_NullCollection_ShouldFail() + { + Action action = () => Assert.AllItemsAreUnique((IEnumerable?)null); + action.Should().Throw() + .WithMessage("Assert.AllItemsAreUnique failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AllItemsAreUnique_Generic_NullComparer_ShouldFail() + { + Action action = () => Assert.AllItemsAreUnique(new[] { 1, 2 }, (IEqualityComparer?)null); + action.Should().Throw() + .WithMessage("Assert.AllItemsAreUnique failed. The parameter 'comparer' is invalid. The value cannot be null."); + } + + public void AllItemsAreUnique_NonGeneric_AllUnique_ShouldPass() + { + ArrayList list = [1, "a", 3.5]; + Assert.AllItemsAreUnique(list); + } + + public void AllItemsAreUnique_NonGeneric_HasDuplicate_ShouldFail() + { + ArrayList list = [1, 2, 3, 2]; + Action action = () => Assert.AllItemsAreUnique(list); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + + duplicates: [2] + collection: [1, 2, 3, 2] + + Assert.AllItemsAreUnique(list) + """); + } + + public void AllItemsAreUnique_NonGeneric_WithComparer_HasDuplicate_ShouldFail() + { + ArrayList list = ["A", "B", "a"]; + Action action = () => Assert.AllItemsAreUnique(list, StringComparer.OrdinalIgnoreCase); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + + duplicates: ["a"] + collection: ["A", "B", "a"] + comparer: OrdinalIgnoreCaseComparer + + Assert.AllItemsAreUnique(list, ) + """); + } + + public void AllItemsAreUnique_NonGeneric_NullCollection_ShouldFail() + { + Action action = () => Assert.AllItemsAreUnique(null); + action.Should().Throw() + .WithMessage("Assert.AllItemsAreUnique failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AllItemsAreUnique_NonGeneric_NullComparer_ShouldFail() + { + ArrayList list = [1, 2]; + Action action = () => Assert.AllItemsAreUnique(list, (IEqualityComparer?)null); + action.Should().Throw() + .WithMessage("Assert.AllItemsAreUnique failed. The parameter 'comparer' is invalid. The value cannot be null."); + } + + public void AllItemsAreUnique_NonGeneric_WithUserMessage_ShouldFail() + { + ArrayList list = [1, 1]; + Action action = () => Assert.AllItemsAreUnique(list, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + User-provided message + + duplicates: [1] + collection: [1, 1] + + Assert.AllItemsAreUnique(list) + """); + } + + public void AllItemsAreUnique_NonGeneric_SingleNull_ShouldPass() + { + ArrayList list = ["a", null, "b"]; + Assert.AllItemsAreUnique(list); + } + + public void AllItemsAreUnique_NonGeneric_NullDuplicate_ShouldFail() + { + ArrayList list = ["a", null, null]; + Action action = () => Assert.AllItemsAreUnique(list); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + + duplicates: [null] + collection: ["a", null, null] + + Assert.AllItemsAreUnique(list) + """); + } + + public void AllItemsAreUnique_Generic_ManyNulls_ReportsNullOnce_ShouldFail() + { + Action action = () => Assert.AllItemsAreUnique(new string?[] { null, "a", null, "b", null }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + + duplicates: [null] + collection: [null, "a", null, "b", null] + + Assert.AllItemsAreUnique(new string?[] { null, "a", null, "b", null }) + """); + } + + public void AllItemsAreUnique_Generic_ManyDuplicatesOfSameValue_ReportsValueOnce_ShouldFail() + { + Action action = () => Assert.AllItemsAreUnique(new[] { 5, 5, 5, 5 }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be unique. + + duplicates: [5] + collection: [5, 5, 5, 5] + + Assert.AllItemsAreUnique(new[] { 5, 5, 5, 5 }) + """); + } + + #endregion // AllItemsAreUnique + + #region AllItemsAreInstancesOfType + + public void AllItemsAreInstancesOfType_Generic_AllMatch_ShouldPass() + => Assert.AllItemsAreInstancesOfType(new object[] { "a", "b", "c" }); + + public void AllItemsAreInstancesOfType_Generic_DerivedTypes_ShouldPass() + => Assert.AllItemsAreInstancesOfType(new object[] { new DerivedAllItemsA(), new DerivedAllItemsB() }); + + public void AllItemsAreInstancesOfType_Generic_BaseTypeAcceptsDerived_ShouldPass() + => Assert.AllItemsAreInstancesOfType(new object[] { 1, "two", 3.0 }); + + public void AllItemsAreInstancesOfType_Generic_Empty_ShouldPass() + => Assert.AllItemsAreInstancesOfType(Array.Empty()); + + public void AllItemsAreInstancesOfType_Generic_NullElement_ShouldPass() + => Assert.AllItemsAreInstancesOfType(new object?[] { "a", null, "b" }); + + public void AllItemsAreInstancesOfType_Generic_HasMismatch_ShouldFail() + { + Action action = () => Assert.AllItemsAreInstancesOfType(new object[] { "a", 42, "b", true }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be instances of the specified type. + + expected type: System.String (or derived) + mismatches: [index 1: System.Int32, index 3: System.Boolean] + collection: ["a", 42, "b", true] + + Assert.AllItemsAreInstancesOfType(new object[] { "a", 42, "b", true }) + """); + } + + public void AllItemsAreInstancesOfType_Generic_WithUserMessage_ShouldFail() + { + Action action = () => Assert.AllItemsAreInstancesOfType(new object[] { 1 }, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be instances of the specified type. + User-provided message + + expected type: System.String (or derived) + mismatches: [index 0: System.Int32] + collection: [1] + + Assert.AllItemsAreInstancesOfType(new object[] { 1 }) + """); + } + + public void AllItemsAreInstancesOfType_Generic_NullCollection_ShouldFail() + { + Action action = () => Assert.AllItemsAreInstancesOfType(null); + action.Should().Throw() + .WithMessage("Assert.AllItemsAreInstancesOfType failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AllItemsAreInstancesOfType_NonGeneric_AllMatch_ShouldPass() + { + ArrayList list = ["a", "b"]; + Assert.AllItemsAreInstancesOfType(list, typeof(string)); + } + + public void AllItemsAreInstancesOfType_NonGeneric_HasMismatch_ShouldFail() + { + ArrayList list = ["a", 42]; + Action action = () => Assert.AllItemsAreInstancesOfType(list, typeof(string)); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be instances of the specified type. + + expected type: System.String (or derived) + mismatches: [index 1: System.Int32] + collection: ["a", 42] + + Assert.AllItemsAreInstancesOfType(list, typeof(string)) + """); + } + + public void AllItemsAreInstancesOfType_NonGeneric_NullCollection_ShouldFail() + { + Action action = () => Assert.AllItemsAreInstancesOfType(null, typeof(string)); + action.Should().Throw() + .WithMessage("Assert.AllItemsAreInstancesOfType failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AllItemsAreInstancesOfType_NonGeneric_NullExpectedType_ShouldFail() + { + ArrayList list = ["a"]; + Action action = () => Assert.AllItemsAreInstancesOfType(list, null); + action.Should().Throw() + .WithMessage("Assert.AllItemsAreInstancesOfType failed. The parameter 'expectedType' is invalid. The value cannot be null."); + } + + public void AllItemsAreInstancesOfType_NonGeneric_WithUserMessage_ShouldFail() + { + ArrayList list = [1]; + Action action = () => Assert.AllItemsAreInstancesOfType(list, typeof(string), "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be instances of the specified type. + User-provided message + + expected type: System.String (or derived) + mismatches: [index 0: System.Int32] + collection: [1] + + Assert.AllItemsAreInstancesOfType(list, typeof(string)) + """); + } + + public void AllItemsAreInstancesOfType_NonGeneric_DerivedTypes_ShouldPass() + { + ArrayList list = [new DerivedAllItemsA(), new DerivedAllItemsB()]; + Assert.AllItemsAreInstancesOfType(list, typeof(DerivedAllItemsBase)); + } + + public void AllItemsAreInstancesOfType_NonGeneric_NullElement_ShouldPass() + { + ArrayList list = ["a", null, "b"]; + Assert.AllItemsAreInstancesOfType(list, typeof(string)); + } + + public void AllItemsAreInstancesOfType_NonGeneric_Empty_ShouldPass() + { + ArrayList list = []; + Assert.AllItemsAreInstancesOfType(list, typeof(string)); + } + + private class DerivedAllItemsBase; + + private sealed class DerivedAllItemsA : DerivedAllItemsBase; + + private sealed class DerivedAllItemsB : DerivedAllItemsBase; + + #endregion // AllItemsAreInstancesOfType +} From 908e86621bc3feaa30bb32c194e82f0c76086d6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Fri, 15 May 2026 09:47:17 +0200 Subject: [PATCH 2/6] Address review feedback for Assert.AllItems* APIs - Drop comparer.GetType().Name from failure evidence (Dim 16): the CLR type name is fragile across TFMs (e.g. StringComparer.OrdinalIgnoreCase reports OrdinalComparer on .NET Framework, OrdinalIgnoreCaseComparer on .NET 5+). The placeholder in the call-site already conveys that a custom comparer was used. Fixes net48 test failures. - Document that null elements are skipped in AllItemsAreInstancesOfType (Dim 17). - Add TODO for NonGenericEqualityComparerAdapter dedup with PR #8234 (Dim 21). - Note why callSite[..^1] cannot be used (Dim 16 NIT was invalid: System.Range/System.Index not available on net462/netstandard2.0). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Assert.AllItemsAreInstancesOfType.cs | 6 +++++ .../Assertions/Assert.AllItemsAreUnique.cs | 25 +++++++++---------- .../Assertions/AssertTests.AllItems.cs | 2 -- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs b/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs index e3b7b186ff..85ff90c82d 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs @@ -43,6 +43,9 @@ public sealed partial class Assert /// or some elements of do not inherit from / implement /// . /// + /// + /// Null elements in are skipped and do not cause the assertion to fail. + /// public static void AllItemsAreInstancesOfType([NotNull] IEnumerable? collection, [NotNull] Type? expectedType, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "", [CallerArgumentExpression(nameof(expectedType))] string expectedTypeExpression = "") { CheckParameterNotNull(collection, "Assert.AllItemsAreInstancesOfType", "collection"); @@ -72,6 +75,9 @@ public static void AllItemsAreInstancesOfType([NotNull] IEnumerable? collection, /// Thrown if is null or some elements of /// do not inherit from / implement . /// + /// + /// Null elements in are skipped and do not cause the assertion to fail. + /// public static void AllItemsAreInstancesOfType([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { CheckParameterNotNull(collection, "Assert.AllItemsAreInstancesOfType", "collection"); diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs b/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs index cec1215e3d..5a915b9370 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs @@ -36,7 +36,7 @@ public sealed partial class Assert public static void AllItemsAreUnique([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); - AllItemsAreUniqueImpl(collection, EqualityComparer.Default, comparerName: null, message, collectionExpression); + AllItemsAreUniqueImpl(collection, EqualityComparer.Default, hasUserComparer: false, message, collectionExpression); } /// @@ -66,7 +66,7 @@ public static void AllItemsAreUnique([NotNull] IEnumerable? collection, [N { CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); CheckParameterNotNull(comparer, "Assert.AllItemsAreUnique", "comparer"); - AllItemsAreUniqueImpl(collection, comparer, comparer.GetType().Name, message, collectionExpression); + AllItemsAreUniqueImpl(collection, comparer, hasUserComparer: true, message, collectionExpression); } /// @@ -90,7 +90,7 @@ public static void AllItemsAreUnique([NotNull] IEnumerable? collection, [N public static void AllItemsAreUnique([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); - AllItemsAreUniqueImpl(collection.Cast(), EqualityComparer.Default, comparerName: null, message, collectionExpression); + AllItemsAreUniqueImpl(collection.Cast(), EqualityComparer.Default, hasUserComparer: false, message, collectionExpression); } /// @@ -119,11 +119,11 @@ public static void AllItemsAreUnique([NotNull] IEnumerable? collection, [NotNull { CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); CheckParameterNotNull(comparer, "Assert.AllItemsAreUnique", "comparer"); - AllItemsAreUniqueImpl(collection.Cast(), new NonGenericEqualityComparerAdapter(comparer), comparer.GetType().Name, message, collectionExpression); + AllItemsAreUniqueImpl(collection.Cast(), new NonGenericEqualityComparerAdapter(comparer), hasUserComparer: true, message, collectionExpression); } #pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. - private static void AllItemsAreUniqueImpl(IEnumerable collection, IEqualityComparer comparer, string? comparerName, string? message, string collectionExpression) + private static void AllItemsAreUniqueImpl(IEnumerable collection, IEqualityComparer comparer, bool hasUserComparer, string? message, string collectionExpression) { List snapshot = collection is List list ? list : [.. collection]; @@ -171,13 +171,13 @@ private static void AllItemsAreUniqueImpl(IEnumerable collection, IEqualit if (duplicates is not null) { - ReportAssertAllItemsAreUniqueFailed(snapshot, duplicates, comparerName, message, collectionExpression); + ReportAssertAllItemsAreUniqueFailed(snapshot, duplicates, hasUserComparer, message, collectionExpression); } } #pragma warning restore CS8714 [DoesNotReturn] - private static void ReportAssertAllItemsAreUniqueFailed(IEnumerable collection, List duplicates, string? comparerName, string? message, string collectionExpression) + private static void ReportAssertAllItemsAreUniqueFailed(IEnumerable collection, List duplicates, bool hasUserComparer, string? message, string collectionExpression) { string collectionText = AssertionValueRenderer.RenderValue(collection); string duplicatesText = AssertionValueRenderer.RenderValue(duplicates); @@ -186,16 +186,11 @@ private static void ReportAssertAllItemsAreUniqueFailed(IEnumerable collec .AddLine("duplicates:", duplicatesText) .AddLine("collection:", collectionText); - if (comparerName is not null) - { - evidence.AddLine("comparer:", comparerName); - } - StructuredAssertionMessage structured = new(FrameworkMessages.AllItemsAreUniqueFailedSummary); structured.WithUserMessage(message); structured.WithEvidence(evidence); structured.WithExpectedAndActual(expectedText: null, actualText: collectionText); - structured.WithCallSiteExpression(BuildCallSiteWithComparerForCollection("Assert.AllItemsAreUnique", collectionExpression, comparerName is not null)); + structured.WithCallSiteExpression(BuildCallSiteWithComparerForCollection("Assert.AllItemsAreUnique", collectionExpression, hasUserComparer)); ReportAssertFailed(structured); } @@ -210,11 +205,15 @@ private static void ReportAssertAllItemsAreUniqueFailed(IEnumerable collec // FormatCallSiteExpression has no overload accepting a third argument expression; insert // the placeholder so the rendered call-site reflects the overload that was actually invoked. + // Note: range/index syntax (callSite[..^1]) is not used because System.Range/System.Index are unavailable + // on net462 / netstandard2.0, the lowest TFMs targeted by this project. return string.Concat(callSite.Substring(0, callSite.Length - 1), ", )"); } #endregion // AllItemsAreUnique + // TODO: Deduplicate with the same adapter in Assert.CollectionEquivalence.cs (introduced by PR #8234) + // once both PRs have landed. private sealed class NonGenericEqualityComparerAdapter : IEqualityComparer { private readonly IEqualityComparer _comparer; diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs index 3269d87b62..4ff89ccd28 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs @@ -222,7 +222,6 @@ Assertion failed. Expected all items in collection to be unique. duplicates: ["a"] collection: ["A", "B", "a"] - comparer: OrdinalIgnoreCaseComparer Assert.AllItemsAreUnique(new[] { "A", "B", "a" }, ) """); @@ -275,7 +274,6 @@ Assertion failed. Expected all items in collection to be unique. duplicates: ["a"] collection: ["A", "B", "a"] - comparer: OrdinalIgnoreCaseComparer Assert.AllItemsAreUnique(list, ) """); From 53d068711f8dceec8291c83566fa4427793fb420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Fri, 15 May 2026 17:23:49 +0200 Subject: [PATCH 3/6] Rename to AreAll* family and align with Assert conventions - Assert.AllItemsAreNotNull -> Assert.AreAllNotNull - Assert.AllItemsAreUnique -> Assert.AreAllDistinct (LINQ-aligned vocabulary) - Assert.AllItemsAreInstancesOfType -> Assert.AreAllOfType - Param order flipped to (expectedType, collection) to match the modern (expected, actual, options) Assert convention. - Null elements now FAIL (previously skipped) to match the semantics of the singular Assert.IsInstanceOfType ([NotNull]) and the LINQ Enumerable.OfType contract that null is T == false. - Mismatch evidence renders null elements as 'index N: '. Also: - Renamed resx entries (AllItems* -> AreAll*) and regenerated xlf. - Updated PublicAPI.Unshipped.txt (8 entries, alphabetical). - Updated unit tests (renamed file + methods, adjusted expected failure messages, added _NullElement_ShouldFail tests for AreAllOfType). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...sAreUnique.cs => Assert.AreAllDistinct.cs} | 64 ++- ...sAreNotNull.cs => Assert.AreAllNotNull.cs} | 26 +- ...tancesOfType.cs => Assert.AreAllOfType.cs} | 101 ++-- .../PublicAPI/PublicAPI.Unshipped.txt | 16 +- .../Resources/FrameworkMessages.resx | 10 +- .../Resources/xlf/FrameworkMessages.cs.xlf | 24 +- .../Resources/xlf/FrameworkMessages.de.xlf | 24 +- .../Resources/xlf/FrameworkMessages.es.xlf | 24 +- .../Resources/xlf/FrameworkMessages.fr.xlf | 24 +- .../Resources/xlf/FrameworkMessages.it.xlf | 24 +- .../Resources/xlf/FrameworkMessages.ja.xlf | 24 +- .../Resources/xlf/FrameworkMessages.ko.xlf | 24 +- .../Resources/xlf/FrameworkMessages.pl.xlf | 24 +- .../Resources/xlf/FrameworkMessages.pt-BR.xlf | 24 +- .../Resources/xlf/FrameworkMessages.ru.xlf | 24 +- .../Resources/xlf/FrameworkMessages.tr.xlf | 24 +- .../xlf/FrameworkMessages.zh-Hans.xlf | 24 +- .../xlf/FrameworkMessages.zh-Hant.xlf | 24 +- .../Assertions/AssertTests.AllItems.cs | 506 ----------------- .../Assertions/AssertTests.AreAll.cs | 530 ++++++++++++++++++ 20 files changed, 802 insertions(+), 763 deletions(-) rename src/TestFramework/TestFramework/Assertions/{Assert.AllItemsAreUnique.cs => Assert.AreAllDistinct.cs} (74%) rename src/TestFramework/TestFramework/Assertions/{Assert.AllItemsAreNotNull.cs => Assert.AreAllNotNull.cs} (73%) rename src/TestFramework/TestFramework/Assertions/{Assert.AllItemsAreInstancesOfType.cs => Assert.AreAllOfType.cs} (55%) delete mode 100644 test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs create mode 100644 test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs similarity index 74% rename from src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs rename to src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs index 5a915b9370..9b52dd8320 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreUnique.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs @@ -12,11 +12,12 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; #pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads public sealed partial class Assert { - #region AllItemsAreUnique + #region AreAllDistinct /// - /// Tests whether all items in the specified collection are unique and throws - /// an exception if any two elements in the collection are equal. + /// Tests whether all items in the specified collection are distinct (no two + /// elements are equal) and throws an exception if any two elements in the + /// collection are equal. /// /// The type of the collection items. /// @@ -33,16 +34,16 @@ public sealed partial class Assert /// /// Thrown if is null or contains at least one duplicate element. /// - public static void AllItemsAreUnique([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + public static void AreAllDistinct([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { - CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); - AllItemsAreUniqueImpl(collection, EqualityComparer.Default, hasUserComparer: false, message, collectionExpression); + CheckParameterNotNull(collection, "Assert.AreAllDistinct", "collection"); + AreAllDistinctImpl(collection, EqualityComparer.Default, hasUserComparer: false, message, collectionExpression); } /// - /// Tests whether all items in the specified collection are unique using the - /// supplied and throws an exception if any two - /// elements in the collection are equal. + /// Tests whether all items in the specified collection are distinct (no two + /// elements are equal) using the supplied and throws + /// an exception if any two elements in the collection are equal. /// /// The type of the collection items. /// @@ -62,16 +63,17 @@ public static void AllItemsAreUnique([NotNull] IEnumerable? collection, st /// /// Thrown if is null or contains at least one duplicate element. /// - public static void AllItemsAreUnique([NotNull] IEnumerable? collection, [NotNull] IEqualityComparer? comparer, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + public static void AreAllDistinct([NotNull] IEnumerable? collection, [NotNull] IEqualityComparer? comparer, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { - CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); - CheckParameterNotNull(comparer, "Assert.AllItemsAreUnique", "comparer"); - AllItemsAreUniqueImpl(collection, comparer, hasUserComparer: true, message, collectionExpression); + CheckParameterNotNull(collection, "Assert.AreAllDistinct", "collection"); + CheckParameterNotNull(comparer, "Assert.AreAllDistinct", "comparer"); + AreAllDistinctImpl(collection, comparer, hasUserComparer: true, message, collectionExpression); } /// - /// Tests whether all items in the specified collection are unique and throws - /// an exception if any two elements in the collection are equal. + /// Tests whether all items in the specified collection are distinct (no two + /// elements are equal) and throws an exception if any two elements in the + /// collection are equal. /// /// /// The collection in which to search for duplicate elements. @@ -87,16 +89,16 @@ public static void AllItemsAreUnique([NotNull] IEnumerable? collection, [N /// /// Thrown if is null or contains at least one duplicate element. /// - public static void AllItemsAreUnique([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + public static void AreAllDistinct([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { - CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); - AllItemsAreUniqueImpl(collection.Cast(), EqualityComparer.Default, hasUserComparer: false, message, collectionExpression); + CheckParameterNotNull(collection, "Assert.AreAllDistinct", "collection"); + AreAllDistinctImpl(collection.Cast(), EqualityComparer.Default, hasUserComparer: false, message, collectionExpression); } /// - /// Tests whether all items in the specified collection are unique using the - /// supplied and throws an exception if any two - /// elements in the collection are equal. + /// Tests whether all items in the specified collection are distinct (no two + /// elements are equal) using the supplied and throws + /// an exception if any two elements in the collection are equal. /// /// /// The collection in which to search for duplicate elements. @@ -115,15 +117,15 @@ public static void AllItemsAreUnique([NotNull] IEnumerable? collection, string? /// /// Thrown if is null or contains at least one duplicate element. /// - public static void AllItemsAreUnique([NotNull] IEnumerable? collection, [NotNull] IEqualityComparer? comparer, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + public static void AreAllDistinct([NotNull] IEnumerable? collection, [NotNull] IEqualityComparer? comparer, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { - CheckParameterNotNull(collection, "Assert.AllItemsAreUnique", "collection"); - CheckParameterNotNull(comparer, "Assert.AllItemsAreUnique", "comparer"); - AllItemsAreUniqueImpl(collection.Cast(), new NonGenericEqualityComparerAdapter(comparer), hasUserComparer: true, message, collectionExpression); + CheckParameterNotNull(collection, "Assert.AreAllDistinct", "collection"); + CheckParameterNotNull(comparer, "Assert.AreAllDistinct", "comparer"); + AreAllDistinctImpl(collection.Cast(), new NonGenericEqualityComparerAdapter(comparer), hasUserComparer: true, message, collectionExpression); } #pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. - private static void AllItemsAreUniqueImpl(IEnumerable collection, IEqualityComparer comparer, bool hasUserComparer, string? message, string collectionExpression) + private static void AreAllDistinctImpl(IEnumerable collection, IEqualityComparer comparer, bool hasUserComparer, string? message, string collectionExpression) { List snapshot = collection is List list ? list : [.. collection]; @@ -171,13 +173,13 @@ private static void AllItemsAreUniqueImpl(IEnumerable collection, IEqualit if (duplicates is not null) { - ReportAssertAllItemsAreUniqueFailed(snapshot, duplicates, hasUserComparer, message, collectionExpression); + ReportAssertAreAllDistinctFailed(snapshot, duplicates, hasUserComparer, message, collectionExpression); } } #pragma warning restore CS8714 [DoesNotReturn] - private static void ReportAssertAllItemsAreUniqueFailed(IEnumerable collection, List duplicates, bool hasUserComparer, string? message, string collectionExpression) + private static void ReportAssertAreAllDistinctFailed(IEnumerable collection, List duplicates, bool hasUserComparer, string? message, string collectionExpression) { string collectionText = AssertionValueRenderer.RenderValue(collection); string duplicatesText = AssertionValueRenderer.RenderValue(duplicates); @@ -186,11 +188,11 @@ private static void ReportAssertAllItemsAreUniqueFailed(IEnumerable collec .AddLine("duplicates:", duplicatesText) .AddLine("collection:", collectionText); - StructuredAssertionMessage structured = new(FrameworkMessages.AllItemsAreUniqueFailedSummary); + StructuredAssertionMessage structured = new(FrameworkMessages.AreAllDistinctFailedSummary); structured.WithUserMessage(message); structured.WithEvidence(evidence); structured.WithExpectedAndActual(expectedText: null, actualText: collectionText); - structured.WithCallSiteExpression(BuildCallSiteWithComparerForCollection("Assert.AllItemsAreUnique", collectionExpression, hasUserComparer)); + structured.WithCallSiteExpression(BuildCallSiteWithComparerForCollection("Assert.AreAllDistinct", collectionExpression, hasUserComparer)); ReportAssertFailed(structured); } @@ -210,7 +212,7 @@ private static void ReportAssertAllItemsAreUniqueFailed(IEnumerable collec return string.Concat(callSite.Substring(0, callSite.Length - 1), ", )"); } - #endregion // AllItemsAreUnique + #endregion // AreAllDistinct // TODO: Deduplicate with the same adapter in Assert.CollectionEquivalence.cs (introduced by PR #8234) // once both PRs have landed. diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreNotNull.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreAllNotNull.cs similarity index 73% rename from src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreNotNull.cs rename to src/TestFramework/TestFramework/Assertions/Assert.AreAllNotNull.cs index 2f33ef5d91..88b0f15899 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreNotNull.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreAllNotNull.cs @@ -12,7 +12,7 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; #pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads public sealed partial class Assert { - #region AllItemsAreNotNull + #region AreAllNotNull /// /// Tests whether all items in the specified collection are non-null and throws @@ -32,10 +32,10 @@ public sealed partial class Assert /// /// Thrown if is null or contains at least one null element. /// - public static void AllItemsAreNotNull([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + public static void AreAllNotNull([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { - CheckParameterNotNull(collection, "Assert.AllItemsAreNotNull", "collection"); - AllItemsAreNotNullImpl(collection.Cast(), message, collectionExpression); + CheckParameterNotNull(collection, "Assert.AreAllNotNull", "collection"); + AreAllNotNullImpl(collection.Cast(), message, collectionExpression); } /// @@ -57,13 +57,13 @@ public static void AllItemsAreNotNull([NotNull] IEnumerable? collection, string? /// /// Thrown if is null or contains at least one null element. /// - public static void AllItemsAreNotNull([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + public static void AreAllNotNull([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { - CheckParameterNotNull(collection, "Assert.AllItemsAreNotNull", "collection"); - AllItemsAreNotNullImpl(collection, message, collectionExpression); + CheckParameterNotNull(collection, "Assert.AreAllNotNull", "collection"); + AreAllNotNullImpl(collection, message, collectionExpression); } - private static void AllItemsAreNotNullImpl(IEnumerable collection, string? message, string collectionExpression) + private static void AreAllNotNullImpl(IEnumerable collection, string? message, string collectionExpression) { List snapshot = collection is List list ? list : [.. collection]; List? nullIndices = null; @@ -78,12 +78,12 @@ private static void AllItemsAreNotNullImpl(IEnumerable collection, string? if (nullIndices is not null) { - ReportAssertAllItemsAreNotNullFailed(snapshot, nullIndices, message, collectionExpression); + ReportAssertAreAllNotNullFailed(snapshot, nullIndices, message, collectionExpression); } } [DoesNotReturn] - private static void ReportAssertAllItemsAreNotNullFailed(IEnumerable collection, List nullIndices, string? message, string collectionExpression) + private static void ReportAssertAreAllNotNullFailed(IEnumerable collection, List nullIndices, string? message, string collectionExpression) { string collectionText = AssertionValueRenderer.RenderValue(collection); string nullIndicesText = AssertionValueRenderer.RenderValue(nullIndices); @@ -92,14 +92,14 @@ private static void ReportAssertAllItemsAreNotNullFailed(IEnumerable colle .AddLine("null indices:", nullIndicesText) .AddLine("collection:", collectionText); - StructuredAssertionMessage structured = new(FrameworkMessages.AllItemsAreNotNullFailedSummary); + StructuredAssertionMessage structured = new(FrameworkMessages.AreAllNotNullFailedSummary); structured.WithUserMessage(message); structured.WithEvidence(evidence); structured.WithExpectedAndActual(expectedText: null, actualText: collectionText); - structured.WithCallSiteExpression(FormatCallSiteExpression("Assert.AllItemsAreNotNull", collectionExpression, "")); + structured.WithCallSiteExpression(FormatCallSiteExpression("Assert.AreAllNotNull", collectionExpression, "")); ReportAssertFailed(structured); } - #endregion // AllItemsAreNotNull + #endregion // AreAllNotNull } diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs similarity index 55% rename from src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs rename to src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs index 85ff90c82d..3a7265f1d3 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AllItemsAreInstancesOfType.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs @@ -12,51 +12,50 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; #pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads public sealed partial class Assert { - #region AllItemsAreInstancesOfType + #region AreAllOfType /// - /// Tests whether all elements in the specified collection are instances of the - /// expected type and throws an exception if the expected type is not in the - /// inheritance hierarchy of one or more of the elements. + /// Tests whether all elements in the specified collection are instances of (or + /// derived from) the expected type and throws an exception if the expected type is + /// not in the inheritance hierarchy of one or more of the elements, or if any + /// element is null. /// - /// - /// The collection containing elements the test expects to be of the specified type. - /// /// /// The expected type of each element of . /// + /// + /// The collection containing elements the test expects to be of the specified type. + /// /// /// The message to include in the exception when an element in - /// is not an instance of . The message is shown in + /// is null or not an instance of . The message is shown in /// test results. /// - /// - /// The syntactic expression of collection as given by the compiler via caller argument expression. - /// Users shouldn't pass a value for this parameter. - /// /// /// The syntactic expression of expectedType as given by the compiler via caller argument expression. /// Users shouldn't pass a value for this parameter. /// + /// + /// The syntactic expression of collection as given by the compiler via caller argument expression. + /// Users shouldn't pass a value for this parameter. + /// /// - /// Thrown if or is null, - /// or some elements of do not inherit from / implement - /// . + /// Thrown if or is null, + /// or some elements of are null or do not inherit from / + /// implement . /// - /// - /// Null elements in are skipped and do not cause the assertion to fail. - /// - public static void AllItemsAreInstancesOfType([NotNull] IEnumerable? collection, [NotNull] Type? expectedType, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "", [CallerArgumentExpression(nameof(expectedType))] string expectedTypeExpression = "") + public static void AreAllOfType([NotNull] Type? expectedType, [NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(expectedType))] string expectedTypeExpression = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { - CheckParameterNotNull(collection, "Assert.AllItemsAreInstancesOfType", "collection"); - CheckParameterNotNull(expectedType, "Assert.AllItemsAreInstancesOfType", "expectedType"); - AllItemsAreInstancesOfTypeImpl(collection, expectedType, genericTypeArgumentName: null, message, collectionExpression, expectedTypeExpression); + CheckParameterNotNull(expectedType, "Assert.AreAllOfType", "expectedType"); + CheckParameterNotNull(collection, "Assert.AreAllOfType", "collection"); + AreAllOfTypeImpl(collection, expectedType, genericTypeArgumentName: null, message, collectionExpression, expectedTypeExpression); } /// - /// Tests whether all elements in the specified collection are instances of the - /// expected type and throws an exception if the expected type is not in the - /// inheritance hierarchy of one or more of the elements. + /// Tests whether all elements in the specified collection are instances of (or + /// derived from) the expected type and throws an exception if the expected type is + /// not in the inheritance hierarchy of one or more of the elements, or if any + /// element is null. /// /// The type each element of is expected to be. /// @@ -64,7 +63,7 @@ public static void AllItemsAreInstancesOfType([NotNull] IEnumerable? collection, /// /// /// The message to include in the exception when an element in - /// is not an instance of . The message is shown in + /// is null or not an instance of . The message is shown in /// test results. /// /// @@ -73,26 +72,31 @@ public static void AllItemsAreInstancesOfType([NotNull] IEnumerable? collection, /// /// /// Thrown if is null or some elements of - /// do not inherit from / implement . + /// are null or do not inherit from / implement + /// . /// - /// - /// Null elements in are skipped and do not cause the assertion to fail. - /// - public static void AllItemsAreInstancesOfType([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") + public static void AreAllOfType([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { - CheckParameterNotNull(collection, "Assert.AllItemsAreInstancesOfType", "collection"); - AllItemsAreInstancesOfTypeImpl(collection, typeof(TExpected), genericTypeArgumentName: "TExpected", message, collectionExpression, expectedTypeExpression: null); + CheckParameterNotNull(collection, "Assert.AreAllOfType", "collection"); + AreAllOfTypeImpl(collection, typeof(TExpected), genericTypeArgumentName: "TExpected", message, collectionExpression, expectedTypeExpression: null); } - private static void AllItemsAreInstancesOfTypeImpl(IEnumerable collection, Type expectedType, string? genericTypeArgumentName, string? message, string collectionExpression, string? expectedTypeExpression) + private static void AreAllOfTypeImpl(IEnumerable collection, Type expectedType, string? genericTypeArgumentName, string? message, string collectionExpression, string? expectedTypeExpression) { List snapshot = [.. collection.Cast()]; List? mismatchIndices = null; - List? mismatchTypes = null; + List? mismatchTypes = null; for (int i = 0; i < snapshot.Count; i++) { object? element = snapshot[i]; - if (element is not null && !expectedType.IsInstanceOfType(element)) + if (element is null) + { + mismatchIndices ??= []; + mismatchTypes ??= []; + mismatchIndices.Add(i); + mismatchTypes.Add(null); + } + else if (!expectedType.IsInstanceOfType(element)) { mismatchIndices ??= []; mismatchTypes ??= []; @@ -103,12 +107,12 @@ private static void AllItemsAreInstancesOfTypeImpl(IEnumerable collection, Type if (mismatchIndices is not null) { - ReportAssertAllItemsAreInstancesOfTypeFailed(snapshot, expectedType, mismatchIndices, mismatchTypes!, genericTypeArgumentName, message, collectionExpression, expectedTypeExpression); + ReportAssertAreAllOfTypeFailed(snapshot, expectedType, mismatchIndices, mismatchTypes!, genericTypeArgumentName, message, collectionExpression, expectedTypeExpression); } } [DoesNotReturn] - private static void ReportAssertAllItemsAreInstancesOfTypeFailed(IEnumerable collection, Type expectedType, List mismatchIndices, List mismatchTypes, string? genericTypeArgumentName, string? message, string collectionExpression, string? expectedTypeExpression) + private static void ReportAssertAreAllOfTypeFailed(IEnumerable collection, Type expectedType, List mismatchIndices, List mismatchTypes, string? genericTypeArgumentName, string? message, string collectionExpression, string? expectedTypeExpression) { string collectionText = AssertionValueRenderer.RenderValue(collection); string expectedTypeText = $"{expectedType} (or derived)"; @@ -122,7 +126,16 @@ private static void ReportAssertAllItemsAreInstancesOfTypeFailed(IEnumerable"); + } + else + { + mismatchesBuilder.Append(mismatchType); + } } mismatchesBuilder.Append(']'); @@ -133,14 +146,14 @@ private static void ReportAssertAllItemsAreInstancesOfTypeFailed(IEnumerable"; + ? "Assert.AreAllOfType" + : $"Assert.AreAllOfType<{genericTypeArgumentName}>"; string? callSite = genericTypeArgumentName is null - ? FormatCallSiteExpression(assertionMethodName, collectionExpression, expectedTypeExpression!, "", "") + ? FormatCallSiteExpression(assertionMethodName, expectedTypeExpression!, collectionExpression, "", "") : FormatCallSiteExpression(assertionMethodName, collectionExpression, ""); - StructuredAssertionMessage structured = new(FrameworkMessages.AllItemsAreInstancesOfTypeFailedSummary); + StructuredAssertionMessage structured = new(FrameworkMessages.AreAllOfTypeFailedSummary); structured.WithUserMessage(message); structured.WithEvidence(evidence); structured.WithExpectedAndActual(expectedText: null, actualText: collectionText); @@ -149,5 +162,5 @@ private static void ReportAssertAllItemsAreInstancesOfTypeFailed(IEnumerable System.IDisposable! Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException.ActualText.get -> string? Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException.ExpectedText.get -> string? -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreInstancesOfType(System.Collections.IEnumerable? collection, System.Type? expectedType, string? message = "", string! collectionExpression = "", string! expectedTypeExpression = "") -> void -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreInstancesOfType(System.Collections.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreNotNull(System.Collections.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreNotNull(System.Collections.Generic.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreUnique(System.Collections.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreUnique(System.Collections.IEnumerable? collection, System.Collections.IEqualityComparer? comparer, string? message = "", string! collectionExpression = "") -> void -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreUnique(System.Collections.Generic.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void -static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AllItemsAreUnique(System.Collections.Generic.IEnumerable? collection, System.Collections.Generic.IEqualityComparer? comparer, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreAllDistinct(System.Collections.IEnumerable? collection, System.Collections.IEqualityComparer? comparer, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreAllDistinct(System.Collections.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreAllDistinct(System.Collections.Generic.IEnumerable? collection, System.Collections.Generic.IEqualityComparer? comparer, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreAllDistinct(System.Collections.Generic.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreAllNotNull(System.Collections.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreAllNotNull(System.Collections.Generic.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreAllOfType(System.Type? expectedType, System.Collections.IEnumerable? collection, string? message = "", string! expectedTypeExpression = "", string! collectionExpression = "") -> void +static Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreAllOfType(System.Collections.IEnumerable? collection, string? message = "", string! collectionExpression = "") -> void diff --git a/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx b/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx index 8f2b449887..3448219940 100644 --- a/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx +++ b/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx @@ -420,13 +420,13 @@ Actual: {2} Expected value to not be null. - + Expected all items in collection to be non-null. - - Expected all items in collection to be unique. + + Expected all items in collection to be distinct. - - Expected all items in collection to be instances of the specified type. + + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf index 90883b9e16..ff083ac80c 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf @@ -12,24 +12,24 @@ Očekávaná kolekce obsahuje {1} výskyt(ů) <{2}>. Aktuální kolekce obsahuje {3} výskyt(ů). {0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + Byla nalezena duplicitní položka:<{1}>. {0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - Byla nalezena duplicitní položka:<{1}>. {0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf index 12d6076e36..aecde97a96 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf @@ -12,24 +12,24 @@ Die erwartete Sammlung enthält {1} Vorkommen von <{2}>. Die tatsächliche Sammlung enthält {3} Vorkommen. {0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + Doppeltes Element gefunden: <{1}>. {0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - Doppeltes Element gefunden: <{1}>. {0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf index 255a30cbf9..3826d95424 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf @@ -12,24 +12,24 @@ Apariciones que contiene la colección esperada: {1} de <{2}>. Apariciones que contiene la colección real: {3}. {0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + Se encontró un elemento duplicado:<{1}>. {0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - Se encontró un elemento duplicado:<{1}>. {0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf index 4cabcea255..ab422ca519 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf @@ -12,24 +12,24 @@ La collection attendue contient {1} occurrence(s) de <{2}>. La collection réelle contient {3} occurrence(s). {0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + Un élément dupliqué a été trouvé : <{1}>. {0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - Un élément dupliqué a été trouvé : <{1}>. {0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf index 86ffdd9aa6..70d223b4bb 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf @@ -12,24 +12,24 @@ La raccolta prevista contiene {1} occorrenza/e di <{2}>. La raccolta effettiva contiene {3} occorrenza/e. {0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + Rilevato elemento duplicato:<{1}>. {0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - Rilevato elemento duplicato:<{1}>. {0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf index e724769c2e..b8ead8dbe1 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf @@ -12,24 +12,24 @@ 予期されたコレクションでは、<{2}> が {1} 回発生します。実際のコレクションでは、{3} 回発生します。{0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + 重複する項目が見つかりました:<{1}>。{0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - 重複する項目が見つかりました:<{1}>。{0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf index c78fe91d9a..140c74e14b 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf @@ -12,24 +12,24 @@ 필요한 컬렉션에 <{2}>은(는) {1}개가 포함되어야 하는데 실제 컬렉션에는 {3}개가 포함되어 있습니다. {0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + 중복된 항목이 있습니다. <{1}>. {0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - 중복된 항목이 있습니다. <{1}>. {0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf index aff015dc21..25566abf1e 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf @@ -12,24 +12,24 @@ Oczekiwana kolekcja zawiera {1} wystąpień <{2}>. Bieżąca kolekcja zawiera {3} wystąpień. {0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + Znaleziono duplikat:<{1}>. {0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - Znaleziono duplikat:<{1}>. {0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf index 123529e2bf..75bed6d247 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf @@ -12,24 +12,24 @@ A coleção esperada contém {1} ocorrência(s) de <{2}>. A coleção real contém {3} ocorrência(s). {0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + Item duplicado encontrado:<{1}>. {0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - Item duplicado encontrado:<{1}>. {0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf index 372cc841ee..2325ca7c78 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf @@ -12,24 +12,24 @@ Ожидаемый набор содержит следующее число событий <{2}>: {1}. Фактический набор содержит число событий: {3}. {0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + Обнаружен совпадающий элемент: <{1}>. {0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - Обнаружен совпадающий элемент: <{1}>. {0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf index 8d1c20fbc7..b4c70470e6 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf @@ -12,24 +12,24 @@ Beklenen koleksiyon {1} <{2}> örneği içerir. Gerçek koleksiyon {3} örnek içerir. {0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + Yinelenen öğe bulundu:<{1}>. {0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - Yinelenen öğe bulundu:<{1}>. {0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf index 030cf342f1..f1885afdb7 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf @@ -12,24 +12,24 @@ 所需集合包含 <{2}> 的 {1} 个匹配项。实际集合包含 {3} 个匹配项。{0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + 找到了重复项: <{1}>。{0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - 找到了重复项: <{1}>。{0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf index 46309a25bd..ac7eae6e65 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf @@ -12,24 +12,24 @@ 預期在集合中包含 {1} 項 <{2}>,但實際的集合卻有 {3} 項。{0} - - Expected all items in collection to be instances of the specified type. - Expected all items in collection to be instances of the specified type. + + Duplicate item found:<{1}>. {0} + 找到重複的項目: <{1}>。{0} + + + + Expected all items in collection to be distinct. + Expected all items in collection to be distinct. - + Expected all items in collection to be non-null. Expected all items in collection to be non-null. - - Duplicate item found:<{1}>. {0} - 找到重複的項目: <{1}>。{0} - - - - Expected all items in collection to be unique. - Expected all items in collection to be unique. + + Expected all items in collection to be of the specified type. + Expected all items in collection to be of the specified type. diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs deleted file mode 100644 index 4ff89ccd28..0000000000 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AllItems.cs +++ /dev/null @@ -1,506 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections; - -using AwesomeAssertions; - -using TestFramework.ForTestingMSTest; - -namespace Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests; - -public partial class AssertTests : TestContainer -{ - #region AllItemsAreNotNull - - public void AllItemsAreNotNull_Generic_NoNulls_ShouldPass() - => Assert.AllItemsAreNotNull(new[] { "a", "b", "c" }); - - public void AllItemsAreNotNull_Generic_Empty_ShouldPass() - => Assert.AllItemsAreNotNull(Array.Empty()); - - public void AllItemsAreNotNull_Generic_ValueTypes_ShouldPass() - => Assert.AllItemsAreNotNull(new[] { 1, 2, 3 }); - - public void AllItemsAreNotNull_Generic_HasNull_ShouldFail() - { - Action action = () => Assert.AllItemsAreNotNull(new[] { "a", null, "b", null }); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be non-null. - - null indices: [1, 3] - collection: ["a", null, "b", null] - - Assert.AllItemsAreNotNull(new[] { "a", null, "b", null }) - """); - } - - public void AllItemsAreNotNull_Generic_WithUserMessage_ShouldFail() - { - Action action = () => Assert.AllItemsAreNotNull(new[] { "a", null }, "User-provided message"); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be non-null. - User-provided message - - null indices: [1] - collection: ["a", null] - - Assert.AllItemsAreNotNull(new[] { "a", null }) - """); - } - - public void AllItemsAreNotNull_Generic_NullCollection_ShouldFail() - { - Action action = () => Assert.AllItemsAreNotNull((IEnumerable?)null); - action.Should().Throw() - .WithMessage("Assert.AllItemsAreNotNull failed. The parameter 'collection' is invalid. The value cannot be null."); - } - - public void AllItemsAreNotNull_NonGeneric_NoNulls_ShouldPass() - { - ArrayList list = ["a", "b", "c"]; - Assert.AllItemsAreNotNull(list); - } - - public void AllItemsAreNotNull_NonGeneric_HasNull_ShouldFail() - { - ArrayList list = ["a", null, "b"]; - Action action = () => Assert.AllItemsAreNotNull(list); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be non-null. - - null indices: [1] - collection: ["a", null, "b"] - - Assert.AllItemsAreNotNull(list) - """); - } - - public void AllItemsAreNotNull_NonGeneric_NullCollection_ShouldFail() - { - Action action = () => Assert.AllItemsAreNotNull(null); - action.Should().Throw() - .WithMessage("Assert.AllItemsAreNotNull failed. The parameter 'collection' is invalid. The value cannot be null."); - } - - public void AllItemsAreNotNull_NonGeneric_WithUserMessage_ShouldFail() - { - ArrayList list = ["a", null]; - Action action = () => Assert.AllItemsAreNotNull(list, "User-provided message"); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be non-null. - User-provided message - - null indices: [1] - collection: ["a", null] - - Assert.AllItemsAreNotNull(list) - """); - } - - public void AllItemsAreNotNull_Generic_NullableValueType_HasNull_ShouldFail() - { - Action action = () => Assert.AllItemsAreNotNull(new int?[] { 1, null, 3 }); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be non-null. - - null indices: [1] - collection: [1, null, 3] - - Assert.AllItemsAreNotNull(new int?[] { 1, null, 3 }) - """); - } - - public void AllItemsAreNotNull_Generic_LazyEnumerable_HasNull_ShouldFail() - { - static IEnumerable Lazy() - { - yield return "a"; - yield return null; - yield return "b"; - } - - Action action = () => Assert.AllItemsAreNotNull(Lazy()); - action.Should().Throw() - .WithMessage("*null indices: [1]*collection:*"); - } - - #endregion // AllItemsAreNotNull - - #region AllItemsAreUnique - - public void AllItemsAreUnique_Generic_AllUnique_ShouldPass() - => Assert.AllItemsAreUnique(new[] { 1, 2, 3 }); - - public void AllItemsAreUnique_Generic_Empty_ShouldPass() - => Assert.AllItemsAreUnique(Array.Empty()); - - public void AllItemsAreUnique_Generic_SingleNull_ShouldPass() - => Assert.AllItemsAreUnique(new string?[] { "a", null, "b" }); - - public void AllItemsAreUnique_Generic_HasDuplicate_ShouldFail() - { - Action action = () => Assert.AllItemsAreUnique(new[] { 1, 2, 3, 4, 3 }); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - - duplicates: [3] - collection: [1, 2, 3, 4, 3] - - Assert.AllItemsAreUnique(new[] { 1, 2, 3, 4, 3 }) - """); - } - - public void AllItemsAreUnique_Generic_HasMultipleDuplicates_ShouldFail() - { - Action action = () => Assert.AllItemsAreUnique(new[] { 1, 2, 3, 2, 1, 1 }); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - - duplicates: [2, 1] - collection: [1, 2, 3, 2, 1, 1] - - Assert.AllItemsAreUnique(new[] { 1, 2, 3, 2, 1, 1 }) - """); - } - - public void AllItemsAreUnique_Generic_NullDuplicate_ShouldFail() - { - Action action = () => Assert.AllItemsAreUnique(new string?[] { "a", null, "b", null }); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - - duplicates: [null] - collection: ["a", null, "b", null] - - Assert.AllItemsAreUnique(new string?[] { "a", null, "b", null }) - """); - } - - public void AllItemsAreUnique_Generic_WithUserMessage_ShouldFail() - { - Action action = () => Assert.AllItemsAreUnique(new[] { 1, 1 }, "User-provided message"); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - User-provided message - - duplicates: [1] - collection: [1, 1] - - Assert.AllItemsAreUnique(new[] { 1, 1 }) - """); - } - - public void AllItemsAreUnique_Generic_WithComparer_AllUnique_ShouldPass() - => Assert.AllItemsAreUnique(new[] { "a", "B", "c" }, StringComparer.OrdinalIgnoreCase); - - public void AllItemsAreUnique_Generic_WithComparer_HasDuplicate_ShouldFail() - { - Action action = () => Assert.AllItemsAreUnique(new[] { "A", "B", "a" }, StringComparer.OrdinalIgnoreCase); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - - duplicates: ["a"] - collection: ["A", "B", "a"] - - Assert.AllItemsAreUnique(new[] { "A", "B", "a" }, ) - """); - } - - public void AllItemsAreUnique_Generic_NullCollection_ShouldFail() - { - Action action = () => Assert.AllItemsAreUnique((IEnumerable?)null); - action.Should().Throw() - .WithMessage("Assert.AllItemsAreUnique failed. The parameter 'collection' is invalid. The value cannot be null."); - } - - public void AllItemsAreUnique_Generic_NullComparer_ShouldFail() - { - Action action = () => Assert.AllItemsAreUnique(new[] { 1, 2 }, (IEqualityComparer?)null); - action.Should().Throw() - .WithMessage("Assert.AllItemsAreUnique failed. The parameter 'comparer' is invalid. The value cannot be null."); - } - - public void AllItemsAreUnique_NonGeneric_AllUnique_ShouldPass() - { - ArrayList list = [1, "a", 3.5]; - Assert.AllItemsAreUnique(list); - } - - public void AllItemsAreUnique_NonGeneric_HasDuplicate_ShouldFail() - { - ArrayList list = [1, 2, 3, 2]; - Action action = () => Assert.AllItemsAreUnique(list); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - - duplicates: [2] - collection: [1, 2, 3, 2] - - Assert.AllItemsAreUnique(list) - """); - } - - public void AllItemsAreUnique_NonGeneric_WithComparer_HasDuplicate_ShouldFail() - { - ArrayList list = ["A", "B", "a"]; - Action action = () => Assert.AllItemsAreUnique(list, StringComparer.OrdinalIgnoreCase); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - - duplicates: ["a"] - collection: ["A", "B", "a"] - - Assert.AllItemsAreUnique(list, ) - """); - } - - public void AllItemsAreUnique_NonGeneric_NullCollection_ShouldFail() - { - Action action = () => Assert.AllItemsAreUnique(null); - action.Should().Throw() - .WithMessage("Assert.AllItemsAreUnique failed. The parameter 'collection' is invalid. The value cannot be null."); - } - - public void AllItemsAreUnique_NonGeneric_NullComparer_ShouldFail() - { - ArrayList list = [1, 2]; - Action action = () => Assert.AllItemsAreUnique(list, (IEqualityComparer?)null); - action.Should().Throw() - .WithMessage("Assert.AllItemsAreUnique failed. The parameter 'comparer' is invalid. The value cannot be null."); - } - - public void AllItemsAreUnique_NonGeneric_WithUserMessage_ShouldFail() - { - ArrayList list = [1, 1]; - Action action = () => Assert.AllItemsAreUnique(list, "User-provided message"); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - User-provided message - - duplicates: [1] - collection: [1, 1] - - Assert.AllItemsAreUnique(list) - """); - } - - public void AllItemsAreUnique_NonGeneric_SingleNull_ShouldPass() - { - ArrayList list = ["a", null, "b"]; - Assert.AllItemsAreUnique(list); - } - - public void AllItemsAreUnique_NonGeneric_NullDuplicate_ShouldFail() - { - ArrayList list = ["a", null, null]; - Action action = () => Assert.AllItemsAreUnique(list); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - - duplicates: [null] - collection: ["a", null, null] - - Assert.AllItemsAreUnique(list) - """); - } - - public void AllItemsAreUnique_Generic_ManyNulls_ReportsNullOnce_ShouldFail() - { - Action action = () => Assert.AllItemsAreUnique(new string?[] { null, "a", null, "b", null }); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - - duplicates: [null] - collection: [null, "a", null, "b", null] - - Assert.AllItemsAreUnique(new string?[] { null, "a", null, "b", null }) - """); - } - - public void AllItemsAreUnique_Generic_ManyDuplicatesOfSameValue_ReportsValueOnce_ShouldFail() - { - Action action = () => Assert.AllItemsAreUnique(new[] { 5, 5, 5, 5 }); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be unique. - - duplicates: [5] - collection: [5, 5, 5, 5] - - Assert.AllItemsAreUnique(new[] { 5, 5, 5, 5 }) - """); - } - - #endregion // AllItemsAreUnique - - #region AllItemsAreInstancesOfType - - public void AllItemsAreInstancesOfType_Generic_AllMatch_ShouldPass() - => Assert.AllItemsAreInstancesOfType(new object[] { "a", "b", "c" }); - - public void AllItemsAreInstancesOfType_Generic_DerivedTypes_ShouldPass() - => Assert.AllItemsAreInstancesOfType(new object[] { new DerivedAllItemsA(), new DerivedAllItemsB() }); - - public void AllItemsAreInstancesOfType_Generic_BaseTypeAcceptsDerived_ShouldPass() - => Assert.AllItemsAreInstancesOfType(new object[] { 1, "two", 3.0 }); - - public void AllItemsAreInstancesOfType_Generic_Empty_ShouldPass() - => Assert.AllItemsAreInstancesOfType(Array.Empty()); - - public void AllItemsAreInstancesOfType_Generic_NullElement_ShouldPass() - => Assert.AllItemsAreInstancesOfType(new object?[] { "a", null, "b" }); - - public void AllItemsAreInstancesOfType_Generic_HasMismatch_ShouldFail() - { - Action action = () => Assert.AllItemsAreInstancesOfType(new object[] { "a", 42, "b", true }); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be instances of the specified type. - - expected type: System.String (or derived) - mismatches: [index 1: System.Int32, index 3: System.Boolean] - collection: ["a", 42, "b", true] - - Assert.AllItemsAreInstancesOfType(new object[] { "a", 42, "b", true }) - """); - } - - public void AllItemsAreInstancesOfType_Generic_WithUserMessage_ShouldFail() - { - Action action = () => Assert.AllItemsAreInstancesOfType(new object[] { 1 }, "User-provided message"); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be instances of the specified type. - User-provided message - - expected type: System.String (or derived) - mismatches: [index 0: System.Int32] - collection: [1] - - Assert.AllItemsAreInstancesOfType(new object[] { 1 }) - """); - } - - public void AllItemsAreInstancesOfType_Generic_NullCollection_ShouldFail() - { - Action action = () => Assert.AllItemsAreInstancesOfType(null); - action.Should().Throw() - .WithMessage("Assert.AllItemsAreInstancesOfType failed. The parameter 'collection' is invalid. The value cannot be null."); - } - - public void AllItemsAreInstancesOfType_NonGeneric_AllMatch_ShouldPass() - { - ArrayList list = ["a", "b"]; - Assert.AllItemsAreInstancesOfType(list, typeof(string)); - } - - public void AllItemsAreInstancesOfType_NonGeneric_HasMismatch_ShouldFail() - { - ArrayList list = ["a", 42]; - Action action = () => Assert.AllItemsAreInstancesOfType(list, typeof(string)); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be instances of the specified type. - - expected type: System.String (or derived) - mismatches: [index 1: System.Int32] - collection: ["a", 42] - - Assert.AllItemsAreInstancesOfType(list, typeof(string)) - """); - } - - public void AllItemsAreInstancesOfType_NonGeneric_NullCollection_ShouldFail() - { - Action action = () => Assert.AllItemsAreInstancesOfType(null, typeof(string)); - action.Should().Throw() - .WithMessage("Assert.AllItemsAreInstancesOfType failed. The parameter 'collection' is invalid. The value cannot be null."); - } - - public void AllItemsAreInstancesOfType_NonGeneric_NullExpectedType_ShouldFail() - { - ArrayList list = ["a"]; - Action action = () => Assert.AllItemsAreInstancesOfType(list, null); - action.Should().Throw() - .WithMessage("Assert.AllItemsAreInstancesOfType failed. The parameter 'expectedType' is invalid. The value cannot be null."); - } - - public void AllItemsAreInstancesOfType_NonGeneric_WithUserMessage_ShouldFail() - { - ArrayList list = [1]; - Action action = () => Assert.AllItemsAreInstancesOfType(list, typeof(string), "User-provided message"); - action.Should().Throw() - .WithMessage( - """ - Assertion failed. Expected all items in collection to be instances of the specified type. - User-provided message - - expected type: System.String (or derived) - mismatches: [index 0: System.Int32] - collection: [1] - - Assert.AllItemsAreInstancesOfType(list, typeof(string)) - """); - } - - public void AllItemsAreInstancesOfType_NonGeneric_DerivedTypes_ShouldPass() - { - ArrayList list = [new DerivedAllItemsA(), new DerivedAllItemsB()]; - Assert.AllItemsAreInstancesOfType(list, typeof(DerivedAllItemsBase)); - } - - public void AllItemsAreInstancesOfType_NonGeneric_NullElement_ShouldPass() - { - ArrayList list = ["a", null, "b"]; - Assert.AllItemsAreInstancesOfType(list, typeof(string)); - } - - public void AllItemsAreInstancesOfType_NonGeneric_Empty_ShouldPass() - { - ArrayList list = []; - Assert.AllItemsAreInstancesOfType(list, typeof(string)); - } - - private class DerivedAllItemsBase; - - private sealed class DerivedAllItemsA : DerivedAllItemsBase; - - private sealed class DerivedAllItemsB : DerivedAllItemsBase; - - #endregion // AllItemsAreInstancesOfType -} diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs new file mode 100644 index 0000000000..4d16e68e26 --- /dev/null +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs @@ -0,0 +1,530 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections; + +using AwesomeAssertions; + +using TestFramework.ForTestingMSTest; + +namespace Microsoft.VisualStudio.TestPlatform.TestFramework.UnitTests; + +public partial class AssertTests : TestContainer +{ + #region AreAllNotNull + + public void AreAllNotNull_Generic_NoNulls_ShouldPass() + => Assert.AreAllNotNull(new[] { "a", "b", "c" }); + + public void AreAllNotNull_Generic_Empty_ShouldPass() + => Assert.AreAllNotNull(Array.Empty()); + + public void AreAllNotNull_Generic_ValueTypes_ShouldPass() + => Assert.AreAllNotNull(new[] { 1, 2, 3 }); + + public void AreAllNotNull_Generic_HasNull_ShouldFail() + { + Action action = () => Assert.AreAllNotNull(new[] { "a", null, "b", null }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be non-null. + + null indices: [1, 3] + collection: ["a", null, "b", null] + + Assert.AreAllNotNull(new[] { "a", null, "b", null }) + """); + } + + public void AreAllNotNull_Generic_WithUserMessage_ShouldFail() + { + Action action = () => Assert.AreAllNotNull(new[] { "a", null }, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be non-null. + User-provided message + + null indices: [1] + collection: ["a", null] + + Assert.AreAllNotNull(new[] { "a", null }) + """); + } + + public void AreAllNotNull_Generic_NullCollection_ShouldFail() + { + Action action = () => Assert.AreAllNotNull((IEnumerable?)null); + action.Should().Throw() + .WithMessage("Assert.AreAllNotNull failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AreAllNotNull_NonGeneric_NoNulls_ShouldPass() + { + ArrayList list = ["a", "b", "c"]; + Assert.AreAllNotNull(list); + } + + public void AreAllNotNull_NonGeneric_HasNull_ShouldFail() + { + ArrayList list = ["a", null, "b"]; + Action action = () => Assert.AreAllNotNull(list); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be non-null. + + null indices: [1] + collection: ["a", null, "b"] + + Assert.AreAllNotNull(list) + """); + } + + public void AreAllNotNull_NonGeneric_NullCollection_ShouldFail() + { + Action action = () => Assert.AreAllNotNull(null); + action.Should().Throw() + .WithMessage("Assert.AreAllNotNull failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AreAllNotNull_NonGeneric_WithUserMessage_ShouldFail() + { + ArrayList list = ["a", null]; + Action action = () => Assert.AreAllNotNull(list, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be non-null. + User-provided message + + null indices: [1] + collection: ["a", null] + + Assert.AreAllNotNull(list) + """); + } + + public void AreAllNotNull_Generic_NullableValueType_HasNull_ShouldFail() + { + Action action = () => Assert.AreAllNotNull(new int?[] { 1, null, 3 }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be non-null. + + null indices: [1] + collection: [1, null, 3] + + Assert.AreAllNotNull(new int?[] { 1, null, 3 }) + """); + } + + public void AreAllNotNull_Generic_LazyEnumerable_HasNull_ShouldFail() + { + static IEnumerable Lazy() + { + yield return "a"; + yield return null; + yield return "b"; + } + + Action action = () => Assert.AreAllNotNull(Lazy()); + action.Should().Throw() + .WithMessage("*null indices: [1]*collection:*"); + } + + #endregion // AreAllNotNull + + #region AreAllDistinct + + public void AreAllDistinct_Generic_AllDistinct_ShouldPass() + => Assert.AreAllDistinct(new[] { 1, 2, 3 }); + + public void AreAllDistinct_Generic_Empty_ShouldPass() + => Assert.AreAllDistinct(Array.Empty()); + + public void AreAllDistinct_Generic_SingleNull_ShouldPass() + => Assert.AreAllDistinct(new string?[] { "a", null, "b" }); + + public void AreAllDistinct_Generic_HasDuplicate_ShouldFail() + { + Action action = () => Assert.AreAllDistinct(new[] { 1, 2, 3, 4, 3 }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + + duplicates: [3] + collection: [1, 2, 3, 4, 3] + + Assert.AreAllDistinct(new[] { 1, 2, 3, 4, 3 }) + """); + } + + public void AreAllDistinct_Generic_HasMultipleDuplicates_ShouldFail() + { + Action action = () => Assert.AreAllDistinct(new[] { 1, 2, 3, 2, 1, 1 }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + + duplicates: [2, 1] + collection: [1, 2, 3, 2, 1, 1] + + Assert.AreAllDistinct(new[] { 1, 2, 3, 2, 1, 1 }) + """); + } + + public void AreAllDistinct_Generic_NullDuplicate_ShouldFail() + { + Action action = () => Assert.AreAllDistinct(new string?[] { "a", null, "b", null }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + + duplicates: [null] + collection: ["a", null, "b", null] + + Assert.AreAllDistinct(new string?[] { "a", null, "b", null }) + """); + } + + public void AreAllDistinct_Generic_WithUserMessage_ShouldFail() + { + Action action = () => Assert.AreAllDistinct(new[] { 1, 1 }, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + User-provided message + + duplicates: [1] + collection: [1, 1] + + Assert.AreAllDistinct(new[] { 1, 1 }) + """); + } + + public void AreAllDistinct_Generic_WithComparer_AllDistinct_ShouldPass() + => Assert.AreAllDistinct(new[] { "a", "B", "c" }, StringComparer.OrdinalIgnoreCase); + + public void AreAllDistinct_Generic_WithComparer_HasDuplicate_ShouldFail() + { + Action action = () => Assert.AreAllDistinct(new[] { "A", "B", "a" }, StringComparer.OrdinalIgnoreCase); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + + duplicates: ["a"] + collection: ["A", "B", "a"] + + Assert.AreAllDistinct(new[] { "A", "B", "a" }, ) + """); + } + + public void AreAllDistinct_Generic_NullCollection_ShouldFail() + { + Action action = () => Assert.AreAllDistinct((IEnumerable?)null); + action.Should().Throw() + .WithMessage("Assert.AreAllDistinct failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AreAllDistinct_Generic_NullComparer_ShouldFail() + { + Action action = () => Assert.AreAllDistinct(new[] { 1, 2 }, (IEqualityComparer?)null); + action.Should().Throw() + .WithMessage("Assert.AreAllDistinct failed. The parameter 'comparer' is invalid. The value cannot be null."); + } + + public void AreAllDistinct_NonGeneric_AllDistinct_ShouldPass() + { + ArrayList list = [1, "a", 3.5]; + Assert.AreAllDistinct(list); + } + + public void AreAllDistinct_NonGeneric_HasDuplicate_ShouldFail() + { + ArrayList list = [1, 2, 3, 2]; + Action action = () => Assert.AreAllDistinct(list); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + + duplicates: [2] + collection: [1, 2, 3, 2] + + Assert.AreAllDistinct(list) + """); + } + + public void AreAllDistinct_NonGeneric_WithComparer_HasDuplicate_ShouldFail() + { + ArrayList list = ["A", "B", "a"]; + Action action = () => Assert.AreAllDistinct(list, StringComparer.OrdinalIgnoreCase); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + + duplicates: ["a"] + collection: ["A", "B", "a"] + + Assert.AreAllDistinct(list, ) + """); + } + + public void AreAllDistinct_NonGeneric_NullCollection_ShouldFail() + { + Action action = () => Assert.AreAllDistinct(null); + action.Should().Throw() + .WithMessage("Assert.AreAllDistinct failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AreAllDistinct_NonGeneric_NullComparer_ShouldFail() + { + ArrayList list = [1, 2]; + Action action = () => Assert.AreAllDistinct(list, (IEqualityComparer?)null); + action.Should().Throw() + .WithMessage("Assert.AreAllDistinct failed. The parameter 'comparer' is invalid. The value cannot be null."); + } + + public void AreAllDistinct_NonGeneric_WithUserMessage_ShouldFail() + { + ArrayList list = [1, 1]; + Action action = () => Assert.AreAllDistinct(list, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + User-provided message + + duplicates: [1] + collection: [1, 1] + + Assert.AreAllDistinct(list) + """); + } + + public void AreAllDistinct_NonGeneric_SingleNull_ShouldPass() + { + ArrayList list = ["a", null, "b"]; + Assert.AreAllDistinct(list); + } + + public void AreAllDistinct_NonGeneric_NullDuplicate_ShouldFail() + { + ArrayList list = ["a", null, null]; + Action action = () => Assert.AreAllDistinct(list); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + + duplicates: [null] + collection: ["a", null, null] + + Assert.AreAllDistinct(list) + """); + } + + public void AreAllDistinct_Generic_ManyNulls_ReportsNullOnce_ShouldFail() + { + Action action = () => Assert.AreAllDistinct(new string?[] { null, "a", null, "b", null }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + + duplicates: [null] + collection: [null, "a", null, "b", null] + + Assert.AreAllDistinct(new string?[] { null, "a", null, "b", null }) + """); + } + + public void AreAllDistinct_Generic_ManyDuplicatesOfSameValue_ReportsValueOnce_ShouldFail() + { + Action action = () => Assert.AreAllDistinct(new[] { 5, 5, 5, 5 }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be distinct. + + duplicates: [5] + collection: [5, 5, 5, 5] + + Assert.AreAllDistinct(new[] { 5, 5, 5, 5 }) + """); + } + + #endregion // AreAllDistinct + + #region AreAllOfType + + public void AreAllOfType_Generic_AllMatch_ShouldPass() + => Assert.AreAllOfType(new object[] { "a", "b", "c" }); + + public void AreAllOfType_Generic_DerivedTypes_ShouldPass() + => Assert.AreAllOfType(new object[] { new DerivedAllItemsA(), new DerivedAllItemsB() }); + + public void AreAllOfType_Generic_BaseTypeAcceptsDerived_ShouldPass() + => Assert.AreAllOfType(new object[] { 1, "two", 3.0 }); + + public void AreAllOfType_Generic_Empty_ShouldPass() + => Assert.AreAllOfType(Array.Empty()); + + public void AreAllOfType_Generic_NullElement_ShouldFail() + { + Action action = () => Assert.AreAllOfType(new object?[] { "a", null, "b" }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be of the specified type. + + expected type: System.String (or derived) + mismatches: [index 1: ] + collection: ["a", null, "b"] + + Assert.AreAllOfType(new object?[] { "a", null, "b" }) + """); + } + + public void AreAllOfType_Generic_HasMismatch_ShouldFail() + { + Action action = () => Assert.AreAllOfType(new object[] { "a", 42, "b", true }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be of the specified type. + + expected type: System.String (or derived) + mismatches: [index 1: System.Int32, index 3: System.Boolean] + collection: ["a", 42, "b", true] + + Assert.AreAllOfType(new object[] { "a", 42, "b", true }) + """); + } + + public void AreAllOfType_Generic_WithUserMessage_ShouldFail() + { + Action action = () => Assert.AreAllOfType(new object[] { 1 }, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be of the specified type. + User-provided message + + expected type: System.String (or derived) + mismatches: [index 0: System.Int32] + collection: [1] + + Assert.AreAllOfType(new object[] { 1 }) + """); + } + + public void AreAllOfType_Generic_NullCollection_ShouldFail() + { + Action action = () => Assert.AreAllOfType(null); + action.Should().Throw() + .WithMessage("Assert.AreAllOfType failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AreAllOfType_NonGeneric_AllMatch_ShouldPass() + { + ArrayList list = ["a", "b"]; + Assert.AreAllOfType(typeof(string), list); + } + + public void AreAllOfType_NonGeneric_HasMismatch_ShouldFail() + { + ArrayList list = ["a", 42]; + Action action = () => Assert.AreAllOfType(typeof(string), list); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be of the specified type. + + expected type: System.String (or derived) + mismatches: [index 1: System.Int32] + collection: ["a", 42] + + Assert.AreAllOfType(typeof(string), list) + """); + } + + public void AreAllOfType_NonGeneric_NullCollection_ShouldFail() + { + Action action = () => Assert.AreAllOfType(typeof(string), null); + action.Should().Throw() + .WithMessage("Assert.AreAllOfType failed. The parameter 'collection' is invalid. The value cannot be null."); + } + + public void AreAllOfType_NonGeneric_NullExpectedType_ShouldFail() + { + ArrayList list = ["a"]; + Action action = () => Assert.AreAllOfType(null, list); + action.Should().Throw() + .WithMessage("Assert.AreAllOfType failed. The parameter 'expectedType' is invalid. The value cannot be null."); + } + + public void AreAllOfType_NonGeneric_WithUserMessage_ShouldFail() + { + ArrayList list = [1]; + Action action = () => Assert.AreAllOfType(typeof(string), list, "User-provided message"); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be of the specified type. + User-provided message + + expected type: System.String (or derived) + mismatches: [index 0: System.Int32] + collection: [1] + + Assert.AreAllOfType(typeof(string), list) + """); + } + + public void AreAllOfType_NonGeneric_DerivedTypes_ShouldPass() + { + ArrayList list = [new DerivedAllItemsA(), new DerivedAllItemsB()]; + Assert.AreAllOfType(typeof(DerivedAllItemsBase), list); + } + + public void AreAllOfType_NonGeneric_NullElement_ShouldFail() + { + ArrayList list = ["a", null, "b"]; + Action action = () => Assert.AreAllOfType(typeof(string), list); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be of the specified type. + + expected type: System.String (or derived) + mismatches: [index 1: ] + collection: ["a", null, "b"] + + Assert.AreAllOfType(typeof(string), list) + """); + } + + public void AreAllOfType_NonGeneric_Empty_ShouldPass() + { + ArrayList list = []; + Assert.AreAllOfType(typeof(string), list); + } + + private class DerivedAllItemsBase; + + private sealed class DerivedAllItemsA : DerivedAllItemsBase; + + private sealed class DerivedAllItemsB : DerivedAllItemsBase; + + #endregion // AreAllOfType +} From a4f87c8397febcea0b3f06c2a75019036a303f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Fri, 15 May 2026 17:51:19 +0200 Subject: [PATCH 4/6] Address expert-review findings: refactor AreAllOfType mismatch tracking and expand test coverage - Replace parallel List/List with a single List using a private readonly struct (avoids ValueTuple which is unavailable on net462). - Add Debug.Assert pinning the FormatCallSiteExpression contract that the rendered call-site ends with ')'. - Expand AreAllOfType tests to cover boxed value types, Nullable null elements, struct mismatches, non-generic value-type elements, and interface expected types. - Add AreAllDistinct tests pinning the null short-circuit semantics for user-provided comparers (null elements are not passed to the comparer). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Assertions/Assert.AreAllDistinct.cs | 1 + .../Assertions/Assert.AreAllOfType.cs | 44 +++++--- .../Assertions/AssertTests.AreAll.cs | 104 ++++++++++++++++++ 3 files changed, 131 insertions(+), 18 deletions(-) diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs index 9b52dd8320..334d87c3c9 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs @@ -209,6 +209,7 @@ private static void ReportAssertAreAllDistinctFailed(IEnumerable collectio // the placeholder so the rendered call-site reflects the overload that was actually invoked. // Note: range/index syntax (callSite[..^1]) is not used because System.Range/System.Index are unavailable // on net462 / netstandard2.0, the lowest TFMs targeted by this project. + Debug.Assert(callSite.Length > 0 && callSite[callSite.Length - 1] == ')', "FormatCallSiteExpression contract: rendered call-site must end with ')'."); return string.Concat(callSite.Substring(0, callSite.Length - 1), ", )"); } diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs index 3a7265f1d3..d28172713d 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs @@ -84,57 +84,52 @@ public static void AreAllOfType([NotNull] IEnumerable? collection, st private static void AreAllOfTypeImpl(IEnumerable collection, Type expectedType, string? genericTypeArgumentName, string? message, string collectionExpression, string? expectedTypeExpression) { List snapshot = [.. collection.Cast()]; - List? mismatchIndices = null; - List? mismatchTypes = null; + List? mismatches = null; for (int i = 0; i < snapshot.Count; i++) { object? element = snapshot[i]; if (element is null) { - mismatchIndices ??= []; - mismatchTypes ??= []; - mismatchIndices.Add(i); - mismatchTypes.Add(null); + mismatches ??= []; + mismatches.Add(new TypeMismatch(i, actualType: null)); } else if (!expectedType.IsInstanceOfType(element)) { - mismatchIndices ??= []; - mismatchTypes ??= []; - mismatchIndices.Add(i); - mismatchTypes.Add(element.GetType()); + mismatches ??= []; + mismatches.Add(new TypeMismatch(i, element.GetType())); } } - if (mismatchIndices is not null) + if (mismatches is not null) { - ReportAssertAreAllOfTypeFailed(snapshot, expectedType, mismatchIndices, mismatchTypes!, genericTypeArgumentName, message, collectionExpression, expectedTypeExpression); + ReportAssertAreAllOfTypeFailed(snapshot, expectedType, mismatches, genericTypeArgumentName, message, collectionExpression, expectedTypeExpression); } } [DoesNotReturn] - private static void ReportAssertAreAllOfTypeFailed(IEnumerable collection, Type expectedType, List mismatchIndices, List mismatchTypes, string? genericTypeArgumentName, string? message, string collectionExpression, string? expectedTypeExpression) + private static void ReportAssertAreAllOfTypeFailed(IEnumerable collection, Type expectedType, List mismatches, string? genericTypeArgumentName, string? message, string collectionExpression, string? expectedTypeExpression) { string collectionText = AssertionValueRenderer.RenderValue(collection); string expectedTypeText = $"{expectedType} (or derived)"; StringBuilder mismatchesBuilder = new(); mismatchesBuilder.Append('['); - for (int i = 0; i < mismatchIndices.Count; i++) + for (int i = 0; i < mismatches.Count; i++) { if (i > 0) { mismatchesBuilder.Append(", "); } - mismatchesBuilder.Append("index ").Append(mismatchIndices[i]).Append(": "); - Type? mismatchType = mismatchTypes[i]; - if (mismatchType is null) + TypeMismatch mismatch = mismatches[i]; + mismatchesBuilder.Append("index ").Append(mismatch.Index).Append(": "); + if (mismatch.ActualType is null) { mismatchesBuilder.Append(""); } else { - mismatchesBuilder.Append(mismatchType); + mismatchesBuilder.Append(mismatch.ActualType); } } @@ -162,5 +157,18 @@ private static void ReportAssertAreAllOfTypeFailed(IEnumerable collecti ReportAssertFailed(structured); } + private readonly struct TypeMismatch + { + public TypeMismatch(int index, Type? actualType) + { + Index = index; + ActualType = actualType; + } + + public int Index { get; } + + public Type? ActualType { get; } + } + #endregion // AreAllOfType } diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs index 4d16e68e26..e27a11cf51 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs @@ -363,6 +363,36 @@ Assertion failed. Expected all items in collection to be distinct. """); } + // Pins the current behavior: null elements are short-circuited and never passed to the user-provided comparer. + // A comparer that treats null as equal to "" is therefore not consulted, and [null, ""] is considered distinct. + public void AreAllDistinct_Generic_ComparerTreatsNullAsEmpty_NullAndEmpty_ShouldPass() + => Assert.AreAllDistinct(new string?[] { null, string.Empty }, new NullEqualsEmptyStringComparer()); + + // Pins the current behavior: a comparer that throws on null is never invoked with a null argument because + // null elements are short-circuited before the comparer is consulted. + public void AreAllDistinct_Generic_ComparerThrowsOnNull_WithNulls_ShouldNotInvokeComparerForNull() + => Assert.AreAllDistinct(new string?[] { null, "a", "b" }, new ThrowOnNullStringComparer()); + + private sealed class NullEqualsEmptyStringComparer : IEqualityComparer + { + public bool Equals(string? x, string? y) => (x ?? string.Empty) == (y ?? string.Empty); + + public int GetHashCode(string? obj) => (obj ?? string.Empty).GetHashCode(); + } + + private sealed class ThrowOnNullStringComparer : IEqualityComparer + { + public bool Equals(string? x, string? y) + => x is null || y is null + ? throw new InvalidOperationException("Comparer should not be invoked with null.") + : x == y; + + public int GetHashCode(string? obj) + => obj is null + ? throw new InvalidOperationException("Comparer should not be invoked with null.") + : obj.GetHashCode(); + } + #endregion // AreAllDistinct #region AreAllOfType @@ -520,6 +550,80 @@ public void AreAllOfType_NonGeneric_Empty_ShouldPass() Assert.AreAllOfType(typeof(string), list); } + public void AreAllOfType_Generic_BoxedValueType_AllMatch_ShouldPass() + => Assert.AreAllOfType(new object[] { 1, 2, 3 }); + + public void AreAllOfType_Generic_BoxedValueType_HasMismatch_ShouldFail() + { + Action action = () => Assert.AreAllOfType(new object[] { 1, "x" }); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be of the specified type. + + expected type: System.Int32 (or derived) + mismatches: [index 1: System.String] + collection: [1, "x"] + + Assert.AreAllOfType(new object[] { 1, "x" }) + """); + } + + // Pins the current behavior of `AreAllOfType` for nullable value types: a `null` element fails because + // `typeof(int?).IsInstanceOfType(null)` returns false. Boxed non-null nullable values are accepted because + // boxing erases the `Nullable` wrapper. + public void AreAllOfType_Generic_NullableValueType_NullElement_ShouldFail() + { + Action action = () => Assert.AreAllOfType(new object?[] { 1, null, 3 }); + action.Should().Throw() + .WithMessage("*mismatches: [index 1: ]*"); + } + + public void AreAllOfType_Generic_StructMismatch_ShouldFail() + { + Action action = () => Assert.AreAllOfType(new object[] { DateTime.UtcNow, "x" }); + action.Should().Throw() + .WithMessage( + """ + *expected type: System.DateTime (or derived) + mismatches: [index 1: System.String]* + """); + } + + public void AreAllOfType_NonGeneric_BoxedValueType_AllMatch_ShouldPass() + { + ArrayList list = [1, 2, 3]; + Assert.AreAllOfType(typeof(int), list); + } + + public void AreAllOfType_NonGeneric_BoxedValueType_HasMismatch_ShouldFail() + { + ArrayList list = [1, "x"]; + Action action = () => Assert.AreAllOfType(typeof(int), list); + action.Should().Throw() + .WithMessage( + """ + Assertion failed. Expected all items in collection to be of the specified type. + + expected type: System.Int32 (or derived) + mismatches: [index 1: System.String] + collection: [1, "x"] + + Assert.AreAllOfType(typeof(int), list) + """); + } + + public void AreAllOfType_Generic_Interface_AllImplement_ShouldPass() + => Assert.AreAllOfType(new object[] { new System.IO.MemoryStream(), new System.IO.MemoryStream() }); + + public void AreAllOfType_NonGeneric_Interface_HasMismatch_ShouldFail() + { + ArrayList list = [new System.IO.MemoryStream(), "not-disposable-string"]; + Action action = () => Assert.AreAllOfType(typeof(IDisposable), list); + action.Should().Throw() + .WithMessage("*expected type: System.IDisposable (or derived)*mismatches: [index 1: System.String]*"); + } + private class DerivedAllItemsBase; private sealed class DerivedAllItemsA : DerivedAllItemsBase; From eb1172dad5e25d5a56179b5163efa98c3281f073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Fri, 15 May 2026 20:11:49 +0200 Subject: [PATCH 5/6] Address AreAll review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Assertions/Assert.AreAllDistinct.cs | 29 +++++++------- .../Assertions/Assert.AreAllOfType.cs | 2 +- .../Assertions/AssertTests.AreAll.cs | 39 +++++++++++++++++-- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs index 334d87c3c9..93e77e81c2 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs @@ -37,7 +37,7 @@ public sealed partial class Assert public static void AreAllDistinct([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { CheckParameterNotNull(collection, "Assert.AreAllDistinct", "collection"); - AreAllDistinctImpl(collection, EqualityComparer.Default, hasUserComparer: false, message, collectionExpression); + AreAllDistinctImpl(collection, EqualityComparer.Default, comparerTypeName: null, message, collectionExpression); } /// @@ -67,7 +67,7 @@ public static void AreAllDistinct([NotNull] IEnumerable? collection, [NotN { CheckParameterNotNull(collection, "Assert.AreAllDistinct", "collection"); CheckParameterNotNull(comparer, "Assert.AreAllDistinct", "comparer"); - AreAllDistinctImpl(collection, comparer, hasUserComparer: true, message, collectionExpression); + AreAllDistinctImpl(collection, comparer, comparerTypeName: comparer.GetType().Name, message, collectionExpression); } /// @@ -92,7 +92,7 @@ public static void AreAllDistinct([NotNull] IEnumerable? collection, [NotN public static void AreAllDistinct([NotNull] IEnumerable? collection, string? message = "", [CallerArgumentExpression(nameof(collection))] string collectionExpression = "") { CheckParameterNotNull(collection, "Assert.AreAllDistinct", "collection"); - AreAllDistinctImpl(collection.Cast(), EqualityComparer.Default, hasUserComparer: false, message, collectionExpression); + AreAllDistinctImpl(collection.Cast(), EqualityComparer.Default, comparerTypeName: null, message, collectionExpression); } /// @@ -121,17 +121,15 @@ public static void AreAllDistinct([NotNull] IEnumerable? collection, [NotNull] I { CheckParameterNotNull(collection, "Assert.AreAllDistinct", "collection"); CheckParameterNotNull(comparer, "Assert.AreAllDistinct", "comparer"); - AreAllDistinctImpl(collection.Cast(), new NonGenericEqualityComparerAdapter(comparer), hasUserComparer: true, message, collectionExpression); + AreAllDistinctImpl(collection.Cast(), new NonGenericEqualityComparerAdapter(comparer), comparerTypeName: comparer.GetType().Name, message, collectionExpression); } #pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. - private static void AreAllDistinctImpl(IEnumerable collection, IEqualityComparer comparer, bool hasUserComparer, string? message, string collectionExpression) + private static void AreAllDistinctImpl(IEnumerable collection, IEqualityComparer comparer, string? comparerTypeName, string? message, string collectionExpression) { List snapshot = collection is List list ? list : [.. collection]; -#pragma warning disable IDE0028 // Collection initialization can be simplified - target-typed new with constructor argument is preferred over collection expression here HashSet seen = new(comparer); -#pragma warning restore IDE0028 bool seenNull = false; List? duplicates = null; @@ -160,9 +158,7 @@ private static void AreAllDistinctImpl(IEnumerable collection, IEqualityCo if (!seen.Add(item)) { -#pragma warning disable IDE0028 - duplicatesSeen ??= new HashSet(comparer); -#pragma warning restore IDE0028 + duplicatesSeen ??= new(comparer); if (duplicatesSeen.Add(item)) { duplicates ??= []; @@ -173,13 +169,13 @@ private static void AreAllDistinctImpl(IEnumerable collection, IEqualityCo if (duplicates is not null) { - ReportAssertAreAllDistinctFailed(snapshot, duplicates, hasUserComparer, message, collectionExpression); + ReportAssertAreAllDistinctFailed(snapshot, duplicates, comparerTypeName, message, collectionExpression); } } #pragma warning restore CS8714 [DoesNotReturn] - private static void ReportAssertAreAllDistinctFailed(IEnumerable collection, List duplicates, bool hasUserComparer, string? message, string collectionExpression) + private static void ReportAssertAreAllDistinctFailed(IEnumerable collection, List duplicates, string? comparerTypeName, string? message, string collectionExpression) { string collectionText = AssertionValueRenderer.RenderValue(collection); string duplicatesText = AssertionValueRenderer.RenderValue(duplicates); @@ -188,11 +184,16 @@ private static void ReportAssertAreAllDistinctFailed(IEnumerable collectio .AddLine("duplicates:", duplicatesText) .AddLine("collection:", collectionText); + if (comparerTypeName is not null) + { + evidence.AddLine("comparer:", comparerTypeName); + } + StructuredAssertionMessage structured = new(FrameworkMessages.AreAllDistinctFailedSummary); structured.WithUserMessage(message); structured.WithEvidence(evidence); structured.WithExpectedAndActual(expectedText: null, actualText: collectionText); - structured.WithCallSiteExpression(BuildCallSiteWithComparerForCollection("Assert.AreAllDistinct", collectionExpression, hasUserComparer)); + structured.WithCallSiteExpression(BuildCallSiteWithComparerForCollection("Assert.AreAllDistinct", collectionExpression, comparerTypeName is not null)); ReportAssertFailed(structured); } @@ -224,7 +225,7 @@ private sealed class NonGenericEqualityComparerAdapter : IEqualityComparer _comparer = comparer; - public new bool Equals(object? x, object? y) => _comparer.Equals(x, y); + public bool Equals(object? x, object? y) => _comparer.Equals(x, y); public int GetHashCode(object? obj) => obj is null ? 0 : _comparer.GetHashCode(obj); } diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs index d28172713d..5ae37365b4 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreAllOfType.cs @@ -151,7 +151,7 @@ private static void ReportAssertAreAllOfTypeFailed(IEnumerable collecti StructuredAssertionMessage structured = new(FrameworkMessages.AreAllOfTypeFailedSummary); structured.WithUserMessage(message); structured.WithEvidence(evidence); - structured.WithExpectedAndActual(expectedText: null, actualText: collectionText); + structured.WithExpectedAndActual(expectedTypeText, collectionText); structured.WithCallSiteExpression(callSite); ReportAssertFailed(structured); diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs index e27a11cf51..6ae04d2944 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreAll.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections; @@ -210,11 +210,11 @@ Assertion failed. Expected all items in collection to be distinct. } public void AreAllDistinct_Generic_WithComparer_AllDistinct_ShouldPass() - => Assert.AreAllDistinct(new[] { "a", "B", "c" }, StringComparer.OrdinalIgnoreCase); + => Assert.AreAllDistinct(new[] { "a", "B", "c" }, new CaseInsensitiveStringComparer()); public void AreAllDistinct_Generic_WithComparer_HasDuplicate_ShouldFail() { - Action action = () => Assert.AreAllDistinct(new[] { "A", "B", "a" }, StringComparer.OrdinalIgnoreCase); + Action action = () => Assert.AreAllDistinct(new[] { "A", "B", "a" }, new CaseInsensitiveStringComparer()); action.Should().Throw() .WithMessage( """ @@ -222,6 +222,7 @@ Assertion failed. Expected all items in collection to be distinct. duplicates: ["a"] collection: ["A", "B", "a"] + comparer: CaseInsensitiveStringComparer Assert.AreAllDistinct(new[] { "A", "B", "a" }, ) """); @@ -266,7 +267,7 @@ Assertion failed. Expected all items in collection to be distinct. public void AreAllDistinct_NonGeneric_WithComparer_HasDuplicate_ShouldFail() { ArrayList list = ["A", "B", "a"]; - Action action = () => Assert.AreAllDistinct(list, StringComparer.OrdinalIgnoreCase); + Action action = () => Assert.AreAllDistinct(list, new CaseInsensitiveStringComparer()); action.Should().Throw() .WithMessage( """ @@ -274,6 +275,7 @@ Assertion failed. Expected all items in collection to be distinct. duplicates: ["a"] collection: ["A", "B", "a"] + comparer: CaseInsensitiveStringComparer Assert.AreAllDistinct(list, ) """); @@ -373,6 +375,17 @@ public void AreAllDistinct_Generic_ComparerTreatsNullAsEmpty_NullAndEmpty_Should public void AreAllDistinct_Generic_ComparerThrowsOnNull_WithNulls_ShouldNotInvokeComparerForNull() => Assert.AreAllDistinct(new string?[] { null, "a", "b" }, new ThrowOnNullStringComparer()); + private sealed class CaseInsensitiveStringComparer : IEqualityComparer, IEqualityComparer + { + public bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); + + public int GetHashCode(string? obj) => obj is null ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(obj); + + bool IEqualityComparer.Equals(object? x, object? y) => Equals(x as string, y as string); + + int IEqualityComparer.GetHashCode(object obj) => obj is string value ? GetHashCode(value) : 0; + } + private sealed class NullEqualsEmptyStringComparer : IEqualityComparer { public bool Equals(string? x, string? y) => (x ?? string.Empty) == (y ?? string.Empty); @@ -458,6 +471,24 @@ Assertion failed. Expected all items in collection to be of the specified type. """); } + public void AreAllOfType_Generic_HasMismatch_ShouldPopulateExpectedAndActualPayload() + { + try + { + Assert.AreAllOfType(new object[] { 1 }); + } + catch (AssertFailedException ex) + { + ex.ExpectedText.Should().Be("System.String (or derived)"); + ex.ActualText.Should().Be("[1]"); + ex.Data["assert.expected"].Should().Be("System.String (or derived)"); + ex.Data["assert.actual"].Should().Be("[1]"); + return; + } + + throw new AssertFailedException("Expected AssertFailedException was not thrown."); + } + public void AreAllOfType_Generic_NullCollection_ShouldFail() { Action action = () => Assert.AreAllOfType(null); From 297979e1da948ec1c6670cfd5030d5b15013b5dc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 16 May 2026 11:58:25 +0000 Subject: [PATCH 6/6] Fix AreAllDistinct analyzer build issues Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com> --- .../TestFramework/Assertions/Assert.AreAllDistinct.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs index 14cb832662..0929bfe3dc 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreAllDistinct.cs @@ -129,7 +129,9 @@ private static void AreAllDistinctImpl(IEnumerable collection, IEqualityCo { List snapshot = collection is List list ? list : [.. collection]; - HashSet seen = new HashSet(comparer); +#pragma warning disable IDE0028 // Collection initialization can be simplified - target-typed `new` cannot pass the comparer in the same syntactic form expected. + var seen = new HashSet(comparer); +#pragma warning restore IDE0028 bool seenNull = false; List? duplicates = null; @@ -158,7 +160,9 @@ private static void AreAllDistinctImpl(IEnumerable collection, IEqualityCo if (!seen.Add(item)) { - duplicatesSeen ??= new HashSet(comparer); +#pragma warning disable IDE0028 // Collection initialization can be simplified - target-typed `new` cannot pass the comparer in the same syntactic form expected. + duplicatesSeen ??= new(comparer); +#pragma warning restore IDE0028 if (duplicatesSeen.Add(item)) { duplicates ??= []; @@ -209,7 +213,7 @@ private static void ReportAssertAreAllDistinctFailed(IEnumerable collectio // FormatCallSiteExpression has no overload accepting a third argument expression; insert // the placeholder so the rendered call-site reflects the overload that was actually invoked. Debug.Assert(callSite.Length > 0 && callSite[callSite.Length - 1] == ')', "FormatCallSiteExpression contract: rendered call-site must end with ')'."); - return string.Concat(callSite[..^1], ", )"); + return string.Concat(callSite.Remove(callSite.Length - 1), ", )"); } #endregion // AreAllDistinct