From ba0b1df185d5f25dc9f3257dbbad075079912482 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 21:07:52 +0200 Subject: [PATCH] Migrate string AreEqual messages to RFC 012 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...ert.AreEqual.InterpolatedStringHandlers.cs | 44 ++- .../Assertions/Assert.AreEqual.String.cs | 281 ++++++++------- .../Assertions/Assert.AreEqual.cs | 104 +----- .../Resources/FrameworkMessages.resx | 13 +- .../Resources/xlf/FrameworkMessages.cs.xlf | 77 +++-- .../Resources/xlf/FrameworkMessages.de.xlf | 77 +++-- .../Resources/xlf/FrameworkMessages.es.xlf | 77 +++-- .../Resources/xlf/FrameworkMessages.fr.xlf | 77 +++-- .../Resources/xlf/FrameworkMessages.it.xlf | 77 +++-- .../Resources/xlf/FrameworkMessages.ja.xlf | 77 +++-- .../Resources/xlf/FrameworkMessages.ko.xlf | 77 +++-- .../Resources/xlf/FrameworkMessages.pl.xlf | 77 +++-- .../Resources/xlf/FrameworkMessages.pt-BR.xlf | 77 +++-- .../Resources/xlf/FrameworkMessages.ru.xlf | 77 +++-- .../Resources/xlf/FrameworkMessages.tr.xlf | 77 +++-- .../xlf/FrameworkMessages.zh-Hans.xlf | 77 +++-- .../xlf/FrameworkMessages.zh-Hant.xlf | 77 +++-- .../Assertions/AssertTests.AreEqualTests.cs | 320 +++++++----------- 18 files changed, 909 insertions(+), 854 deletions(-) diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.InterpolatedStringHandlers.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.InterpolatedStringHandlers.cs index a887cc5fac..9f5a395e21 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.InterpolatedStringHandlers.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.InterpolatedStringHandlers.cs @@ -157,7 +157,7 @@ internal void ComputeAssertion(string notExpectedExpression, string actualExpres public readonly struct AssertNonGenericAreEqualInterpolatedStringHandler { private readonly StringBuilder? _builder; - private readonly Action? _failAction; + private readonly Action? _failAction; public AssertNonGenericAreEqualInterpolatedStringHandler(int literalLength, int formattedCount, float expected, float actual, float delta, out bool shouldAppend) { @@ -165,7 +165,8 @@ public AssertNonGenericAreEqualInterpolatedStringHandler(int literalLength, int if (shouldAppend) { _builder = new StringBuilder(literalLength + formattedCount); - _failAction = userMessage => ReportAssertAreEqualFailed(expected, actual, delta, userMessage); + _failAction = (userMessage, expectedExpression, actualExpression) => + ReportAssertAreEqualFailed(expected, actual, delta, BuildUserMessageForExpectedExpressionAndActualExpression(userMessage, expectedExpression, actualExpression)); } } @@ -175,7 +176,8 @@ public AssertNonGenericAreEqualInterpolatedStringHandler(int literalLength, int if (shouldAppend) { _builder = new StringBuilder(literalLength + formattedCount); - _failAction = userMessage => ReportAssertAreEqualFailed(expected, actual, delta, userMessage); + _failAction = (userMessage, expectedExpression, actualExpression) => + ReportAssertAreEqualFailed(expected, actual, delta, BuildUserMessageForExpectedExpressionAndActualExpression(userMessage, expectedExpression, actualExpression)); } } @@ -185,7 +187,8 @@ public AssertNonGenericAreEqualInterpolatedStringHandler(int literalLength, int if (shouldAppend) { _builder = new StringBuilder(literalLength + formattedCount); - _failAction = userMessage => ReportAssertAreEqualFailed(expected, actual, delta, userMessage); + _failAction = (userMessage, expectedExpression, actualExpression) => + ReportAssertAreEqualFailed(expected, actual, delta, BuildUserMessageForExpectedExpressionAndActualExpression(userMessage, expectedExpression, actualExpression)); } } @@ -195,13 +198,20 @@ public AssertNonGenericAreEqualInterpolatedStringHandler(int literalLength, int if (shouldAppend) { _builder = new StringBuilder(literalLength + formattedCount); - _failAction = userMessage => ReportAssertAreEqualFailed(expected, actual, delta, userMessage); + _failAction = (userMessage, expectedExpression, actualExpression) => + ReportAssertAreEqualFailed(expected, actual, delta, BuildUserMessageForExpectedExpressionAndActualExpression(userMessage, expectedExpression, actualExpression)); } } public AssertNonGenericAreEqualInterpolatedStringHandler(int literalLength, int formattedCount, string? expected, string? actual, bool ignoreCase, out bool shouldAppend) - : this(literalLength, formattedCount, expected, actual, ignoreCase, CultureInfo.InvariantCulture, out shouldAppend) { + shouldAppend = AreEqualFailing(expected, actual, ignoreCase, CultureInfo.InvariantCulture); + if (shouldAppend) + { + _builder = new StringBuilder(literalLength + formattedCount); + _failAction = (userMessage, expectedExpression, actualExpression) => + ReportAssertAreEqualFailed(expected, actual, ignoreCase, CultureInfo.InvariantCulture, cultureExplicit: false, userMessage, expectedExpression, actualExpression); + } } public AssertNonGenericAreEqualInterpolatedStringHandler(int literalLength, int formattedCount, string? expected, string? actual, bool ignoreCase, CultureInfo culture, out bool shouldAppend) @@ -211,18 +221,13 @@ public AssertNonGenericAreEqualInterpolatedStringHandler(int literalLength, int if (shouldAppend) { _builder = new StringBuilder(literalLength + formattedCount); - _failAction = userMessage => ReportAssertAreEqualFailed(expected, actual, ignoreCase, culture, userMessage); + _failAction = (userMessage, expectedExpression, actualExpression) => + ReportAssertAreEqualFailed(expected, actual, ignoreCase, culture, cultureExplicit: true, userMessage, expectedExpression, actualExpression); } } internal void ComputeAssertion(string expectedExpression, string actualExpression) - { - if (_failAction is not null) - { - _builder!.Insert(0, string.Format(CultureInfo.CurrentCulture, FrameworkMessages.CallerArgumentExpressionTwoParametersMessage, "expected", expectedExpression, "actual", actualExpression) + " "); - _failAction.Invoke(_builder!.ToString()); - } - } + => _failAction?.Invoke(_builder!.ToString(), expectedExpression, actualExpression); public void AppendLiteral(string value) => _builder!.Append(value); @@ -310,8 +315,14 @@ public AssertNonGenericAreNotEqualInterpolatedStringHandler(int literalLength, i } public AssertNonGenericAreNotEqualInterpolatedStringHandler(int literalLength, int formattedCount, string? notExpected, string? actual, bool ignoreCase, out bool shouldAppend) - : this(literalLength, formattedCount, notExpected, actual, ignoreCase, CultureInfo.InvariantCulture, out shouldAppend) { + shouldAppend = AreNotEqualFailing(notExpected, actual, ignoreCase, CultureInfo.InvariantCulture); + if (shouldAppend) + { + _builder = new StringBuilder(literalLength + formattedCount); + _failAction = (userMessage, notExpectedExpr, actualExpr) => + ReportAssertAreNotEqualFailed(notExpected, actual, ignoreCase, CultureInfo.InvariantCulture, cultureExplicit: false, userMessage, notExpectedExpr, actualExpr); + } } public AssertNonGenericAreNotEqualInterpolatedStringHandler(int literalLength, int formattedCount, string? notExpected, string? actual, bool ignoreCase, CultureInfo culture, out bool shouldAppend) @@ -321,7 +332,8 @@ public AssertNonGenericAreNotEqualInterpolatedStringHandler(int literalLength, i if (shouldAppend) { _builder = new StringBuilder(literalLength + formattedCount); - _failAction = (userMessage, notExpectedExpr, actualExpr) => ReportAssertAreNotEqualFailed(notExpected, actual, userMessage, notExpectedExpr, actualExpr); + _failAction = (userMessage, notExpectedExpr, actualExpr) => + ReportAssertAreNotEqualFailed(notExpected, actual, ignoreCase, culture, cultureExplicit: true, userMessage, notExpectedExpr, actualExpr); } } diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.String.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.String.cs index 2fa3024a36..19a248c683 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.String.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.String.cs @@ -17,32 +17,131 @@ private static bool AreEqualFailing(string? expected, string? actual, bool ignor => CompareInternal(expected, actual, ignoreCase, culture) != 0; [DoesNotReturn] - private static void ReportAssertAreEqualFailed(string? expected, string? actual, bool ignoreCase, CultureInfo culture, string userMessage) + private static void ReportAssertAreEqualFailed(string? expected, string? actual, bool ignoreCase, CultureInfo culture, bool cultureExplicit, string? message, string expectedExpression, string actualExpression) { - string finalMessage; + string expectedRendered = AssertionValueRenderer.RenderValue(expected); + string actualRendered = AssertionValueRenderer.RenderValue(actual); - // If the user requested to match case, and the difference between expected/actual is casing only, then we use a different message. - if (!ignoreCase && CompareInternal(expected, actual, ignoreCase: true, culture) == 0) + StructuredAssertionMessage structured = new(FrameworkMessages.AreEqualStringsFailedSummary); + if (!ignoreCase && expected is not null && actual is not null && CompareInternal(expected, actual, ignoreCase: true, culture) == 0) { - finalMessage = string.Format( - CultureInfo.CurrentCulture, - FrameworkMessages.AreEqualCaseFailMsg, - userMessage, - ReplaceNulls(expected), - ReplaceNulls(actual)); + structured.WithAdditionalSummaryLine(FrameworkMessages.AreEqualStringsCaseOnlyDifferenceMsg); } - else + + if (expected is not null && actual is not null) { - // Use enhanced string comparison for string-specific failures - finalMessage = FormatStringComparisonMessage(expected, actual, userMessage); + int diffIndex = FindFirstStringDifference(expected, actual, ignoreCase, culture); + if (diffIndex >= 0) + { + AppendStringDiffSummary(structured, expected, actual, diffIndex); + } } - ReportAssertFailed("Assert.AreEqual", finalMessage); + structured.WithUserMessage(message); + structured.WithEvidence(CreateStringComparisonEvidence("expected:", expectedRendered, actualRendered, ignoreCase, culture, cultureExplicit)); + structured.WithExpectedAndActual(expectedRendered, actualRendered); + structured.WithCallSiteExpression(FormatCallSiteExpression("Assert.AreEqual", expectedExpression, actualExpression, "", "")); + + ReportAssertFailed(structured); + } + + [DoesNotReturn] + private static void ReportAssertAreNotEqualFailed(string? notExpected, string? actual, bool ignoreCase, CultureInfo culture, bool cultureExplicit, string? message, string notExpectedExpression, string actualExpression) + { + string notExpectedRendered = AssertionValueRenderer.RenderValue(notExpected); + string actualRendered = AssertionValueRenderer.RenderValue(actual); + + StructuredAssertionMessage structured = new(ignoreCase + ? FrameworkMessages.AreNotEqualStringsCaseInsensitiveFailedSummary + : FrameworkMessages.AreNotEqualStringsFailedSummary); + structured.WithUserMessage(message); + structured.WithEvidence(CreateStringComparisonEvidence("not expected:", notExpectedRendered, actualRendered, ignoreCase, culture, cultureExplicit)); + structured.WithExpectedAndActual($"not {notExpectedRendered}", actualRendered); + structured.WithCallSiteExpression(FormatCallSiteExpression("Assert.AreNotEqual", notExpectedExpression, actualExpression, "", "")); + + ReportAssertFailed(structured); + } + + private static EvidenceBlock CreateStringComparisonEvidence(string firstLabel, string firstValue, string actualValue, bool ignoreCase, CultureInfo culture, bool cultureExplicit) + { + EvidenceBlock evidence = EvidenceBlock.Create() + .AddLine(firstLabel, firstValue) + .AddLine("actual:", actualValue); + + if (ignoreCase) + { + evidence.AddLine("ignore case:", "true"); + } + + // Track whether the culture overload was used so explicit CultureInfo.InvariantCulture remains self-describing as culture: "". + if (cultureExplicit) + { + evidence.AddLine("culture:", culture.Name); + } + + return evidence; } private static bool AreNotEqualFailing(string? notExpected, string? actual, bool ignoreCase, CultureInfo culture) => CompareInternal(notExpected, actual, ignoreCase, culture) == 0; + private static int FindFirstStringDifference(string expected, string actual, bool ignoreCase, CultureInfo culture) + { + if (!ignoreCase && culture.Equals(CultureInfo.InvariantCulture)) + { + return FindFirstStringDifference(expected, actual); + } + + int expectedIndex = 0; + int actualIndex = 0; + + while (expectedIndex < expected.Length && actualIndex < actual.Length) + { + if (CompareInternal(expected[expectedIndex].ToString(), actual[actualIndex].ToString(), ignoreCase, culture) == 0) + { + expectedIndex++; + actualIndex++; + continue; + } + + if (TryAdvanceMatchingWindow(expected, actual, ref expectedIndex, ref actualIndex, ignoreCase, culture)) + { + continue; + } + + return Math.Min(expectedIndex, actualIndex); + } + + return expectedIndex != expected.Length || actualIndex != actual.Length + ? Math.Min(expectedIndex, actualIndex) + : -1; + } + + private static bool TryAdvanceMatchingWindow(string expected, string actual, ref int expectedIndex, ref int actualIndex, bool ignoreCase, CultureInfo culture) + { + const int MaxWindowLength = 3; + + for (int expectedWindow = 1; expectedWindow <= MaxWindowLength && expectedIndex + expectedWindow <= expected.Length; expectedWindow++) + { + for (int actualWindow = 1; actualWindow <= MaxWindowLength && actualIndex + actualWindow <= actual.Length; actualWindow++) + { + if (expectedWindow == 1 && actualWindow == 1) + { + continue; + } + + if (CompareInternal(expected.Substring(expectedIndex, expectedWindow), actual.Substring(actualIndex, actualWindow), ignoreCase, culture) == 0) + { + expectedIndex += expectedWindow; + actualIndex += actualWindow; + return true; + } + } + } + + return false; + } + /// /// Tests whether the specified strings are equal and throws an exception /// if they are not equal. The invariant culture is used for the comparison. @@ -74,7 +173,16 @@ private static bool AreNotEqualFailing(string? notExpected, string? actual, bool /// Thrown if is not equal to . /// public static void AreEqual(string? expected, string? actual, bool ignoreCase, string? message = "", [CallerArgumentExpression(nameof(expected))] string expectedExpression = "", [CallerArgumentExpression(nameof(actual))] string actualExpression = "") - => AreEqual(expected, actual, ignoreCase, CultureInfo.InvariantCulture, message, expectedExpression, actualExpression); + { + TelemetryCollector.TrackAssertionCall("Assert.AreEqual"); + + if (!AreEqualFailing(expected, actual, ignoreCase, CultureInfo.InvariantCulture)) + { + return; + } + + ReportAssertAreEqualFailed(expected, actual, ignoreCase, CultureInfo.InvariantCulture, cultureExplicit: false, message, expectedExpression, actualExpression); + } /// #pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/76578 @@ -139,8 +247,7 @@ public static void AreEqual(string? expected, string? actual, bool ignoreCase, C return; } - string userMessage = BuildUserMessageForExpectedExpressionAndActualExpression(message, expectedExpression, actualExpression); - ReportAssertAreEqualFailed(expected, actual, ignoreCase, culture, userMessage); + ReportAssertAreEqualFailed(expected, actual, ignoreCase, culture, cultureExplicit: true, message, expectedExpression, actualExpression); } /// @@ -175,7 +282,16 @@ public static void AreEqual(string? expected, string? actual, bool ignoreCase, C /// Thrown if is equal to . /// public static void AreNotEqual(string? notExpected, string? actual, bool ignoreCase, string? message = "", [CallerArgumentExpression(nameof(notExpected))] string notExpectedExpression = "", [CallerArgumentExpression(nameof(actual))] string actualExpression = "") - => AreNotEqual(notExpected, actual, ignoreCase, CultureInfo.InvariantCulture, message, notExpectedExpression, actualExpression); + { + TelemetryCollector.TrackAssertionCall("Assert.AreNotEqual"); + + if (!AreNotEqualFailing(notExpected, actual, ignoreCase, CultureInfo.InvariantCulture)) + { + return; + } + + ReportAssertAreNotEqualFailed(notExpected, actual, ignoreCase, CultureInfo.InvariantCulture, cultureExplicit: false, message, notExpectedExpression, actualExpression); + } /// #pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/76578 @@ -235,140 +351,15 @@ public static void AreNotEqual(string? notExpected, string? actual, bool ignoreC { TelemetryCollector.TrackAssertionCall("Assert.AreNotEqual"); - CheckParameterNotNull(culture, "Assert.AreNotEqual", "culture"); + CheckParameterNotNull(culture, "Assert.AreNotEqual", nameof(culture)); if (!AreNotEqualFailing(notExpected, actual, ignoreCase, culture)) { return; } - ReportAssertAreNotEqualFailed(notExpected, actual, message, notExpectedExpression, actualExpression); + ReportAssertAreNotEqualFailed(notExpected, actual, ignoreCase, culture, cultureExplicit: true, message, notExpectedExpression, actualExpression); } #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters #pragma warning restore RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads } - -internal static class StringPreviewHelper -{ - public static Tuple CreateStringPreviews(string expected, string actual, int diffIndex, int fullPreviewLength) - { - int ellipsisLength = 3; // Length of the ellipsis "..." - - if (fullPreviewLength % 2 == 0) - { - // Being odd makes it easier to calculate the context length, and center the marker, this is not user customizable. - throw new ArgumentException($"{nameof(fullPreviewLength)} must be odd, but it was even."); - } - - // This is arbitrary number that is 2 times the size of the ellipsis, - // plus 3 chars to make it easier to check the tests are correct when part of string is masked. - // Preview length is not user customizable, just makes it harder to break the tests, and avoids few ifs we would need to write otherwise. - if (fullPreviewLength < 9) - { - throw new ArgumentException($"{nameof(fullPreviewLength)} cannot be shorter than 9."); - } - - // In case we want to instead count runes or text elements we can change it just here. - int expectedLength = expected.Length; - int actualLength = actual.Length; - - if (diffIndex < 0 || diffIndex > Math.Min(expectedLength, actualLength)) // Not -1 here because the difference can be right after the end of the shorter string. - { - throw new ArgumentOutOfRangeException(nameof(diffIndex), "diffIndex must be within the bounds of both strings."); - } - - int contextLength = (fullPreviewLength - 1) / 2; - - // Diff index must point into the string, the start of the strings will always be shortened the same amount, - // because otherwise the diff would happen at the beginning of the string. - // So we just care about how far we are from the end of the string, so we can show the maximum amount of info to the user - // when diff is really close to the end. - string shorterString = expectedLength < actualLength ? expected : actual; - string longerString = expectedLength < actualLength ? actual : expected; - bool expectedIsShorter = expectedLength < actualLength; - - int shorterStringLength = shorterString.Length; - int longerStringLength = longerString.Length; - - // End marker will point to the end of the shorter string, but the end of the longer string will be replaced by ... when it reaches the end of the preview. - // Make sure we don't point at the dots. To do this we need to make sure the strings are cut at the beginning, rather than preferring the maximum context shown. - // - // Marker needs to point where ellipsis would be when we shorten the longer string. - bool markerPointsAtTheEnd = shorterStringLength - diffIndex <= ellipsisLength; - // Strings need to have different lengths, for same length strings we don't add ellipsis. - bool stringsHaveDifferentLength = longerStringLength > shorterStringLength; - // Shorter string needs to be long enough to fill the preview window to the point where ellipsis shows up (last 3 chars). - bool shorterStringIsLongEnoughToFillPreviewWindow = shorterStringLength >= fullPreviewLength - ellipsisLength; - bool markerPointsAtEllipsis = markerPointsAtTheEnd && stringsHaveDifferentLength && shorterStringIsLongEnoughToFillPreviewWindow; - int ellipsisSpaceOrZero = markerPointsAtEllipsis ? ellipsisLength + 2 : 0; - - // Find the end of the string that we will show, either the end of the shorter string, or the end of the preview window. - int endOfString = Math.Min(diffIndex + contextLength, shorterStringLength); - - // Then calculate the start of the preview from that. This makes sure that if diff is close end of the string we show as much as we can. - int start = endOfString - fullPreviewLength + ellipsisSpaceOrZero; - - // If the string is shorter than the preview, start cutting from 0, otherwise start cutting from the calculated start. - int cutStart = Math.Max(0, start); - // From here we need to handle longer and shorter string separately, because one of the can be shorter, - // and we want to show the maximum we can that fits in the preview window. - int cutEndShort = Math.Min(cutStart + fullPreviewLength, shorterStringLength); - int cutEndLong = Math.Min(cutStart + fullPreviewLength, longerStringLength); - - string shorterStringPreview = shorterString.Substring(cutStart, cutEndShort - cutStart); - string longerStringPreview = longerString.Substring(cutStart, cutEndLong - cutStart); - - // We cut something from the start of the string, so we need to add ellipsis there. - // We know if one string is cut then both must be cut, otherwise the diff would be at the beginning of the string. - if (cutStart > 0) - { - shorterStringPreview = EllipsisStart(shorterStringPreview); - longerStringPreview = EllipsisStart(longerStringPreview); - } - - // We cut something from the end of the string, so we need to add ellipsis there. - // We don't know if both strings are cut, so we need to check them separately. - if (cutEndShort < shorterStringLength) - { - shorterStringPreview = EllipsisEnd(shorterStringPreview); - } - - // We cut something from the end of the string, so we need to add ellipsis there. - if (cutEndLong < longerStringLength) - { - longerStringPreview = EllipsisEnd(longerStringPreview); - } - - string escapedShorterStringPreview = MakeControlCharactersVisible(shorterStringPreview); - string escapedLongerStringPreview = MakeControlCharactersVisible(longerStringPreview); - - return new Tuple( - expectedIsShorter ? escapedShorterStringPreview : escapedLongerStringPreview, - expectedIsShorter ? escapedLongerStringPreview : escapedShorterStringPreview, - diffIndex - cutStart); - } - - private static string EllipsisEnd(string text) - => $"{text.Substring(0, text.Length - 3)}..."; - - private static string EllipsisStart(string text) - => $"...{text.Substring(3)}"; - - private static string MakeControlCharactersVisible(string text) - { - var stringBuilder = new StringBuilder(text.Length); - foreach (char ch in text) - { - if (char.IsControl(ch)) - { - stringBuilder.Append((char)(0x2400 + ch)); - } - else - { - stringBuilder.Append(ch); - } - } - - return stringBuilder.ToString(); - } -} diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.cs index fcb4b1b364..00dcb754a4 100644 --- a/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.cs +++ b/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.cs @@ -145,40 +145,21 @@ public static void AreEqual(T? expected, T? actual, IEqualityComparer comp private static bool AreEqualFailing(T? expected, T? actual, IEqualityComparer? comparer) => !(comparer ?? EqualityComparer.Default).Equals(expected!, actual!); - private static string FormatStringComparisonMessage(string? expected, string? actual, string userMessage) - { - // Handle null cases - if (expected is null && actual is null) - { - return string.Format( - CultureInfo.CurrentCulture, - FrameworkMessages.AreEqualFailMsg, - userMessage, - ReplaceNulls(expected), - ReplaceNulls(actual)); - } - - if (expected is null || actual is null) - { - return string.Format( - CultureInfo.CurrentCulture, - FrameworkMessages.AreEqualFailMsg, - userMessage, - ReplaceNulls(expected), - ReplaceNulls(actual)); - } - - // Find the first difference - int diffIndex = FindFirstStringDifference(expected, actual); + private static void AppendStringDiffSummary(StructuredAssertionMessage structured, string expected, string actual) + => AppendStringDiffSummary(structured, expected, actual, FindFirstStringDifference(expected, actual)); + private static void AppendStringDiffSummary(StructuredAssertionMessage structured, string expected, string actual, int diffIndex) + { if (diffIndex == -1) { - // Strings are equal - should not happen in practice, we call this method only when they are not equal. throw ApplicationStateGuard.Unreachable(); } - // Format the enhanced string comparison message - return FormatStringDifferenceMessage(expected, actual, diffIndex, userMessage); + string diffSummary = expected.Length == actual.Length + ? string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AreEqualStringDiffLengthBothMsg, expected.Length, diffIndex) + : string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AreEqualStringDiffLengthDifferentMsg, expected.Length, actual.Length, diffIndex); + + structured.WithAdditionalSummaryLine(diffSummary); } private static int FindFirstStringDifference(string expected, string actual) @@ -197,97 +178,40 @@ private static int FindFirstStringDifference(string expected, string actual) return expected.Length != actual.Length ? minLength : -1; } - private static string FormatStringDifferenceMessage(string expected, string actual, int diffIndex, string userMessage) - { - string lengthInfo = expected.Length == actual.Length - ? string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AreEqualStringDiffLengthBothMsg, expected.Length, diffIndex) - : string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AreEqualStringDiffLengthDifferentMsg, expected.Length, actual.Length); - - // Create contextual preview around the difference - const int contextLength = 41; // Show up to 20 characters of context on each side - Tuple tuple = StringPreviewHelper.CreateStringPreviews(expected, actual, diffIndex, contextLength); - string expectedPreview = tuple.Item1; - string actualPreview = tuple.Item2; - int caretPosition = tuple.Item3; - - // Get localized prefixes - string expectedPrefix = FrameworkMessages.AreEqualStringDiffExpectedPrefix; - string actualPrefix = FrameworkMessages.AreEqualStringDiffActualPrefix; - - // Calculate the maximum prefix length to align the caret properly - int maxPrefixLength = Math.Max(expectedPrefix.Length, actualPrefix.Length); - - // Pad shorter prefix to match the longer one for proper alignment - string paddedExpectedPrefix = expectedPrefix.PadRight(maxPrefixLength); - string paddedActualPrefix = actualPrefix.PadRight(maxPrefixLength); - - // Build the formatted lines with proper alignment - string expectedLine = paddedExpectedPrefix + $"\"{expectedPreview}\""; - string actualLine = paddedActualPrefix + $"\"{actualPreview}\""; - - // The caret should align under the difference in the string content - // For localized prefixes with different lengths, we need to account for the longer prefix - // to ensure proper alignment. But the caret position is relative to the string content. - int adjustedCaretPosition = maxPrefixLength + 1 + caretPosition; // +1 for the opening quote - - // Format user message properly - add leading space if not empty, otherwise no extra formatting - string formattedUserMessage = string.IsNullOrEmpty(userMessage) ? string.Empty : $" {userMessage}"; - - return string.Format( - CultureInfo.CurrentCulture, - FrameworkMessages.AreEqualStringDiffFailMsg, - lengthInfo, - formattedUserMessage, - expectedLine, - actualLine, - new string('-', adjustedCaretPosition) + "^"); - } - [DoesNotReturn] private static void ReportAssertAreEqualFailed(object? expected, object? actual, string? message, string expectedExpression, string actualExpression) { string expectedRendered = AssertionValueRenderer.RenderValue(expected); string actualRendered = AssertionValueRenderer.RenderValue(actual); - string summary; EvidenceBlock evidence; - string? additionalSummaryLine = null; + StructuredAssertionMessage structured; if (actual is not null && expected is not null && !actual.GetType().Equals(expected.GetType())) { Type expectedType = expected.GetType(); Type actualType = actual.GetType(); - summary = FrameworkMessages.AreEqualDifferentTypesFailedSummary; evidence = EvidenceBlock.Create() .AddLine("expected:", expectedRendered) .AddLine("expected type:", expectedType.FullName ?? expectedType.Name) .AddLine("actual:", actualRendered) .AddLine("actual type:", actualType.FullName ?? actualType.Name); + structured = new(FrameworkMessages.AreEqualDifferentTypesFailedSummary); } else if (expected is string expectedString && actual is string actualString) { - summary = FrameworkMessages.AreEqualStringsFailedSummary; - int diffIndex = FindFirstStringDifference(expectedString, actualString); - additionalSummaryLine = expectedString.Length == actualString.Length - ? string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AreEqualStringDiffLengthBothMsg, expectedString.Length, diffIndex) - : string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AreEqualStringDiffLengthDifferentMsg, expectedString.Length, actualString.Length); - evidence = EvidenceBlock.Create() .AddLine("expected:", expectedRendered) .AddLine("actual:", actualRendered); + structured = new(FrameworkMessages.AreEqualStringsFailedSummary); + AppendStringDiffSummary(structured, expectedString, actualString); } else { - summary = FrameworkMessages.AreEqualFailedSummary; evidence = EvidenceBlock.Create() .AddLine("expected:", expectedRendered) .AddLine("actual:", actualRendered); - } - - StructuredAssertionMessage structured = new(summary); - if (additionalSummaryLine is not null) - { - structured.WithAdditionalSummaryLine(additionalSummaryLine); + structured = new(FrameworkMessages.AreEqualFailedSummary); } structured.WithUserMessage(message); diff --git a/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx b/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx index 53794d770c..2b2cdee2f4 100644 --- a/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx +++ b/src/TestFramework/TestFramework/Resources/FrameworkMessages.resx @@ -151,10 +151,10 @@ But was: - String lengths are both {0} but differ at index {1}. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. - Expected string length {0} but was {1}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. Expected values to be structurally equivalent. @@ -491,12 +491,21 @@ Actual: {2} Expected values to be equal, but they are of different types. + + Strings differ only in case. + Expected strings to be equal. Expected values to not be equal. + + Expected strings to differ (case-insensitive). + + + Expected strings to differ. + Expected all items in collection to be non-null. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf index 7df8e72e87..44995aeece 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - Očekáváno:<{1}>. Aktuálně:<{2}>. {0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Očekáván rozdíl, který není větší jak <{3}> mezi očekávanou hodnotou <{1}> a aktuální hodnotou <{2}>. {0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - Očekáváno:<{1}>. Případ je rozdílný pro aktuální hodnotu:<{2}>. {0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} Očekáváno:<{1} ({2})>. Aktuálně:<{3} ({4})>. {0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - Očekáváno: - - - - But was: - Ale bylo: - - - String lengths are both {0} but differ at index {1}. - Délky obou řetězců jsou {0}, ale liší se na indexu {1}. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + Délky obou řetězců jsou {0}, ale liší se na indexu {1}. - Expected string length {0} but was {1}. - Očekávaná délka řetězce je {0}, ale byla {1}. - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} Nebyla očekávána žádná hodnota kromě:<{1}>. Aktuálně:<{2}>. {0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Očekáván rozdíl, který je větší jak <{3}> mezi očekávanou hodnotou <{1}> a aktuální hodnotou <{2}>. {0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf index 8e6e4185da..9b5a667d29 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - Erwartet:<{1}>. Tatsächlich:<{2}>. {0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Es wurde eine Differenz nicht größer als <{3}> zwischen dem erwarteten Wert <{1}> und dem tatsächlichen Wert <{2}> erwartet. {0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - Erwartet:<{1}>. Die Großschreibung des tatsächlichen Werts weicht davon ab:<{2}>. {0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} Erwartet:<{1} ({2})>. Tatsächlich:<{3} ({4})>. {0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - Erwartet: - - - - But was: - War aber: - - - String lengths are both {0} but differ at index {1}. - Die Zeichenfolgenlängen sind beide {0}, unterscheiden sich jedoch bei Index {1}. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + Die Zeichenfolgenlängen sind beide {0}, unterscheiden sich jedoch bei Index {1}. - Expected string length {0} but was {1}. - Die erwartete Länge der Zeichenfolge ist {0}, war aber {1}. - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} Es wurde ein beliebiger Wert erwartet außer:<{1}>. Tatsächlich:<{2}>. {0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Es wurde eine Differenz größer als <{3}> zwischen dem erwarteten Wert <{1}> und dem tatsächlichen Wert <{2}> erwartet. {0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf index 76b764f6cf..093fc603f2 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - Se esperaba <{1}>, pero es <{2}>. {0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Se esperaba una diferencia no superior a <{3}> entre el valor esperado <{1}> y el valor actual <{2}>. {0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - Se esperaba:<{1}>. La caja es diferente para el valor actual:<{2}>. {0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} Se esperaba:<{1} ({2})>, pero es:<{3} ({4})>. {0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - Se esperaba: - - - - But was: - Pero fue: - - - String lengths are both {0} but differ at index {1}. - Las longitudes de las cadenas son {0} pero difieren en el índice {1}. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + Las longitudes de las cadenas son {0} pero difieren en el índice {1}. - Expected string length {0} but was {1}. - Se esperaba una longitud de cadena {0} pero fue {1}. - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} Se esperaba cualquier valor excepto <{1}>, pero es <{2}>. {0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Se esperaba una diferencia mayor que <{3}> entre el valor esperado <{1}> y el valor actual <{2}>. {0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf index 6b531d6516..23c37ba0c6 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - Attendu : <{1}>, Réel : <{2}>. {0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Différence attendue non supérieure à <{3}> comprise entre la valeur attendue <{1}> et la valeur réelle <{2}>. {0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - Attendu :<{1}>. La casse est différente pour la valeur réelle :<{2}>. {0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} Attendu : <{1} ({2})>, Réel : <{3} ({4})>. {0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - Attendu : - - - - But was: - Mais c'était : - - - String lengths are both {0} but differ at index {1}. - Les longueurs de chaîne sont toutes les deux {0} mais diffèrent à l’index {1}. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + Les longueurs de chaîne sont toutes les deux {0} mais diffèrent à l’index {1}. - Expected string length {0} but was {1}. - La longueur de chaîne attendue {0} mais était {1}. - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} Toute valeur attendue sauf :<{1}>. Réel :<{2}>. {0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Différence attendue supérieure à <{3}> comprise entre la valeur attendue <{1}> et la valeur réelle <{2}>. {0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf index d4ead1a1fa..2ea392f3c8 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - Previsto:<{1}>. Effettivo:<{2}>. {0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Prevista una differenza non maggiore di <{3}> tra il valore previsto <{1}> e il valore effettivo <{2}>. {0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - Previsto:<{1}>. La combinazione di maiuscole e minuscole è diversa per il valore effettivo:<{2}>. {0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} Previsto:<{1} ({2})>. Effettivo:<{3} ({4})>. {0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - Previsto: - - - - But was: - Ma era: - - - String lengths are both {0} but differ at index {1}. - Le lunghezze delle stringhe sono entrambe {0} ma differiscono all'indice {1}. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + Le lunghezze delle stringhe sono entrambe {0} ma differiscono all'indice {1}. - Expected string length {0} but was {1}. - La lunghezza della stringa prevista è {0} ma era {1}. - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} Previsto qualsiasi valore tranne:<{1}>. Effettivo:<{2}>. {0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Prevista una differenza maggiore di <{3}> tra il valore previsto <{1}> e il valore effettivo <{2}>. {0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf index b638f995a8..7af0947897 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - <{1}> が必要ですが、<{2}> が指定されました。{0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - 指定する値 <{1}> と実際の値 <{2}> との間には <{3}> 以内の差が必要です。{0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - <{1}> が必要です。実際の値: <{2}> では大文字と小文字が異なります。{0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} <{1} ({2})> が必要ですが、<{3} ({4})> が指定されました。{0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - 期待値: - - - - But was: - しかし、次でした: - - - String lengths are both {0} but differ at index {1}. - 文字列の長さは両方とも {0} ですが、インデックス {1} で異なります。 + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + 文字列の長さは両方とも {0} ですが、インデックス {1} で異なります。 - Expected string length {0} but was {1}. - 期待される文字列の長さは {0} ですが、実際は {1} でした。 - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} <{1}> 以外の任意の値が必要ですが、<{2}> が指定されています。{0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - 指定する値 <{1}> と実際の値 <{2}> との間には、<{3}> を超える差が必要です。{0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf index 9b542cd3e1..1f80de8249 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - 예상 값: <{1}>. 실제 값: <{2}>. {0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - 예상 값 <{1}>과(와) 실제 값 <{2}>의 차이가 <{3}>보다 크지 않아야 합니다. {0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - 예상 값: <{1}>. 대/소문자가 다른 실제 값: <{2}>. {0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} 예상 값: <{1} ({2})>. 실제 값: <{3} ({4})>. {0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - 예상: - - - - But was: - 그러나 다음과 같습니다. - - - String lengths are both {0} but differ at index {1}. - 문자열 길이는 둘 다 {0} 이지만 인덱스 {1}에서 다릅니다. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + 문자열 길이는 둘 다 {0} 이지만 인덱스 {1}에서 다릅니다. - Expected string length {0} but was {1}. - 문자열 길이 {0}(을)를 예상했지만 {1}입니다. - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} 예상 값: <{1}>을(를) 제외한 모든 값. 실제 값: <{2}>. {0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - 예상 값 <{1}>과(와) 실제 값 <{2}>의 차이가 <{3}>보다 커야 합니다. {0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf index 7eebba06d1..65cd8dbae7 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - Oczekiwana:<{1}>. Rzeczywista:<{2}>. {0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Oczekiwano różnicy nie większej niż <{3}> pomiędzy oczekiwaną wartością <{1}> a rzeczywistą wartością <{2}>. {0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - Oczekiwano:<{1}>. Przypadek różni się od rzeczywistej wartości:<{2}>. {0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} Oczekiwana:<{1} ({2})>. Rzeczywista:<{3} ({4})>. {0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - Oczekiwane: - - - - But was: - Ale było: - - - String lengths are both {0} but differ at index {1}. - Długości ciągów są {0}, ale różnią się w indeksie {1}. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + Długości ciągów są {0}, ale różnią się w indeksie {1}. - Expected string length {0} but was {1}. - Oczekiwano ciągu o długości {0}, ale miał wartość {1}. - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} Oczekiwano dowolnej wartości za wyjątkiem:<{1}>. Rzeczywista:<{2}>. {0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Oczekiwano różnicy większej niż <{3}> pomiędzy oczekiwaną wartością <{1}> a rzeczywistą wartością <{2}>. {0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf index 676c1622a3..640d36ae2b 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - Esperado:<{1}>. Real:<{2}>. {0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Esperada uma diferença não maior que <{3}> entre o valor esperado <{1}> e o valor real <{2}>. {0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - Esperado:<{1}>. Capitalização é diferente para o valor real:<{2}>. {0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} Esperado:<{1} ({2})>. Real:<{3} ({4})>. {0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - Esperado: - - - - But was: - Mas foi: - - - String lengths are both {0} but differ at index {1}. - Os comprimentos de cadeia de caracteres são ambos {0}, mas diferem no índice {1}. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + Os comprimentos de cadeia de caracteres são ambos {0}, mas diferem no índice {1}. - Expected string length {0} but was {1}. - Comprimento esperado da cadeia de caracteres {0}, mas foi {1}. - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} Esperado qualquer valor exceto:<{1}>. Real:<{2}>. {0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Esperada uma diferença maior que <{3}> entre o valor esperado <{1}> e o valor real <{2}>. {0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf index b1a797df9e..97f673d976 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - Ожидается: <{1}>. Фактически: <{2}>. {0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Между ожидаемым значением <{1}> и фактическим значением <{2}> требуется разница не более чем <{3}>. {0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - Ожидается: <{1}>. Отличается на фактическое значение: <{2}>. {0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} Ожидается: <{1} ({2})>. Фактически: <{3} ({4})>. {0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - Ожидалось: - - - - But was: - Было: - - - String lengths are both {0} but differ at index {1}. - Длины строк равны {0}, но различаются по индексу {1}. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + Длины строк равны {0}, но различаются по индексу {1}. - Expected string length {0} but was {1}. - Ожидалась длина строки: {0}, фактическая длина строки: {1}. - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} Ожидается любое значение, кроме: <{1}>. Фактически: <{2}>. {0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Между ожидаемым значением <{1}> и фактическим значением <{2}> требуется разница более чем <{3}>. {0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf index 8b795391cc..cab1941e68 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - Beklenen:<{1}>. Gerçek:<{2}>. {0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Beklenen değer <{1}> ile gerçek değer <{2}> arasında, şundan büyük olmayan fark bekleniyor: <{3}>. {0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - Beklenen:<{1}>. Durum, gerçek değer için farklı:<{2}>. {0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} Beklenen:<{1} ({2})>. Gerçek:<{3} ({4})>. {0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - Beklenen: - - - - But was: - Ancak: - - - String lengths are both {0} but differ at index {1}. - Dize uzunlukları her ikisi de {0} ama dizin {1} üzerinde farklılık gösterir. + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + Dize uzunlukları her ikisi de {0} ama dizin {1} üzerinde farklılık gösterir. - Expected string length {0} but was {1}. - Beklenen dize uzunluğu {0} idi, ancak dize uzunluğu {1} oldu. - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} Şunun dışında bir değer bekleniyor:<{1}>. Gerçek:<{2}>. {0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - Beklenen değer <{1}> ile gerçek değer <{2}> arasında, şundan büyük olan fark bekleniyor: <{3}>. {0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf index 28e9e3fad0..8c96500f61 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - 应为: <{1}>,实际为: <{2}>。{0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - 预期值 <{1}> 和实际值 <{2}> 之间的差不应大于 <{3}>。{0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - 应为: <{1}>。实际值的大小写有所不同: <{2}>。{0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} 应为: <{1} ({2})>,实际为: <{3} ({4})>。{0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - 应为: - - - - But was: - 但却是: - - - String lengths are both {0} but differ at index {1}. - 字符串长度均为 {0},但在索引 {1} 处有所不同。 + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + 字符串长度均为 {0},但在索引 {1} 处有所不同。 - Expected string length {0} but was {1}. - 字符串长度应为 {0},但为 {1}。 - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} 应为: <{1}> 以外的任意值,实际为: <{2}>。{0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - 预期值 <{1}> 和实际值 <{2}> 之间的差应大于 <{3}>。{0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf index 99595530c5..86e3c3e4a3 100644 --- a/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf +++ b/src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf @@ -32,56 +32,61 @@ Expected all items in collection to be of the specified type. - - Expected:<{1}>. Actual:<{2}>. {0} - 預期: <{1}>。實際: <{2}>。{0} - + + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected:<{1}>. Case is different for actual value:<{2}>. {0} + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - 預期值 <{1}> 和實際值 <{2}> 之間的預期差異沒有大於 <{3}>。{0} - - - - Expected:<{1}>. Case is different for actual value:<{2}>. {0} - 預期: <{1}>。大小寫與下列實際值不同: <{2}>。{0} - + Expected a difference no greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected:<{1} ({2})>. Actual:<{3} ({4})>. {0} 預期: <{1} ({2})>。實際: <{3} ({4})>。{0} + + Expected:<{1}>. Actual:<{2}>. {0} + Expected:<{1}>. Actual:<{2}>. {0} + + + + But was: + But was: + + + + Expected: + Expected: + + {0}{1} {2} {3} {4} - {0}{1} + {0}{1} {2} {3} {4} - - Expected: - 預期為: - - - - But was: - 但為: - - - String lengths are both {0} but differ at index {1}. - 字串長度兩者都是 {0},但索引 {1} 不同。 + Strings have same length ({0}) and differ at 1 location(s). First difference at index {1}. + 字串長度兩者都是 {0},但索引 {1} 不同。 - Expected string length {0} but was {1}. - 預期的字串長度為 {0},但為 {1}。 - + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + Strings have different lengths (expected: {0}, actual: {1}) and differ at 1 location(s). First difference at index {2}. + + + + Strings differ only in case. + Strings differ only in case. + Expected values to be structurally equivalent. @@ -188,15 +193,25 @@ <root> Placeholder used in equivalence-mismatch messages when the difference is at the top of the object graph. + + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} + + Expected any value except:<{1}>. Actual:<{2}>. {0} 預期任何值 (<{1}> 除外)。實際: <{2}>。{0} - - Expected a difference greater than <{3}> between expected value <{1}> and actual value <{2}>. {0} - 預期值 <{1}> 和實際值 <{2}> 之間的預期差異大於 <{3}>。{0} - + + Expected strings to differ (case-insensitive). + Expected strings to differ (case-insensitive). + + + + Expected strings to differ. + Expected strings to differ. + Could not complete structural comparison. diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreEqualTests.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreEqualTests.cs index 213fc4b2a7..8feba2c3f4 100644 --- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreEqualTests.cs +++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreEqualTests.cs @@ -173,8 +173,19 @@ public void AreEqual_WithEnglishCultureAndDoesNotIgnoreCase_Throws() // Won't ignore case. Action action = () => Assert.AreEqual(expected, actual, false, englishCulture); - action.Should().Throw() - .WithMessage("Assert.AreEqual failed. Expected:. Case is different for actual value:. 'expected' expression: 'expected', 'actual' expression: 'actual'."); + action.Should().Throw() + .Which.Message.Should().Be( + """ + Assertion failed. Expected strings to be equal. + Strings differ only in case. + Strings have same length (1) and differ at 1 location(s). First difference at index 0. + + expected: "i" + actual: "I" + culture: en-EN + + Assert.AreEqual(expected, actual) + """); } public void AreEqual_WithTurkishCultureAndDoesNotIgnoreCase_Throws() @@ -1503,7 +1514,7 @@ public void AreEqualStringDifferenceAtBeginning() .Which.Message.Should().Be( """ Assertion failed. Expected strings to be equal. - String lengths are both 4 but differ at index 0. + Strings have same length (4) and differ at 1 location(s). First difference at index 0. expected: "baaa" actual: "aaaa" @@ -1519,7 +1530,7 @@ public void AreEqualStringDifferenceAtEnd() .Which.Message.Should().Be( """ Assertion failed. Expected strings to be equal. - String lengths are both 4 but differ at index 3. + Strings have same length (4) and differ at 1 location(s). First difference at index 3. expected: "aaaa" actual: "aaab" @@ -1531,17 +1542,12 @@ String lengths are both 4 but differ at index 3. public void AreEqualStringWithSpecialCharactersShouldEscape() { Action action = () => Assert.AreEqual("aa\ta", "aa a"); - action.Should().Throw() - .Which.Message.Should().Be( - """ - Assertion failed. Expected strings to be equal. - String lengths are both 4 but differ at index 2. - - expected: "aa\ta" - actual: "aa a" + AssertFailedException ex = action.Should().Throw().Which; - Assert.AreEqual("aa\ta", "aa a") - """); + ex.Message.Should().Contain("Strings have same length (4) and differ at 1 location(s). First difference at index 2."); + ex.Message.Should().Contain("expected: \"aa\\ta\""); + ex.Message.Should().Contain("actual: \"aa a\""); + ex.Message.Should().Contain("Assert.AreEqual(\"aa\\ta\", \"aa a\")"); } // Long-string truncation is intentionally not yet implemented; documents the current full-string render. @@ -1555,7 +1561,7 @@ public void AreEqualLongStringsShowsFullStrings() .Which.Message.Should().Be( """ Assertion failed. Expected strings to be equal. - String lengths are both 201 but differ at index 100. + Strings have same length (201) and differ at 1 location(s). First difference at index 100. expected: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" actual: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" @@ -1567,12 +1573,21 @@ String lengths are both 201 but differ at index 100. public void AreEqualStringWithCultureShouldUseEnhancedMessage() { Action action = () => Assert.AreEqual("aaaa", "aaab", false, CultureInfo.InvariantCulture); - action.Should().Throw() - .WithMessage(""" - Assert.AreEqual failed. String lengths are both 4 but differ at index 3. 'expected' expression: '"aaaa"', 'actual' expression: '"aaab"'. - Expected: "aaaa" - But was: "aaab" - --------------^ + AssertFailedException ex = action.Should().Throw().Which; + + ex.Message.Should().StartWith( + """ + Assertion failed. Expected strings to be equal. + Strings have same length (4) and differ at 1 location(s). First difference at index 3. + + expected: "aaaa" + actual: "aaab" + """); + ex.Message.Should().Contain($"{Environment.NewLine}culture:"); + ex.Message.Should().EndWith( + """ + + Assert.AreEqual("aaaa", "aaab") """); } @@ -1583,7 +1598,7 @@ public void AreEqualStringWithDifferentLength() .Which.Message.Should().Be( """ Assertion failed. Expected strings to be equal. - Expected string length 4 but was 3. + Strings have different lengths (expected: 4, actual: 3) and differ at 1 location(s). First difference at index 3. expected: "aaaa" actual: "aaa" @@ -1599,7 +1614,7 @@ public void AreEqualShorterExpectedString() .Which.Message.Should().Be( """ Assertion failed. Expected strings to be equal. - Expected string length 3 but was 4. + Strings have different lengths (expected: 3, actual: 4) and differ at 1 location(s). First difference at index 3. expected: "aaa" actual: "aaab" @@ -1615,7 +1630,7 @@ public void AreEqualStringWithUserMessage() .Which.Message.Should().Be( """ Assertion failed. Expected strings to be equal. - String lengths are both 4 but differ at index 3. + Strings have same length (4) and differ at 1 location(s). First difference at index 3. My custom message expected: "aaaa" @@ -1632,7 +1647,7 @@ public void AreEqualStringWithEmojis() .Which.Message.Should().Be( """ Assertion failed. Expected strings to be equal. - Expected string length 2 but was 4. + Strings have different lengths (expected: 2, actual: 4) and differ at 1 location(s). First difference at index 0. expected: "🥰" actual: "aaab" @@ -1641,208 +1656,117 @@ Expected string length 2 but was 4. """); } - public void CreateStringPreviews_DiffPointsToCorrectPlaceInNonShortenedString() + public void AreEqualStringSpecificWithIgnoreCaseAndCultureUsesComparisonAwareDiffIndex() { - int preview = 9; - int length = 1; - int diffIndex = 0; - string stringPreview = FormatStringPreview(StringPreviewHelper.CreateStringPreviews(DigitString(length, diffIndex), DigitString(length, diffIndex), diffIndex, preview)); - StringPreviewsAreEqual( - """ - "X" - "X" - _^ - """, - stringPreview); - } + Action action = () => Assert.AreEqual("straße", "STRAẞE!", true, new CultureInfo("de-DE")); + action.Should().Throw() + .Which.Message.Should().Be( + """ + Assertion failed. Expected strings to be equal. + Strings have different lengths (expected: 6, actual: 7) and differ at 1 location(s). First difference at index 6. - public void CreateStringPreviews_DiffPointsToCorrectPlaceInShortenedStringWithEndCut() - { - int preview = 9; - int length = preview + 10; - int diffIndex = 0; - string stringPreview = FormatStringPreview(StringPreviewHelper.CreateStringPreviews(DigitString(length, diffIndex), DigitString(length, diffIndex), diffIndex, preview)); - StringPreviewsAreEqual( - """ - "X12345..." - "X12345..." - _^ - """, stringPreview); - } + expected: "straße" + actual: "STRAẞE!" + ignore case: true + culture: de-DE - public void CreateStringPreviews_DiffPointsToCorrectPlaceInShortenedStringWithStartCut() - { - int preview = 9; - int length = 10; - int diffIndex = 9; - string stringPreview = FormatStringPreview(StringPreviewHelper.CreateStringPreviews(DigitString(length, diffIndex), DigitString(length, diffIndex), diffIndex: diffIndex, preview)); - StringPreviewsAreEqual( - """ - "...45678X" - "...45678X" - _________^ - """, - stringPreview); + Assert.AreEqual("straße", "STRAẞE!") + """); } - public void CreateStringPreviews_ShowWholeStringWhenDifferenceIsAtTheEndAndJustOneStringDoesNotFit() + public void AreEqualStringSpecificWithNullExpectedUsesStructuredMessage() { - int preview = 21; - int length = 50; - int diffIndex = 16; - string stringPreview = FormatStringPreview(StringPreviewHelper.CreateStringPreviews(DigitString(preview, diffIndex), DigitString(length, diffIndex), diffIndex: diffIndex, preview)); - StringPreviewsAreEqual( - """ - "0123456789012345X7890" - "0123456789012345X7..." - _________________^ - """, - stringPreview); - } + string? expected = null; + string actual = "string"; - public void CreateStringPreviews_MakeSureWeDontPointToEndEllipsis() - { - // We will mask last 3 chars of the string, so we need to make sure that the diff index is not pointing to the end ellipsis. - int preview = 25; - int length = 50; - int diffIndex = 24; + Action action = () => Assert.AreEqual(expected, actual, false); + action.Should().Throw() + .Which.Message.Should().Be( + """ + Assertion failed. Expected strings to be equal. - string stringPreview = FormatStringPreview(StringPreviewHelper.CreateStringPreviews(DigitString(preview, diffIndex), DigitString(length, diffIndex), diffIndex: diffIndex, preview)); - StringPreviewsAreEqual( - """ - "...8901234567890123X" - "...8901234567890123X56..." - ____________________^ - """, - stringPreview); + expected: null + actual: "string" + + Assert.AreEqual(expected, actual) + """); } - public void CreateStringPreviews_MakeSureWeDontPointToEndEllipsis_WhenLongerStringOneCharLargerThanPreviewWindow() + public void AreEqualStringSpecificWithMultilineStringsUsesStructuredMessage() { - // We will mask last 3 chars of the string, so we need to make sure that the diff index is not pointing to the end ellipsis. - int preview = 15; - int diffIndex = preview - 1; + string expected = "line one\nline two\nline three"; + string actual = "line one\nLINE TWO\nline three"; - string stringPreview = FormatStringPreview(StringPreviewHelper.CreateStringPreviews(DigitString(preview, diffIndex), DigitString(preview + 1, diffIndex), diffIndex: diffIndex, preview)); - StringPreviewsAreEqual( - """ - "...890123X" - "...890123X5" - __________^ - """, - stringPreview); + Action action = () => Assert.AreEqual(expected, actual, false); + AssertFailedException ex = action.Should().Throw().Which; + + ex.Message.Should().Contain("Assertion failed. Expected strings to be equal."); + ex.Message.Should().Contain("line one"); + ex.Message.Should().Contain("LINE TWO"); + ex.Message.Should().Contain("Assert.AreEqual(expected, actual)"); } - public void CreateStringPreviews_MakeSureWeDontPointToEndEllipsis_WhenLongerStringIsBarelyLonger() + public void AreEqualStringSpecificWhenEqualDoesNotThrow() + => FluentActions.Invoking(() => Assert.AreEqual("Straße", "STRAẞE", true, new CultureInfo("de-DE"))).Should().NotThrow(); + + public void AreNotEqualStringSpecificShowsStructuredMessage() { - // We will mask last 3 chars of the string, so we need to make sure that the diff index is not pointing to the end ellipsis. - int preview = 25; + string notExpected = "A"; + string actual = "A"; + + Action action = () => Assert.AreNotEqual(notExpected, actual, false); + AssertFailedException ex = action.Should().Throw().Which; - string stringPreview = FormatStringPreview(StringPreviewHelper.CreateStringPreviews("01234567890123456789012345678901234567890123X", "01234567890123456789012345678901234567890123X56", diffIndex: 44, preview)); - StringPreviewsAreEqual( + ex.Message.Should().Be( """ - "...8901234567890123X" - "...8901234567890123X56" - ____________________^ - """, - stringPreview); - } + Assertion failed. Expected strings to differ. - public void CreateStringPreviews_DiffPointsAfterLastCharacterWhenStringsAreAllTheSameCharactersUntilTheEndOfTheShorterOne() - { - int preview = 9; - int diffIndex = 3; - string stringPreview = FormatStringPreview(StringPreviewHelper.CreateStringPreviews("aaa", "aaaX", diffIndex, preview)); - stringPreview.Should().Be(""" - "aaa" - "aaaX" - ____^ + not expected: "A" + actual: "A" + + Assert.AreNotEqual(notExpected, actual) """); + ex.ExpectedText.Should().Be("not \"A\""); + ex.ActualText.Should().Be("\"A\""); + ex.Data["assert.expected"].Should().Be("not \"A\""); + ex.Data["assert.actual"].Should().Be("\"A\""); } - public void CreateStringPreviews_DiffNeverPointsAtEllipsis_Generated() + public void AreNotEqualStringSpecificWithIgnoreCaseAndCultureShowsEvidence() { - // Generate all combinations of string lengths and diff to see if in any of them we point to ellipsis. - StringBuilder s = new(); - foreach (int a in Enumerable.Range(1, 20)) - { - foreach (int e in Enumerable.Range(1, 20)) - { - foreach (int d in Enumerable.Range(1, Math.Min(a, e))) - { - string p = FormatStringPreview(StringPreviewHelper.CreateStringPreviews(DigitString(e, d), DigitString(a, d), diffIndex: d, 11)); - - string[] lines = p.Split('\n'); - int diffIndicator = lines[2].IndexOf('^'); - bool line0PointsOnEllipsis = lines[0].Length > diffIndicator && lines[0][diffIndicator] == '.'; - bool line1PointsOnEllipsis = lines[1].Length > diffIndicator && lines[1][diffIndicator] == '.'; - - if (line0PointsOnEllipsis || line1PointsOnEllipsis) - { - string text = $""" - Failed for: - Expected={e}, Actual={a}, DiffIndex={d} - string result = FormatStringPreview(StringPreviewHelper.CreateStringPreviews(DigitString({e}, {d}), DigitString({a}, {d}), diffIndex: {d}, 11)); - {p} - """; - - s.AppendLine(text); - s.AppendLine(); - } - } - } - } + Action action = () => Assert.AreNotEqual("Straße", "STRAẞE", true, new CultureInfo("de-DE")); + action.Should().Throw() + .Which.Message.Should().Be( + """ + Assertion failed. Expected strings to differ (case-insensitive). - if (s.Length > 0) - { - throw new InvalidOperationException($"Some combinations pointed to ellipsis:\n{s}"); - } - } + not expected: "Straße" + actual: "STRAẞE" + ignore case: true + culture: de-DE - private string FormatStringPreview(Tuple tuple) - => $""" - "{tuple.Item1}" - "{tuple.Item2}" - {new string('_', tuple.Item3 + 1)}{'^'} - """; + Assert.AreNotEqual("Straße", "STRAẞE") + """); + } - private static string DigitString(int length, int diffIndex) + public void AreNotEqualStringSpecificWithBothNullShowsStructuredMessage() { - const string digits = "0123456789"; - if (length <= 0) - { - return string.Empty; - } + string? notExpected = null; + string? actual = null; - var result = new StringBuilder(length); - for (int i = 0; i < length; i++) - { - if (i == diffIndex) - { - // Use 'X' to indicate a difference should be at this index. - // To make it easier to see where the arrow should point, even though both strings are the same (we provide the diff index externally). - result.Append('X'); - continue; - } - - result.Append(digits[i % digits.Length]); - } - - return result.ToString(); - } + Action action = () => Assert.AreNotEqual(notExpected, actual, false); + action.Should().Throw() + .Which.Message.Should().Be( + """ + Assertion failed. Expected strings to differ. - private void StringPreviewsAreEqual(string expected, string actual) - { - if (expected != actual) - { - throw new InvalidOperationException( - $""" - Actual: - {actual} + not expected: null + actual: null - Expected: - {expected} + Assert.AreNotEqual(notExpected, actual) """); - } } + + public void AreNotEqualStringSpecificWhenDifferentDoesNotThrow() + => FluentActions.Invoking(() => Assert.AreNotEqual("Straße", "STRASSE!", true, new CultureInfo("de-DE"))).Should().NotThrow(); }