Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,34 @@ public static void AssertOutputMatchesRegex(this DotnetMuxerResult dotnetMuxerRe
public static void AssertOutputDoesNotContain(this TestHostResult testHostResult, string value, [CallerMemberName] string? callerMemberName = null, [CallerFilePath] string? callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
=> Assert.IsFalse(testHostResult.StandardOutput.Contains(value, StringComparison.Ordinal), GenerateFailedAssertionMessage(testHostResult, callerMemberName: callerMemberName, callerFilePath: callerFilePath, callerLineNumber: callerLineNumber));

/// <summary>
/// Asserts that the test host output contains the given value after Unicode normalization (FormC) and
/// non-breaking space (U+00A0) replacement. Use this instead of <see cref="AssertOutputContains"/> when
/// comparing localized strings that may use different normalization forms or typographic spacing conventions.
/// </summary>
public static void AssertOutputContainsNormalized(this TestHostResult testHostResult, string value, [CallerMemberName] string? callerMemberName = null, [CallerFilePath] string? callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
{
string normalizedOutput = NormalizeForLocalization(testHostResult.StandardOutput);
string normalizedValue = NormalizeForLocalization(value);
Assert.IsTrue(
normalizedOutput.Contains(normalizedValue, StringComparison.Ordinal),
GenerateFailedAssertionMessage(testHostResult, callerMemberName, callerFilePath, callerLineNumber));
}

/// <summary>
/// Asserts that the test host output does not contain the given value after Unicode normalization (FormC) and
/// non-breaking space (U+00A0) replacement. Use this instead of <see cref="AssertOutputDoesNotContain"/> when
/// comparing localized strings that may use different normalization forms or typographic spacing conventions.
/// </summary>
public static void AssertOutputDoesNotContainNormalized(this TestHostResult testHostResult, string value, [CallerMemberName] string? callerMemberName = null, [CallerFilePath] string? callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
{
string normalizedOutput = NormalizeForLocalization(testHostResult.StandardOutput);
string normalizedValue = NormalizeForLocalization(value);
Assert.IsFalse(
normalizedOutput.Contains(normalizedValue, StringComparison.Ordinal),
GenerateFailedAssertionMessage(testHostResult, callerMemberName, callerFilePath, callerLineNumber));
}

public static void AssertStandardErrorContains(this TestHostResult testHostResult, string value, [CallerMemberName] string? callerMemberName = null, [CallerFilePath] string? callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
=> Assert.Contains(value, testHostResult.StandardError, StringComparison.Ordinal, GenerateFailedAssertionMessage(testHostResult, callerMemberName: callerMemberName, callerFilePath: callerFilePath, callerLineNumber: callerLineNumber));

Expand Down Expand Up @@ -165,4 +193,9 @@ private static string GenerateFailedAssertionMessage(TestHostResult testHostResu

private static string GenerateFailedAssertionMessage(DotnetMuxerResult dotnetMuxerResult, string? callerMemberName, string? callerFilePath, int callerLineNumber, [CallerMemberName] string? assertCallerMemberName = null)
=> $"Expression '{assertCallerMemberName}' failed for member '{callerMemberName}' at line {callerLineNumber} of file '{callerFilePath}'. Output of the dotnet muxer is:{Environment.NewLine}{dotnetMuxerResult}";

// Localized resource strings may use different Unicode normalization forms (NFC vs NFD) than C# string literals.
// French locale also uses non-breaking space (U+00A0) before colons per typographic convention.
private static string NormalizeForLocalization(string text)
=> text.Normalize(NormalizationForm.FormC).Replace('\u00A0', ' ');
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// 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.Text;

namespace Microsoft.Testing.Platform.Acceptance.IntegrationTests;

// Temporarily disabled: OneLocBuild keeps reverting the TerminalResources.*.xlf targets to English,
Expand All @@ -13,23 +11,6 @@ public sealed class LocalizationFailingTests : AcceptanceTestBase<LocalizationFa
{
private const string AssetName = "LocalizationTestsFailing";

// Localized resource strings may use different Unicode normalization forms (NFC vs NFD)
// than C# string literals. Normalizing both sides to FormC avoids false mismatches
// with the ordinal comparison used by AssertOutputContains.
// French locale also uses non-breaking space (U+00A0) before colons per typographic convention,
// so we normalize NBSP to regular space for comparison.
private static string NormalizeForComparison(string text)
=> text.Normalize(NormalizationForm.FormC).Replace('\u00A0', ' ');

private static void AssertOutputContainsNormalized(TestHostResult testHostResult, string value)
{
string normalizedOutput = NormalizeForComparison(testHostResult.StandardOutput);
string normalizedValue = NormalizeForComparison(value);
Assert.IsTrue(
normalizedOutput.Contains(normalizedValue, StringComparison.Ordinal),
$"Output does not contain '{value}'.{Environment.NewLine}Output:{Environment.NewLine}{testHostResult.StandardOutput}");
}

[DynamicData(nameof(TargetFrameworks.AllForDynamicData), typeof(TargetFrameworks))]
[TestMethod]
public async Task Execution_WithFailingTest_OutputContainsTranslatedFailureSummary(string tfm)
Expand All @@ -42,8 +23,8 @@ public async Task Execution_WithFailingTest_OutputContainsTranslatedFailureSumma
testHostResult.AssertExitCodeIs(ExitCode.AtLeastOneTestFailed);

// Verify failure summary is in French ("Résumé de série de tests : Échec!")
AssertOutputContainsNormalized(testHostResult, "Résumé de série de tests : Échec!");
AssertOutputContainsNormalized(testHostResult, "échec: 1");
testHostResult.AssertOutputContainsNormalized("Résumé de série de tests : Échec!");
testHostResult.AssertOutputContainsNormalized("échec: 1");
}

public sealed class TestAssetFixture() : TestAssetFixtureBase()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// 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.Text;

namespace Microsoft.Testing.Platform.Acceptance.IntegrationTests;

// Temporarily disabled: OneLocBuild keeps reverting the TerminalResources.*.xlf targets to English,
Expand All @@ -13,32 +11,6 @@ public class LocalizationTests : AcceptanceTestBase<LocalizationTests.TestAssetF
{
private const string AssetName = "LocalizationTests";

// Localized resource strings may use different Unicode normalization forms (NFC vs NFD)
// than C# string literals. Normalizing both sides to FormC avoids false mismatches
// with the ordinal comparison used by AssertOutputContains.
// French locale also uses non-breaking space (U+00A0) before colons per typographic convention,
// so we normalize NBSP to regular space for comparison.
private static string NormalizeForComparison(string text)
=> text.Normalize(NormalizationForm.FormC).Replace('\u00A0', ' ');

private static void AssertOutputContainsNormalized(TestHostResult testHostResult, string value)
{
string normalizedOutput = NormalizeForComparison(testHostResult.StandardOutput);
string normalizedValue = NormalizeForComparison(value);
Assert.IsTrue(
normalizedOutput.Contains(normalizedValue, StringComparison.Ordinal),
$"Output does not contain '{value}'.{Environment.NewLine}Output:{Environment.NewLine}{testHostResult.StandardOutput}");
}

private static void AssertOutputDoesNotContainNormalized(TestHostResult testHostResult, string value)
{
string normalizedOutput = NormalizeForComparison(testHostResult.StandardOutput);
string normalizedValue = NormalizeForComparison(value);
Assert.IsFalse(
normalizedOutput.Contains(normalizedValue, StringComparison.Ordinal),
$"Output should not contain '{value}'.{Environment.NewLine}Output:{Environment.NewLine}{testHostResult.StandardOutput}");
}

[DynamicData(nameof(TargetFrameworks.AllForDynamicData), typeof(TargetFrameworks))]
[TestMethod]
public async Task Execution_WithFrenchLocale_OutputContainsTranslatedSummary(string tfm)
Expand All @@ -51,17 +23,17 @@ public async Task Execution_WithFrenchLocale_OutputContainsTranslatedSummary(str
testHostResult.AssertExitCodeIs(ExitCode.Success);

// Verify the summary line is in French ("Résumé de série de tests : Réussite!")
AssertOutputContainsNormalized(testHostResult, "Résumé de série de tests : Réussite!");
testHostResult.AssertOutputContainsNormalized("Résumé de série de tests : Réussite!");

// Verify the count labels are in French
AssertOutputContainsNormalized(testHostResult, "total: 2");
AssertOutputContainsNormalized(testHostResult, "échec: 0");
AssertOutputContainsNormalized(testHostResult, "opération réussie: 2");
AssertOutputContainsNormalized(testHostResult, "ignoré: 0");
testHostResult.AssertOutputContainsNormalized("total: 2");
testHostResult.AssertOutputContainsNormalized("échec: 0");
testHostResult.AssertOutputContainsNormalized("opération réussie: 2");
testHostResult.AssertOutputContainsNormalized("ignoré: 0");

// Verify English strings are NOT in the output
AssertOutputDoesNotContainNormalized(testHostResult, "Test run summary:");
AssertOutputDoesNotContainNormalized(testHostResult, "succeeded:");
testHostResult.AssertOutputDoesNotContainNormalized("Test run summary:");
testHostResult.AssertOutputDoesNotContainNormalized("succeeded:");
}

[DynamicData(nameof(TargetFrameworks.AllForDynamicData), typeof(TargetFrameworks))]
Expand Down Expand Up @@ -105,8 +77,8 @@ public async Task Execution_WithTestingPlatformUILanguage_TakesPrecedenceOverDot
testHostResult.AssertExitCodeIs(ExitCode.Success);

// French should win because TESTINGPLATFORM_UI_LANGUAGE has higher precedence
AssertOutputContainsNormalized(testHostResult, "Résumé de série de tests : Réussite!");
AssertOutputDoesNotContainNormalized(testHostResult, "Resumen de la serie de pruebas:");
testHostResult.AssertOutputContainsNormalized("Résumé de série de tests : Réussite!");
testHostResult.AssertOutputDoesNotContainNormalized("Resumen de la serie de pruebas:");
}

public sealed class TestAssetFixture() : TestAssetFixtureBase()
Expand Down
Loading