diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 505cb261af..15029ded69 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -16,11 +16,16 @@ env: LATEST_NET_VERSION: '9.0.x' PathToCommunityToolkitAnalyzersBenchmarkCsproj: 'src/CommunityToolkit.Maui.Analyzers.Benchmarks/CommunityToolkit.Maui.Analyzers.Benchmarks.csproj' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: run_benchmarks: name: Run Benchmarks runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [windows-latest, macos-15] diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml index 5f9b745950..8de3437fd5 100644 --- a/.github/workflows/dotnet-build.yml +++ b/.github/workflows/dotnet-build.yml @@ -32,7 +32,7 @@ env: PathToCommunityToolkitMediaElementCsproj: 'src/CommunityToolkit.Maui.MediaElement/CommunityToolkit.Maui.MediaElement.csproj' PathToCommunityToolkitMapsCsproj: 'src/CommunityToolkit.Maui.Maps/CommunityToolkit.Maui.Maps.csproj' PathToCommunityToolkitSampleCsproj: 'samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj' - PathToCommunityToolkitUnitTestCsproj: 'src/CommunityToolkit.Maui.UnitTests/CommunityToolkit.Maui.UnitTests.csproj' + PathToCommunityToolkitUnitTestCsproj: 'src/CommunityToolkit.Maui.UnitTests' PathToCommunityToolkitAnalyzersCsproj: 'src/CommunityToolkit.Maui.Analyzers/CommunityToolkit.Maui.Analyzers.csproj' PathToCommunityToolkitCameraAnalyzersCsproj: 'src/CommunityToolkit.Maui.Camera.Analyzers/CommunityToolkit.Maui.Camera.Analyzers.csproj' PathToCommunityToolkitMediaElementAnalyzersCsproj: 'src/CommunityToolkit.Maui.MediaElement.Analyzers/CommunityToolkit.Maui.MediaElement.Analyzers.csproj' @@ -41,16 +41,21 @@ env: PathToCommunityToolkitAnalyzersCodeFixCsproj: 'src/CommunityToolkit.Maui.Analyzers.CodeFixes/CommunityToolkit.Maui.Analyzers.CodeFixes.csproj' PathToCommunityToolkitCameraAnalyzersCodeFixCsproj: 'src/CommunityToolkit.Maui.Camera.Analyzers.CodeFixes/CommunityToolkit.Maui.Camera.Analyzers.CodeFixes.csproj' PathToCommunityToolkitMediaElementAnalyzersCodeFixCsproj: 'src/CommunityToolkit.Maui.MediaElement.Analyzers.CodeFixes/CommunityToolkit.Maui.MediaElement.Analyzers.CodeFixes.csproj' - PathToCommunityToolkitAnalyzersUnitTestCsproj: 'src/CommunityToolkit.Maui.Analyzers.UnitTests/CommunityToolkit.Maui.Analyzers.UnitTests.csproj' + PathToCommunityToolkitAnalyzersUnitTestCsproj: 'src/CommunityToolkit.Maui.Analyzers.UnitTests' PathToCommunityToolkitAnalyzersBenchmarkCsproj: 'src/CommunityToolkit.Maui.Analyzers.Benchmarks/CommunityToolkit.Maui.Analyzers.Benchmarks.csproj' CommunityToolkitSampleApp_Xcode_Version: '16.2' CommunityToolkitLibrary_Xcode_Version: '16.2' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: build_sample: name: Build Sample App using Latest .NET SDK runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [windows-latest, macos-15] steps: @@ -90,9 +95,8 @@ jobs: build_library: name: Build Library runs-on: ${{ matrix.os }} - env: - VSTEST_TESTHOST_SHUTDOWN_TIMEOUT: 1100 # Fixes "The active test run was aborted. Reason: Test host process crashed" strategy: + fail-fast: false matrix: os: [windows-latest, macos-15] steps: @@ -189,16 +193,24 @@ jobs: - name: 'Build CommunityToolkit.Maui' run: dotnet build ${{ env.PathToLibrarySolution }} -c Release -p:PackageVersion=${{ env.NugetPackageVersion }} -p:Version=${{ env.NugetPackageVersion }} - - name: Run All Unit Tests - run: dotnet test -c Release ${{ env.PathToLibrarySolution }} --settings ".runsettings" --collect "XPlat code coverage" --logger trx --results-directory ${{ runner.temp }} --logger GitHubActions + - name: Run CommunityToolkit Analyzers UnitTests + run: | + cd ${{ env.PathToCommunityToolkitAnalyzersUnitTestCsproj }} + dotnet run -c Release --results-directory "${{ runner.temp }}" --coverage --coverage-output "${{ runner.temp }}/ut-analyzers.cobertura.xml" --coverage-output-format cobertura --report-xunit + + - name: Run CommunityToolkit UnitTests + run: | + cd ${{ env.PathToCommunityToolkitUnitTestCsproj }} + dotnet run -c Release --results-directory "${{ runner.temp }}" --coverage --coverage-output "${{ runner.temp }}/ut.cobertura.xml" --coverage-output-format cobertura --report-xunit - name: Publish Test Results - if: runner.os == 'Windows' + if: runner.os == 'Windows' && (${{ success() || failure() }}) uses: actions/upload-artifact@v4 with: - name: Test Results + name: Test Results ${{ github.run_number }} ${{ runner.os }} path: | - ${{ runner.temp }}/**/*.trx + ${{ runner.temp }}/*.xunit + ${{ runner.temp }}/*cobertura.xml - name: Pack CommunityToolkit.Maui.Core NuGet run: dotnet pack -c Release ${{ env.PathToCommunityToolkitCoreCsproj }} -p:PackageVersion=${{ env.NugetPackageVersion }} diff --git a/azure-pipelines.yml b/azure-pipelines.yml-old similarity index 100% rename from azure-pipelines.yml rename to azure-pipelines.yml-old diff --git a/samples/CommunityToolkit.Maui.Sample.sln b/samples/CommunityToolkit.Maui.Sample.sln index 880a72a736..78ce7b63ea 100644 --- a/samples/CommunityToolkit.Maui.Sample.sln +++ b/samples/CommunityToolkit.Maui.Sample.sln @@ -12,8 +12,10 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3ED2C978-9DDB-48FE-8C5A-521B254F18A3}" ProjectSection(SolutionItems) = preProject ..\.editorconfig = ..\.editorconfig + ..\.github\workflows\benchmarks.yml = ..\.github\workflows\benchmarks.yml ..\Directory.Build.props = ..\Directory.Build.props ..\Directory.Build.targets = ..\Directory.Build.targets + ..\.github\workflows\dotnet-build.yml = ..\.github\workflows\dotnet-build.yml ..\global.json = ..\global.json EndProjectSection EndProject diff --git a/src/CommunityToolkit.Maui.Analyzers.UnitTests/CommunityToolkit.Maui.Analyzers.UnitTests.csproj b/src/CommunityToolkit.Maui.Analyzers.UnitTests/CommunityToolkit.Maui.Analyzers.UnitTests.csproj index 5704417b12..45bc1ac645 100644 --- a/src/CommunityToolkit.Maui.Analyzers.UnitTests/CommunityToolkit.Maui.Analyzers.UnitTests.csproj +++ b/src/CommunityToolkit.Maui.Analyzers.UnitTests/CommunityToolkit.Maui.Analyzers.UnitTests.csproj @@ -2,30 +2,35 @@ $(NetVersion) - false true $(BaseIntermediateOutputPath)\GF true true + + Exe + CommunityToolkit.Maui.Analyzers.UnitTests + + false + true - - - - - - - - + + + + + + + + - - + + diff --git a/src/CommunityToolkit.Maui.Analyzers.UnitTests/xunit.runner.json b/src/CommunityToolkit.Maui.Analyzers.UnitTests/xunit.runner.json new file mode 100644 index 0000000000..f78bc2f0c6 --- /dev/null +++ b/src/CommunityToolkit.Maui.Analyzers.UnitTests/xunit.runner.json @@ -0,0 +1,3 @@ +{ + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json" +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Extensions/PageExtensions.cs b/src/CommunityToolkit.Maui.MediaElement/Extensions/PageExtensions.cs index 62db610fc3..80ae10965e 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Extensions/PageExtensions.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Extensions/PageExtensions.cs @@ -31,7 +31,7 @@ internal static Page GetCurrentPage(this Page currentPage) internal record struct ParentWindow { - static Page CurrentPage => GetCurrentPage(Application.Current?.Windows[0].Page ?? throw new InvalidOperationException($"{nameof(Page)} cannot be null.")); + static Page CurrentPage => GetCurrentPage(Application.Current?.Windows[^1].Page ?? throw new InvalidOperationException($"{nameof(Page)} cannot be null.")); /// /// Checks if the parent window is null. /// diff --git a/src/CommunityToolkit.Maui.SourceGenerators/Generators/TextColorToGenerator.cs b/src/CommunityToolkit.Maui.SourceGenerators/Generators/TextColorToGenerator.cs index 7c7561baea..9c820a6331 100644 --- a/src/CommunityToolkit.Maui.SourceGenerators/Generators/TextColorToGenerator.cs +++ b/src/CommunityToolkit.Maui.SourceGenerators/Generators/TextColorToGenerator.cs @@ -145,6 +145,7 @@ namespace {{textStyleClassMetadata.Namespace}}; public static Task TextColorTo{{textStyleClassMetadata.GenericArguments}}(this global::{{textStyleClassMetadata.Namespace}}.{{textStyleClassMetadata.ClassName}}{{textStyleClassMetadata.GenericArguments}} element, {{mauiColorFullName}} color, uint rate = 16u, uint length = 250u, Easing? easing = null, CancellationToken token = default) {{textStyleClassMetadata.GenericConstraints}} { + token.ThrowIfCancellationRequested(); ArgumentNullException.ThrowIfNull(element); ArgumentNullException.ThrowIfNull(color); diff --git a/src/CommunityToolkit.Maui.UnitTests/Alerts/SnackbarTests.cs b/src/CommunityToolkit.Maui.UnitTests/Alerts/SnackbarTests.cs index f93bfa6d53..d873bd64c6 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Alerts/SnackbarTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Alerts/SnackbarTests.cs @@ -38,7 +38,7 @@ public async Task SnackbarShow_CancellationTokenExpires() var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)); // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); await Assert.ThrowsAsync(() => snackbar.Show(cts.Token)); } @@ -61,7 +61,7 @@ public async Task SnackbarDismiss_CancellationTokenExpires() var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)); // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); await Assert.ThrowsAsync(() => snackbar.Dismiss(cts.Token)); } @@ -81,14 +81,14 @@ await Assert.ThrowsAsync(() => [Fact(Timeout = (int)TestDuration.Short)] public async Task SnackbarShow_IsShownTrue() { - await snackbar.Show(CancellationToken.None); + await snackbar.Show(TestContext.Current.CancellationToken); Assert.True(Snackbar.IsShown); } [Fact(Timeout = (int)TestDuration.Short)] public async Task SnackbarDismissed_IsShownFalse() { - await snackbar.Dismiss(CancellationToken.None); + await snackbar.Dismiss(TestContext.Current.CancellationToken); Assert.False(Snackbar.IsShown); } @@ -100,7 +100,7 @@ public async Task SnackbarShow_ShownEventRaised() { receivedEvents.Add(e); }; - await snackbar.Show(CancellationToken.None); + await snackbar.Show(TestContext.Current.CancellationToken); Assert.Single(receivedEvents); } @@ -112,7 +112,7 @@ public async Task SnackbarDismiss_DismissedEventRaised() { receivedEvents.Add(e); }; - await snackbar.Dismiss(CancellationToken.None); + await snackbar.Dismiss(TestContext.Current.CancellationToken); Assert.Single(receivedEvents); } @@ -125,7 +125,7 @@ public async Task VisualElement_DisplaySnackbar_ShownEventReceived() receivedEvents.Add(e); }; var button = new Button(); - await button.DisplaySnackbar("message", token: CancellationToken.None); + await button.DisplaySnackbar("message", token: TestContext.Current.CancellationToken); Assert.Single(receivedEvents); } @@ -210,13 +210,13 @@ public async Task SnackbarDismiss_CancellationTokenNotCancelled_NotReceiveExcept [Fact(Timeout = (int)TestDuration.Short)] public async Task SnackbarShow_CancellationTokenNone_NotReceiveException() { - await snackbar.Invoking(x => x.Show(CancellationToken.None)).Should().NotThrowAsync(); + await snackbar.Invoking(x => x.Show(TestContext.Current.CancellationToken)).Should().NotThrowAsync(); } [Fact(Timeout = (int)TestDuration.Short)] public async Task SnackbarDismiss_CancellationTokenNone_NotReceiveException() { - await snackbar.Invoking(x => x.Dismiss(CancellationToken.None)).Should().NotThrowAsync(); + await snackbar.Invoking(x => x.Dismiss(TestContext.Current.CancellationToken)).Should().NotThrowAsync(); } [Fact] @@ -233,8 +233,8 @@ public async Task SnackbarNullValuesThrowArgumentNullException() }); Assert.Throws(() => Snackbar.Make(null)); Assert.Throws(() => Snackbar.Make(string.Empty, actionButtonText: null)); - await Assert.ThrowsAsync(() => new Button().DisplaySnackbar(null, token: CancellationToken.None)); - await Assert.ThrowsAsync(() => new Button().DisplaySnackbar(string.Empty, actionButtonText: null, token: CancellationToken.None)); + await Assert.ThrowsAsync(() => new Button().DisplaySnackbar(null, token: TestContext.Current.CancellationToken)); + await Assert.ThrowsAsync(() => new Button().DisplaySnackbar(string.Empty, actionButtonText: null, token: TestContext.Current.CancellationToken)); #pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.UnitTests/Alerts/ToastTests.cs b/src/CommunityToolkit.Maui.UnitTests/Alerts/ToastTests.cs index 10d8e9749d..90e32e007d 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Alerts/ToastTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Alerts/ToastTests.cs @@ -21,7 +21,7 @@ public async Task ToastShow_CancellationTokenExpires() var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)); // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); await Assert.ThrowsAsync(() => toast.Show(cts.Token)); } @@ -44,7 +44,7 @@ public async Task ToastDismiss_CancellationTokenExpires() var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)); // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); await Assert.ThrowsAsync(() => toast.Dismiss(cts.Token)); } @@ -116,13 +116,13 @@ public async Task ToastDismiss_CancellationTokenNotCancelled_NotReceiveException [Fact(Timeout = (int)TestDuration.Short)] public async Task ToastShow_CancellationTokenNone_NotReceiveException() { - await toast.Invoking(x => x.Show(CancellationToken.None)).Should().NotThrowAsync(); + await toast.Invoking(x => x.Show(TestContext.Current.CancellationToken)).Should().NotThrowAsync(); } [Fact(Timeout = (int)TestDuration.Short)] public async Task ToastDismiss_CancellationTokenNone_NotReceiveException() { - await toast.Invoking(x => x.Dismiss(CancellationToken.None)).Should().NotThrowAsync(); + await toast.Invoking(x => x.Dismiss(TestContext.Current.CancellationToken)).Should().NotThrowAsync(); } [Fact] diff --git a/src/CommunityToolkit.Maui.UnitTests/Animations/FadeAnimationTests.cs b/src/CommunityToolkit.Maui.UnitTests/Animations/FadeAnimationTests.cs index 92091ad858..af57c8c3d2 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Animations/FadeAnimationTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Animations/FadeAnimationTests.cs @@ -13,7 +13,7 @@ public async Task AnimateShouldThrowWithNullView() FadeAnimation animation = new(); #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. - await Assert.ThrowsAsync(() => animation.Animate(null, CancellationToken.None)); + await Assert.ThrowsAsync(() => animation.Animate(null, TestContext.Current.CancellationToken)); #pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } @@ -29,10 +29,10 @@ public async Task CancellationTokenCanceled() }; label.EnableAnimations(); - await Assert.ThrowsAsync(() => + await Assert.ThrowsAsync(async () => { - cts.Cancel(); - return animation.Animate(label, cts.Token); + await cts.CancelAsync(); + await animation.Animate(label, cts.Token); }); } @@ -48,7 +48,8 @@ public async Task CancellationTokenExpired() }; label.EnableAnimations(); - await Assert.ThrowsAsync(() => animation.Animate(label, cts.Token)); + await Task.Delay(10, TestContext.Current.CancellationToken); + await Assert.ThrowsAsync(() => animation.Animate(label, cts.Token)); } [Fact(Timeout = (int)TestDuration.Medium)] @@ -62,7 +63,7 @@ public async Task AnimateShouldReturnToOriginalOpacity() }; label.EnableAnimations(); - await animation.Animate(label, CancellationToken.None); + await animation.Animate(label, TestContext.Current.CancellationToken); label.Opacity.Should().Be(0.9); } diff --git a/src/CommunityToolkit.Maui.UnitTests/BaseHandlerTest.cs b/src/CommunityToolkit.Maui.UnitTests/BaseHandlerTest.cs index b52ac266ae..779fdddfc1 100644 --- a/src/CommunityToolkit.Maui.UnitTests/BaseHandlerTest.cs +++ b/src/CommunityToolkit.Maui.UnitTests/BaseHandlerTest.cs @@ -5,9 +5,9 @@ namespace CommunityToolkit.Maui.UnitTests; public abstract class BaseHandlerTest : BaseTest { - protected BaseHandlerTest(IReadOnlyList? servicesToRegister = null) + protected BaseHandlerTest() { - InitializeServicesAndSetMockApplication(servicesToRegister ?? [], out var serviceProvider); + InitializeServicesAndSetMockApplication(out var serviceProvider); ServiceProvider = serviceProvider; } @@ -41,7 +41,7 @@ protected static TViewHandler CreateViewHandler(IView view, bool d return mockViewHandler; } - static void InitializeServicesAndSetMockApplication(in IReadOnlyList transientServicesToRegister, out IServiceProvider serviceProvider) + static void InitializeServicesAndSetMockApplication(out IServiceProvider serviceProvider) { var appBuilder = MauiApp.CreateBuilder() .UseMauiCommunityToolkit() @@ -60,24 +60,21 @@ static void InitializeServicesAndSetMockApplication(in IReadOnlyList trans PopupService.ClearViewModelToViewMappings(); PopupService.AddTransientPopup(mockPopup, mockPageViewModel, appBuilder.Services); + var page = new ContentPage(); #endregion - foreach (var service in transientServicesToRegister) - { - appBuilder.Services.AddTransient(service); - } - var mauiApp = appBuilder.Build(); var application = (MockApplication)mauiApp.Services.GetRequiredService(); - application.AddWindow(new Window()); + application.AddWindow(new Window() { Page = page }); serviceProvider = mauiApp.Services; IPlatformApplication.Current = application; application.Handler = new ApplicationHandlerStub(); - application.Handler.SetMauiContext(new HandlersContextStub(mauiApp.Services)); + application.Handler.SetMauiContext(new HandlersContextStub(serviceProvider)); CreateElementHandler(mockPopup); + CreateViewHandler(page); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.UnitTests/BaseTest.cs b/src/CommunityToolkit.Maui.UnitTests/BaseTest.cs index 4abd310f36..1ef71b7580 100644 --- a/src/CommunityToolkit.Maui.UnitTests/BaseTest.cs +++ b/src/CommunityToolkit.Maui.UnitTests/BaseTest.cs @@ -1,11 +1,15 @@ using System.Globalization; using CommunityToolkit.Maui.UnitTests.Mocks; +using Xunit; namespace CommunityToolkit.Maui.UnitTests; +[Collection("CommunityToolkit.UnitTests")] public abstract class BaseTest : IDisposable { readonly CultureInfo defaultCulture, defaultUiCulture; + protected readonly MockAppInfo mockAppInfo; + protected const AppTheme initialAppTheme = AppTheme.Light; bool isDisposed; @@ -18,14 +22,15 @@ protected enum TestDuration protected BaseTest() { - CompatibilityCheck.UseCompatibility(); - defaultCulture = Thread.CurrentThread.CurrentCulture; defaultUiCulture = Thread.CurrentThread.CurrentUICulture; DeviceDisplay.SetCurrent(null); DeviceInfo.SetCurrent(null); - AppInfo.SetCurrent(null); + AppInfo.SetCurrent(mockAppInfo = new() + { + RequestedTheme = initialAppTheme + }); DispatcherProvider.SetCurrent(new MockDispatcherProvider()); DeviceDisplay.SetCurrent(null); diff --git a/src/CommunityToolkit.Maui.UnitTests/Behaviors/AnimationBehaviorTests.cs b/src/CommunityToolkit.Maui.UnitTests/Behaviors/AnimationBehaviorTests.cs index cc2dac5055..097eb46a73 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Behaviors/AnimationBehaviorTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Behaviors/AnimationBehaviorTests.cs @@ -72,7 +72,7 @@ public async Task AnimateCommandStartsAnimation() Behaviors = { behavior } }.EnableAnimations(); - behavior.AnimateCommand.Execute(CancellationToken.None); + behavior.AnimateCommand.Execute(TestContext.Current.CancellationToken); await animationStartedTcs.Task; await animationEndedTcs.Task; @@ -101,7 +101,7 @@ void HandleAnimationEnded(object? sender, EventArgs e) [Fact] public void AnimateCommandTokenCanceled() { - TaskCanceledException? exception = null; + OperationCanceledException? exception = null; var animationEndedTcs = new TaskCompletionSource(); var animationCommandCts = new CancellationTokenSource(); @@ -128,7 +128,7 @@ public void AnimateCommandTokenCanceled() await animationEndedTcs.Task; }); } - catch (TaskCanceledException e) + catch (OperationCanceledException e) { exception = e; } @@ -145,7 +145,7 @@ void HandleAnimationEnded(object? sender, EventArgs e) [Fact] public void AnimateCommandTokenExpired() { - TaskCanceledException? exception = null; + OperationCanceledException? exception = null; var animationEndedTcs = new TaskCompletionSource(); var animationCommandCts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)); @@ -171,7 +171,7 @@ public void AnimateCommandTokenExpired() await animationEndedTcs.Task; }); } - catch (TaskCanceledException e) + catch (OperationCanceledException e) { exception = e; } diff --git a/src/CommunityToolkit.Maui.UnitTests/Behaviors/CharactersValidationBehaviorTests.cs b/src/CommunityToolkit.Maui.UnitTests/Behaviors/CharactersValidationBehaviorTests.cs index b486346ca1..2381f67561 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Behaviors/CharactersValidationBehaviorTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Behaviors/CharactersValidationBehaviorTests.cs @@ -50,7 +50,7 @@ public async Task IsValid(CharacterType characterType, int minimumCharactersNumb entry.Behaviors.Add(behavior); // Act - await behavior.ForceValidate(CancellationToken.None); + await behavior.ForceValidate(TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedValue, behavior.IsValid); @@ -72,7 +72,7 @@ public async Task CancellationTokenExpired() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => await behavior.ForceValidate(cts.Token)); @@ -94,7 +94,7 @@ public async Task CancellationTokenCanceled() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => diff --git a/src/CommunityToolkit.Maui.UnitTests/Behaviors/EmailValidationBehaviorTests.cs b/src/CommunityToolkit.Maui.UnitTests/Behaviors/EmailValidationBehaviorTests.cs index 8f4cdeb3da..4ed293eab4 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Behaviors/EmailValidationBehaviorTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Behaviors/EmailValidationBehaviorTests.cs @@ -246,7 +246,7 @@ public async Task IsValid(string value, bool expectedValue) entry.Behaviors.Add(behavior); // Act - await behavior.ForceValidate(CancellationToken.None); + await behavior.ForceValidate(TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedValue, behavior.IsValid); @@ -268,7 +268,7 @@ public async Task ForceValidateCancellationTokenExpired() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => await behavior.ForceValidate(cts.Token)); diff --git a/src/CommunityToolkit.Maui.UnitTests/Behaviors/ImageTouchBehaviorTests.cs b/src/CommunityToolkit.Maui.UnitTests/Behaviors/ImageTouchBehaviorTests.cs index 104532e3c4..9a761b5ff4 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Behaviors/ImageTouchBehaviorTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Behaviors/ImageTouchBehaviorTests.cs @@ -77,7 +77,7 @@ public async Task VerifyPressedBackgroundImageChange() Assert.Null(view.Source); - await imageTouchBehavior.ForceUpdateState(CancellationToken.None, false); + await imageTouchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(normalImageSource, view.Source); Assert.Same(normalImageSource, view.Source); @@ -106,7 +106,7 @@ public async Task VerifyPressedBackgroundImageAspectChange() Assert.Equal(Aspect.AspectFit, view.Aspect); - await imageTouchBehavior.ForceUpdateState(CancellationToken.None, false); + await imageTouchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(Aspect.AspectFit, view.Aspect); imageTouchBehavior.HandleTouch(TouchStatus.Started); @@ -128,7 +128,7 @@ public async Task VerifyHoverBackgroundImageChange() imageTouchBehavior.DefaultImageSource = normalImageSource; imageTouchBehavior.HoveredImageSource = hoveredImageSource; - await imageTouchBehavior.ForceUpdateState(CancellationToken.None, false); + await imageTouchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Same(normalImageSource, view.Source); Assert.Equal(normalImageSource, view.Source); @@ -155,7 +155,7 @@ public async Task VerifyHoverBackgroundImageAspectChange() imageTouchBehavior.HoveredImageSource = hoverImageSource; imageTouchBehavior.HoveredImageAspect = Aspect.AspectFill; - await imageTouchBehavior.ForceUpdateState(CancellationToken.None, false); + await imageTouchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(Aspect.AspectFit, view.Aspect); imageTouchBehavior.HandleHover(HoverStatus.Entered); diff --git a/src/CommunityToolkit.Maui.UnitTests/Behaviors/MultiValidationBehaviorTests.cs b/src/CommunityToolkit.Maui.UnitTests/Behaviors/MultiValidationBehaviorTests.cs index 0de9412b10..f35088e4b7 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Behaviors/MultiValidationBehaviorTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Behaviors/MultiValidationBehaviorTests.cs @@ -58,7 +58,7 @@ public async Task IsValid(CharacterType characterType, int minimumCharactersNumb entry.Behaviors.Add(multiBehavior); // Act - await multiBehavior.ForceValidate(CancellationToken.None); + await multiBehavior.ForceValidate(TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedValue, multiBehavior.IsValid); @@ -86,7 +86,7 @@ public async Task ForceValidateCancellationTokenExpired() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => await multiBehavior.ForceValidate(cts.Token)); diff --git a/src/CommunityToolkit.Maui.UnitTests/Behaviors/NumericValidationBehaviorTests.cs b/src/CommunityToolkit.Maui.UnitTests/Behaviors/NumericValidationBehaviorTests.cs index 79fe27c195..a13e7158f1 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Behaviors/NumericValidationBehaviorTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Behaviors/NumericValidationBehaviorTests.cs @@ -61,7 +61,7 @@ public async Task IsValid(string culture, string? value, double minValue, double try { // Act - await behavior.ForceValidate(CancellationToken.None); + await behavior.ForceValidate(TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedValue, behavior.IsValid); @@ -86,7 +86,7 @@ public async Task IsNull() }; entry.Behaviors.Add(behavior); - await Assert.ThrowsAsync(async () => await behavior.ForceValidate(CancellationToken.None)); + await Assert.ThrowsAsync(async () => await behavior.ForceValidate(TestContext.Current.CancellationToken)); } [Fact(Timeout = (int)TestDuration.Short)] @@ -106,7 +106,7 @@ public async Task ShouldNotThrowIsNull() }; entry.Behaviors.Add(behavior); - var action = (async () => await behavior.ForceValidate(CancellationToken.None)); + var action = (async () => await behavior.ForceValidate(TestContext.Current.CancellationToken)); await action.Should().NotThrowAsync(); options.SetShouldSuppressExceptionsInBehaviors(false); @@ -128,7 +128,7 @@ public async Task CancellationTokenExpired() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => await behavior.ForceValidate(cts.Token)); @@ -150,7 +150,7 @@ public async Task CancellationTokenCanceled() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => diff --git a/src/CommunityToolkit.Maui.UnitTests/Behaviors/TextValidationBehaviorTests.cs b/src/CommunityToolkit.Maui.UnitTests/Behaviors/TextValidationBehaviorTests.cs index df46f471e1..4b8020514f 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Behaviors/TextValidationBehaviorTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Behaviors/TextValidationBehaviorTests.cs @@ -31,7 +31,7 @@ public async Task IsValid(string pattern, RegexOptions options, int minLength, i entry.Behaviors.Add(behavior); // Act - await behavior.ForceValidate(CancellationToken.None); + await behavior.ForceValidate(TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedValue, behavior.IsValid); @@ -53,7 +53,7 @@ public async Task CancellationTokenExpired() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => await behavior.ForceValidate(cts.Token)); @@ -75,7 +75,7 @@ public async Task CancellationTokenCanceled() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => diff --git a/src/CommunityToolkit.Maui.UnitTests/Behaviors/TouchBehaviorTests.cs b/src/CommunityToolkit.Maui.UnitTests/Behaviors/TouchBehaviorTests.cs index 142f4fe594..2e90358947 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Behaviors/TouchBehaviorTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Behaviors/TouchBehaviorTests.cs @@ -115,7 +115,7 @@ public async Task VerifyHoverOpacityChange() Assert.Equal(updatedDefaultOpacity, touchBehavior.DefaultOpacity); Assert.Equal(updatedHoveredOpacity, touchBehavior.HoveredOpacity); - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(updatedDefaultOpacity, view.Opacity); touchBehavior.HandleHover(HoverStatus.Entered); @@ -156,7 +156,7 @@ public async Task VerifyPressedOpacityChange() Assert.Equal(TouchBehaviorDefaults.DefaultOpacity, view.Opacity); - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(updatedDefaultOpacity, view.Opacity); touchBehavior.HandleTouch(TouchStatus.Started); @@ -182,7 +182,7 @@ public async Task VerifyHoverTranslationChange() Assert.Equal(TouchBehaviorDefaults.DefaultTranslationX, view.TranslationX); Assert.Equal(TouchBehaviorDefaults.DefaultTranslationY, view.TranslationY); - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(updatedDefaultTranslation, view.TranslationX); Assert.Equal(updatedDefaultTranslation, view.TranslationY); @@ -211,7 +211,7 @@ public async Task VerifyPressedTranslationChange() Assert.Equal(TouchBehaviorDefaults.PressedTranslationX, view.TranslationX); Assert.Equal(TouchBehaviorDefaults.PressedTranslationY, view.TranslationY); - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(updatedDefaultTranslation, view.TranslationX); Assert.Equal(updatedDefaultTranslation, view.TranslationY); @@ -238,7 +238,7 @@ public async Task VerifyHoverScaleChange() Assert.Equal(TouchBehaviorDefaults.DefaultScale, view.Scale); - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(updatedDefaultScale, view.Scale); touchBehavior.HandleHover(HoverStatus.Entered); @@ -261,7 +261,7 @@ public async Task VerifyPressedScaleChange() Assert.Equal(TouchBehaviorDefaults.DefaultScale, view.Scale); - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(updatedDefaultScale, view.Scale); touchBehavior.HandleTouch(TouchStatus.Started); @@ -289,7 +289,7 @@ public async Task VerifyHoverRotationChange() Assert.Equal(TouchBehaviorDefaults.DefaultRotationX, view.RotationX); Assert.Equal(TouchBehaviorDefaults.DefaultRotationY, view.RotationY); - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(updatedDefaultRotation, view.Rotation); Assert.Equal(updatedDefaultRotation, view.RotationX); Assert.Equal(updatedDefaultRotation, view.RotationY); @@ -325,7 +325,7 @@ public async Task VerifyPressedRotationChange() Assert.Equal(TouchBehaviorDefaults.DefaultRotationX, view.RotationX); Assert.Equal(TouchBehaviorDefaults.DefaultRotationY, view.RotationY); - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(updatedDefaultRotation, view.Rotation); Assert.Equal(updatedDefaultRotation, view.RotationX); Assert.Equal(updatedDefaultRotation, view.RotationY); @@ -354,7 +354,7 @@ public async Task VerifyHoverBackgroundColorChange() Assert.Equal(TouchBehaviorDefaults.DefaultBackgroundColor, view.BackgroundColor); - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(defaultColor, view.BackgroundColor); touchBehavior.HandleHover(HoverStatus.Entered); @@ -378,7 +378,7 @@ public async Task VerifyPressedBackgroundColorChange() Assert.Equal(TouchBehaviorDefaults.DefaultBackgroundColor, view.BackgroundColor); - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); Assert.Equal(defaultColor, view.BackgroundColor); touchBehavior.HandleTouch(TouchStatus.Started); @@ -683,7 +683,7 @@ public async Task VerifyIsToggledChangesState() var touchStatusChangedTCS = new TaskCompletionSource(); touchBehavior.CurrentTouchStatusChanged += HandleTouchStatusChanged; - await touchBehavior.ForceUpdateState(CancellationToken.None, false); + await touchBehavior.ForceUpdateState(TestContext.Current.CancellationToken, false); touchStatusChangedTCS = new TaskCompletionSource(); touchBehavior.HandleTouch(TouchStatus.Started); diff --git a/src/CommunityToolkit.Maui.UnitTests/Behaviors/UriValidationBehaviorTests.cs b/src/CommunityToolkit.Maui.UnitTests/Behaviors/UriValidationBehaviorTests.cs index 58774a7683..3cc432155b 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Behaviors/UriValidationBehaviorTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Behaviors/UriValidationBehaviorTests.cs @@ -22,7 +22,7 @@ public async Task IsValid(string value, UriKind uriKind, bool expectedValue) }; // Act - await behavior.ForceValidate(CancellationToken.None); + await behavior.ForceValidate(TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedValue, behavior.IsValid); @@ -44,7 +44,7 @@ public async Task CancellationTokenExpired() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => await behavior.ForceValidate(cts.Token)); @@ -66,7 +66,7 @@ public async Task CancellationTokenCanceled() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => diff --git a/src/CommunityToolkit.Maui.UnitTests/Behaviors/ValidationBehaviorTests.cs b/src/CommunityToolkit.Maui.UnitTests/Behaviors/ValidationBehaviorTests.cs index 103e92e571..834e3dbb1a 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Behaviors/ValidationBehaviorTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Behaviors/ValidationBehaviorTests.cs @@ -1,10 +1,11 @@ using CommunityToolkit.Maui.Behaviors; using CommunityToolkit.Maui.UnitTests.Mocks; using Xunit; +using Xunit.v3; namespace CommunityToolkit.Maui.UnitTests.Behaviors; -public class ValidationBehaviorTests() : BaseBehaviorTest(new MockValidationBehavior(), new View()) +public class ValidationBehaviorTests(ITestOutputHelper testOutputHelper) : BaseBehaviorTest(new MockValidationBehavior(), new View()) { [Fact] public void ValidateOnValueChanged() @@ -39,10 +40,10 @@ public async Task ValidValue_ValidStyle() }; var validStyle = new Style(entry.GetType()); - validStyle.Setters.Add(new Setter() { Property = Entry.BackgroundColorProperty, Value = Colors.Green }); + validStyle.Setters.Add(new Setter() { Property = VisualElement.BackgroundColorProperty, Value = Colors.Green }); var invalidStyle = new Style(entry.GetType()); - invalidStyle.Setters.Add(new Setter() { Property = Entry.BackgroundColorProperty, Value = Colors.Red }); + invalidStyle.Setters.Add(new Setter() { Property = VisualElement.BackgroundColorProperty, Value = Colors.Red }); var behavior = new MockValidationBehavior() { @@ -55,7 +56,7 @@ public async Task ValidValue_ValidStyle() // Act entry.Text = "321"; - await behavior.ForceValidate(CancellationToken.None); + await behavior.ForceValidate(TestContext.Current.CancellationToken); // Assert Assert.Equal(entry.Style, validStyle); @@ -71,10 +72,10 @@ public async Task InvalidValue_InvalidStyle() }; var validStyle = new Style(entry.GetType()); - validStyle.Setters.Add(new Setter() { Property = Entry.BackgroundColorProperty, Value = Colors.Green }); + validStyle.Setters.Add(new Setter() { Property = VisualElement.BackgroundColorProperty, Value = Colors.Green }); var invalidStyle = new Style(entry.GetType()); - invalidStyle.Setters.Add(new Setter() { Property = Entry.BackgroundColorProperty, Value = Colors.Red }); + invalidStyle.Setters.Add(new Setter() { Property = VisualElement.BackgroundColorProperty, Value = Colors.Red }); var behavior = new MockValidationBehavior() { @@ -87,10 +88,23 @@ public async Task InvalidValue_InvalidStyle() // Act entry.Text = "321"; - await behavior.ForceValidate(CancellationToken.None); + await behavior.ForceValidate(TestContext.Current.CancellationToken); // Assert - Assert.Equal(entry.Style, invalidStyle); + Assert.Equal(entry.Style, invalidStyle, (style1, style2) => + { + if (style1 == null || style2 == null) + { + return style1 == style2; + } + + testOutputHelper.WriteLine($"Style1: {style1.Setters.Count} - Style2: {style2.Setters.Count}"); + testOutputHelper.WriteLine($"Style1: {style1.TargetType.FullName} - Style2: {style2.TargetType.FullName}"); + + return style1.Setters.Count == style2.Setters.Count + && style1.TargetType.FullName == style2.TargetType.FullName + && style1.Setters.All(x => style2.Setters.Contains(x, new StyleSetterComparer(testOutputHelper))); + }); } [Fact(Timeout = (int)TestDuration.Short)] @@ -116,7 +130,7 @@ public async Task IsRunning() Assert.False(behavior.IsRunning); // Act - var forceValidateTask = behavior.ForceValidate(CancellationToken.None); + var forceValidateTask = behavior.ForceValidate(TestContext.Current.CancellationToken); // Assert Assert.True(behavior.IsRunning); @@ -136,7 +150,7 @@ public void ForceValidateCommand() var behavior = new MockValidationBehavior() { ExpectedValue = "321", - ForceValidateCommand = new Command(token => + ForceValidateCommand = new Command(_ => { entry.Text = "321"; }) @@ -167,7 +181,7 @@ public async Task CancellationTokenExpired() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => await behavior.ForceValidate(cts.Token)); @@ -189,7 +203,7 @@ public async Task CancellationTokenCanceled() // Act // Ensure CancellationToken expires - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); // Assert await Assert.ThrowsAsync(async () => @@ -231,4 +245,39 @@ public void TestRemoveValidationBindingWithoutBindingContext() Assert.Empty(view.Behaviors); } +} + +public class StyleSetterComparer(ITestOutputHelper testOutputHelper) : IEqualityComparer +{ + public bool Equals(Setter? x, Setter? y) + { + if (ReferenceEquals(x, y)) + { + return true; + } + + if (x is null) + { + return false; + } + + if (y is null) + { + return false; + } + + if (x.GetType() != y.GetType()) + { + return false; + } + + + testOutputHelper.WriteLine($"Setter1: {x.TargetName},{x.Property.PropertyName} - Setter2: {y.TargetName},{y.Property.PropertyName}"); + return x.TargetName == y.TargetName && x.Property.PropertyName == y.Property.PropertyName; + } + + public int GetHashCode(Setter obj) + { + return HashCode.Combine(obj.TargetName, obj.Property); + } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.UnitTests/CommunityToolkit.Maui.UnitTests.csproj b/src/CommunityToolkit.Maui.UnitTests/CommunityToolkit.Maui.UnitTests.csproj index d0d74d952a..e130eafdb2 100644 --- a/src/CommunityToolkit.Maui.UnitTests/CommunityToolkit.Maui.UnitTests.csproj +++ b/src/CommunityToolkit.Maui.UnitTests/CommunityToolkit.Maui.UnitTests.csproj @@ -1,23 +1,23 @@ - + $(NetVersion) - exe - false true $(BaseIntermediateOutputPath)\GF + + Exe + CommunityToolkit.Maui.UnitTests + + false + true - - - - - + diff --git a/src/CommunityToolkit.Maui.UnitTests/Converters/ByteArrayToImageSourceConverterTests.cs b/src/CommunityToolkit.Maui.UnitTests/Converters/ByteArrayToImageSourceConverterTests.cs index 8b497033f6..e34175cc14 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Converters/ByteArrayToImageSourceConverterTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Converters/ByteArrayToImageSourceConverterTests.cs @@ -23,8 +23,8 @@ public async Task ByteArrayToImageSourceConverter() var convertFromResult = (StreamImageSource)byteArrayToImageSourceConverter.ConvertFrom(byteArray); var convertResult = (StreamImageSource)(((ICommunityToolkitValueConverter)byteArrayToImageSourceConverter).Convert(byteArray, typeof(StreamImageSource), null, CultureInfo.CurrentCulture) ?? throw new InvalidOperationException()); - var convertFromResultStream = await GetStreamFromImageSource(convertFromResult, CancellationToken.None); - var convertResultStream = await GetStreamFromImageSource(convertResult, CancellationToken.None); + var convertFromResultStream = await GetStreamFromImageSource(convertFromResult, TestContext.Current.CancellationToken); + var convertResultStream = await GetStreamFromImageSource(convertResult, TestContext.Current.CancellationToken); Assert.True(StreamEquals(convertFromResultStream, new MemoryStream(byteArray))); Assert.True(StreamEquals(convertResultStream, new MemoryStream(byteArray))); diff --git a/src/CommunityToolkit.Maui.UnitTests/Converters/ImageResourceConverterTests.cs b/src/CommunityToolkit.Maui.UnitTests/Converters/ImageResourceConverterTests.cs index 8ba4ae4512..940fd1d6ad 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Converters/ImageResourceConverterTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Converters/ImageResourceConverterTests.cs @@ -1,17 +1,11 @@ using System.Globalization; using CommunityToolkit.Maui.Converters; -using CommunityToolkit.Maui.UnitTests.Mocks; using Xunit; namespace CommunityToolkit.Maui.UnitTests.Converters; public class ImageResourceConverterTests : BaseOneWayConverterTest { - public ImageResourceConverterTests() - { - Application.Current = new MockApplication(ServiceProvider); - } - public static TheoryData NonStringData { get; } = [ (object)3, // primitive type @@ -19,27 +13,20 @@ public ImageResourceConverterTests() new object() // objects ]; - protected override void Dispose(bool isDisposing) - { - Application.Current = null; - - base.Dispose(isDisposing); - } - [Fact(Timeout = (int)TestDuration.Short)] public async Task ImageResourceConverter() { const string resourceToLoad = "CommunityToolkit.Maui.UnitTests.Resources.dotnet-bot.png"; var expectedResource = (StreamImageSource)ImageSource.FromResource(resourceToLoad); - var expectedMemoryStream = await GetStreamFromImageSource(expectedResource, CancellationToken.None); + var expectedMemoryStream = await GetStreamFromImageSource(expectedResource, TestContext.Current.CancellationToken); var imageResourceConverter = new ImageResourceConverter(); var convertResult = (StreamImageSource)(((ICommunityToolkitValueConverter)imageResourceConverter).Convert(resourceToLoad, typeof(ImageSource), null, CultureInfo.CurrentCulture) ?? throw new NullReferenceException()); - var streamResult = await GetStreamFromImageSource(convertResult, CancellationToken.None); + var streamResult = await GetStreamFromImageSource(convertResult, TestContext.Current.CancellationToken); var convertFromResult = (StreamImageSource)imageResourceConverter.ConvertFrom(resourceToLoad, CultureInfo.CurrentCulture); - var streamFromResult = await GetStreamFromImageSource(convertFromResult, CancellationToken.None); + var streamFromResult = await GetStreamFromImageSource(convertFromResult, TestContext.Current.CancellationToken); Assert.True(StreamEquals(expectedMemoryStream, streamResult)); Assert.True(StreamEquals(expectedMemoryStream, streamFromResult)); @@ -56,7 +43,7 @@ public async Task ImageResourceConverter_CancellationTokenExpired() var convertFromResult = (StreamImageSource)imageResourceConverter.ConvertFrom(resourceToLoad, CultureInfo.CurrentCulture); // Ensure CancellationToken has expired - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); await Assert.ThrowsAsync(() => GetStreamFromImageSource(convertFromResult, cts.Token)); } diff --git a/src/CommunityToolkit.Maui.UnitTests/Essentials/AppThemeTests.cs b/src/CommunityToolkit.Maui.UnitTests/Essentials/AppThemeTests.cs index 8f9a31aba8..db139b3431 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Essentials/AppThemeTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Essentials/AppThemeTests.cs @@ -1,34 +1,37 @@ using CommunityToolkit.Maui.Extensions; using CommunityToolkit.Maui.UnitTests.Mocks; +using FluentAssertions; using Xunit; namespace CommunityToolkit.Maui.UnitTests.Essentials; public class AppThemeTests : BaseHandlerTest { - readonly MockAppInfo mockAppInfo; readonly Label label = new(); + readonly Window window; public AppThemeTests() { - const AppTheme initialAppTheme = AppTheme.Light; - AppInfo.SetCurrent(mockAppInfo = new() - { - RequestedTheme = initialAppTheme - }); - ArgumentNullException.ThrowIfNull(Application.Current); - - Application.Current.Windows[0].Page = new ContentPage + var page = new ContentPage() { Content = label }; + window = new Window { - Content = label + Page = page }; + CreateViewHandler(page); + Application.Current.AddWindow(window); SetAppTheme(initialAppTheme, Application.Current); Assert.Equal(initialAppTheme, Application.Current.PlatformAppTheme); } + protected override void Dispose(bool isDisposing) + { + Application.Current?.RemoveWindow(window); + base.Dispose(isDisposing); + } + [Fact] public void AppThemeColorUsesCorrectColorForTheme() { @@ -102,11 +105,11 @@ public void AppThemeResourceUpdatesLabelText() label.SetAppTheme(Label.TextProperty, resource); - Assert.Equal("Light Theme", label.Text); + label.Text.Should().Be("Light Theme"); SetAppTheme(AppTheme.Dark, Application.Current); - Assert.Equal("Dark Theme", label.Text); + label.Text.Should().Be("Dark Theme"); } void SetAppTheme(in AppTheme theme, in IApplication app) diff --git a/src/CommunityToolkit.Maui.UnitTests/Essentials/FileSaverTests.cs b/src/CommunityToolkit.Maui.UnitTests/Essentials/FileSaverTests.cs index 4b2242a33f..2ae91ea8c4 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Essentials/FileSaverTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Essentials/FileSaverTests.cs @@ -20,7 +20,7 @@ public void FileSaverTestsSetDefaultUpdatesInstance() public async Task SaveAsyncFailsOnNet() { FileSaver.SetDefault(new FileSaverImplementation()); - var result = await FileSaver.SaveAsync("fileName", Stream.Null, CancellationToken.None); + var result = await FileSaver.SaveAsync("fileName", Stream.Null, TestContext.Current.CancellationToken); result.Should().NotBeNull(); result.Exception.Should().BeOfType(); result.FilePath.Should().BeNull(); @@ -32,7 +32,7 @@ public async Task SaveAsyncFailsOnNet() public async Task SaveAsyncWithInitialPathFailsOnNet() { FileSaver.SetDefault(new FileSaverImplementation()); - var result = await FileSaver.SaveAsync("initial path", "fileName", Stream.Null, CancellationToken.None); + var result = await FileSaver.SaveAsync("initial path", "fileName", Stream.Null, TestContext.Current.CancellationToken); result.Should().NotBeNull(); result.Exception.Should().BeOfType(); result.FilePath.Should().BeNull(); @@ -44,7 +44,7 @@ public async Task SaveAsyncWithInitialPathFailsOnNet() public async Task SaveAsyncProgressFailsOnNet() { FileSaver.SetDefault(new FileSaverImplementation()); - var result = await FileSaver.SaveAsync("fileName", Stream.Null, new Progress(), CancellationToken.None); + var result = await FileSaver.SaveAsync("fileName", Stream.Null, new Progress(), TestContext.Current.CancellationToken); result.Should().NotBeNull(); result.Exception.Should().BeOfType(); result.FilePath.Should().BeNull(); @@ -56,7 +56,7 @@ public async Task SaveAsyncProgressFailsOnNet() public async Task SaveAsyncProgressWithInitialPathFailsOnNet() { FileSaver.SetDefault(new FileSaverImplementation()); - var result = await FileSaver.SaveAsync("initial path", "fileName", Stream.Null, new Progress(), CancellationToken.None); + var result = await FileSaver.SaveAsync("initial path", "fileName", Stream.Null, new Progress(), TestContext.Current.CancellationToken); result.Should().NotBeNull(); result.Exception.Should().BeOfType(); result.FilePath.Should().BeNull(); diff --git a/src/CommunityToolkit.Maui.UnitTests/Essentials/FolderPickerTests.cs b/src/CommunityToolkit.Maui.UnitTests/Essentials/FolderPickerTests.cs index 2ebbb3305a..d0e57dcfa1 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Essentials/FolderPickerTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Essentials/FolderPickerTests.cs @@ -20,7 +20,7 @@ public void FolderPickerSetDefaultUpdatesInstance() public async Task PickAsyncFailsOnNet() { FolderPicker.SetDefault(new FolderPickerImplementation()); - var result = await FolderPicker.PickAsync(CancellationToken.None); + var result = await FolderPicker.PickAsync(TestContext.Current.CancellationToken); result.Should().NotBeNull(); result.Exception.Should().BeOfType(); result.Folder.Should().BeNull(); @@ -32,7 +32,7 @@ public async Task PickAsyncFailsOnNet() public async Task PickAsyncWithInitialPathFailsOnNet() { FolderPicker.SetDefault(new FolderPickerImplementation()); - var result = await FolderPicker.PickAsync("initial path", CancellationToken.None); + var result = await FolderPicker.PickAsync("initial path", TestContext.Current.CancellationToken); result.Should().NotBeNull(); result.Exception.Should().BeOfType(); result.Folder.Should().BeNull(); diff --git a/src/CommunityToolkit.Maui.UnitTests/Essentials/SpeechToTextTests.cs b/src/CommunityToolkit.Maui.UnitTests/Essentials/SpeechToTextTests.cs index a610eadedc..08133cc88c 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Essentials/SpeechToTextTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Essentials/SpeechToTextTests.cs @@ -21,7 +21,7 @@ public void SpeechToTextTestsSetDefaultUpdatesInstance() public async Task StartListenAsyncFailsOnNet() { SpeechToText.SetDefault(new SpeechToTextImplementation()); - await Assert.ThrowsAsync(() => SpeechToText.StartListenAsync(new SpeechToTextOptions { Culture = CultureInfo.CurrentCulture }, CancellationToken.None)); + await Assert.ThrowsAsync(() => SpeechToText.StartListenAsync(new SpeechToTextOptions { Culture = CultureInfo.CurrentCulture }, TestContext.Current.CancellationToken)); } [Fact(Timeout = (int)TestDuration.Long)] @@ -30,9 +30,9 @@ public async Task StartStopListenAsyncShouldChangeState() SpeechToText.SetDefault(new SpeechToTextImplementationMock(string.Empty, string.Empty)); SpeechToText.Default.StateChanged += OnStateChanged; SpeechToText.Default.CurrentState.Should().Be(SpeechToTextState.Stopped); - await SpeechToText.StartListenAsync(new SpeechToTextOptions { Culture = CultureInfo.CurrentCulture }, CancellationToken.None); + await SpeechToText.StartListenAsync(new SpeechToTextOptions { Culture = CultureInfo.CurrentCulture }, TestContext.Current.CancellationToken); SpeechToText.Default.CurrentState.Should().Be(SpeechToTextState.Listening); - await SpeechToText.StopListenAsync(CancellationToken.None); + await SpeechToText.StopListenAsync(TestContext.Current.CancellationToken); SpeechToText.Default.CurrentState.Should().Be(SpeechToTextState.Stopped); SpeechToText.Default.StateChanged -= OnStateChanged; void OnStateChanged(object? sender, SpeechToTextStateChangedEventArgs args) @@ -51,9 +51,9 @@ public async Task StartStopListenAsyncShouldChangeRecognitionText() SpeechToText.SetDefault(new SpeechToTextImplementationMock(expectedPartialText, expectedFinalText)); SpeechToText.Default.RecognitionResultUpdated += OnRecognitionTextUpdated; SpeechToText.Default.RecognitionResultCompleted += OnRecognitionTextCompleted; - await SpeechToText.StartListenAsync(new SpeechToTextOptions { Culture = CultureInfo.CurrentCulture }, CancellationToken.None); - await Task.Delay(500, CancellationToken.None); - await SpeechToText.StopListenAsync(CancellationToken.None); + await SpeechToText.StartListenAsync(new SpeechToTextOptions { Culture = CultureInfo.CurrentCulture }, TestContext.Current.CancellationToken); + await Task.Delay(500, TestContext.Current.CancellationToken); + await SpeechToText.StopListenAsync(TestContext.Current.CancellationToken); SpeechToText.Default.RecognitionResultUpdated -= OnRecognitionTextUpdated; SpeechToText.Default.RecognitionResultCompleted -= OnRecognitionTextCompleted; currentPartialText.Should().Be(expectedPartialText); @@ -73,14 +73,14 @@ void OnRecognitionTextCompleted(object? sender, SpeechToTextRecognitionResultCom public async Task StopListenAsyncFailsOnNet() { SpeechToText.SetDefault(new SpeechToTextImplementation()); - await Assert.ThrowsAsync(() => SpeechToText.StopListenAsync(CancellationToken.None)); + await Assert.ThrowsAsync(() => SpeechToText.StopListenAsync(TestContext.Current.CancellationToken)); } [Fact(Timeout = (int)TestDuration.Short)] public async Task RequestPermissionsFailsOnNet() { SpeechToText.SetDefault(new SpeechToTextImplementation()); - await Assert.ThrowsAsync(() => SpeechToText.RequestPermissions(CancellationToken.None)); + await Assert.ThrowsAsync(() => SpeechToText.RequestPermissions(TestContext.Current.CancellationToken)); } [Fact] diff --git a/src/CommunityToolkit.Maui.UnitTests/Extensions/BackgroundColorToTests.cs b/src/CommunityToolkit.Maui.UnitTests/Extensions/BackgroundColorToTests.cs index 0b0420ff0f..f0c8200a6e 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Extensions/BackgroundColorToTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Extensions/BackgroundColorToTests.cs @@ -16,7 +16,7 @@ public async Task BackgroundColorTo_VerifyColorChanged() Assert.Equal(originalBackgroundColor, element.BackgroundColor); - var isSuccessful = await element.BackgroundColorTo(updatedBackgroundColor, token: CancellationToken.None); + var isSuccessful = await element.BackgroundColorTo(updatedBackgroundColor, token: TestContext.Current.CancellationToken); Assert.True(isSuccessful); Assert.Equal(updatedBackgroundColor, element.BackgroundColor); @@ -31,9 +31,9 @@ public async Task BackgroundColorTo_CancellationTokenExpired() element.EnableAnimations(); // Ensure CancellationToken has expired - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); - await Assert.ThrowsAsync(() => element.BackgroundColorTo(Colors.Green, token: cts.Token)); + await Assert.ThrowsAsync(() => element.BackgroundColorTo(Colors.Green, token: cts.Token)); } [Fact(Timeout = (int)TestDuration.Short)] @@ -47,7 +47,7 @@ public async Task BackgroundColorTo_CancellationTokenCanceled() // Ensure CancellationToken has expired await cts.CancelAsync(); - await Assert.ThrowsAsync(() => element.BackgroundColorTo(Colors.Green, token: cts.Token)); + await Assert.ThrowsAsync(() => element.BackgroundColorTo(Colors.Green, token: cts.Token)); } [Fact(Timeout = (int)TestDuration.Short)] @@ -58,7 +58,7 @@ public async Task BackgroundColorTo_VerifyColorChangedForDefaultBackgroundColor( VisualElement element = new Label(); element.EnableAnimations(); - var isSuccessful = await element.BackgroundColorTo(updatedBackgroundColor, token: CancellationToken.None); + var isSuccessful = await element.BackgroundColorTo(updatedBackgroundColor, token: TestContext.Current.CancellationToken); Assert.True(isSuccessful); Assert.Equal(updatedBackgroundColor, element.BackgroundColor); @@ -70,7 +70,7 @@ public async Task BackgroundColorTo_DoesNotAllowNullVisualElement() VisualElement? element = null; #pragma warning disable CS8603 // Possible null reference return. - await Assert.ThrowsAsync(() => element?.BackgroundColorTo(Colors.Red, token: CancellationToken.None)); + await Assert.ThrowsAsync(() => element?.BackgroundColorTo(Colors.Red, token: TestContext.Current.CancellationToken)); #pragma warning restore CS8603 // Possible null reference return. } @@ -81,7 +81,7 @@ public async Task BackgroundColorTo_DoesNotAllowNullColor() element.EnableAnimations(); #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. - await Assert.ThrowsAsync(() => element.BackgroundColorTo(null, token: CancellationToken.None)); + await Assert.ThrowsAsync(() => element.BackgroundColorTo(null, token: TestContext.Current.CancellationToken)); #pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.UnitTests/Extensions/TextColorToTests.cs b/src/CommunityToolkit.Maui.UnitTests/Extensions/TextColorToTests.cs index c5ad5ad63d..0822faf702 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Extensions/TextColorToTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Extensions/TextColorToTests.cs @@ -19,7 +19,7 @@ public async Task PublicTextColorTo_VerifyColorChanged() Assert.Equal(originalTextColor, textStyleView.TextColor); - var isSuccessful = await textStyleView.TextColorTo(updatedTextColor, token: CancellationToken.None); + var isSuccessful = await textStyleView.TextColorTo(updatedTextColor, token: TestContext.Current.CancellationToken); Assert.True(isSuccessful); Assert.Equal(updatedTextColor, textStyleView.TextColor); @@ -34,9 +34,9 @@ public async Task TextColorTo_CancellationTokenExpired() label.EnableAnimations(); // Ensure CancellationToken has expired - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); - await Assert.ThrowsAsync(() => label.TextColorTo(Colors.Green, token: cts.Token)); + await Assert.ThrowsAsync(() => label.TextColorTo(Colors.Green, token: cts.Token)); } [Fact(Timeout = (int)TestDuration.Short)] @@ -50,7 +50,7 @@ public async Task TextColorTo_CancellationTokenCanceled() // Ensure CancellationToken has expired await cts.CancelAsync(); - await Assert.ThrowsAsync(() => label.TextColorTo(Colors.Green, token: cts.Token)); + await Assert.ThrowsAsync(() => label.TextColorTo(Colors.Green, token: cts.Token)); } [Fact] @@ -63,7 +63,7 @@ public async Task InternalTextColorTo_VerifyColorChanged() Assert.Equal(originalTextColor, textStyleView.TextColor); - var isSuccessful = await textStyleView.TextColorTo(updatedTextColor, token: CancellationToken.None); + var isSuccessful = await textStyleView.TextColorTo(updatedTextColor, token: TestContext.Current.CancellationToken); Assert.True(isSuccessful); Assert.Equal(updatedTextColor, textStyleView.TextColor); @@ -79,7 +79,7 @@ public async Task LabelTextColorTo_VerifyColorChanged() Assert.Equal(originalTextColor, label.TextColor); - var isSuccessful = await label.TextColorTo(updatedTextColor, token: CancellationToken.None); + var isSuccessful = await label.TextColorTo(updatedTextColor, token: TestContext.Current.CancellationToken); Assert.True(isSuccessful); Assert.Equal(updatedTextColor, label.TextColor); @@ -93,7 +93,7 @@ public async Task LabelTextColorTo_VerifyColorChangedForDefaultBackgroundColor() var label = new Label(); label.EnableAnimations(); - var isSuccessful = await label.TextColorTo(updatedTextColor, token: CancellationToken.None); + var isSuccessful = await label.TextColorTo(updatedTextColor, token: TestContext.Current.CancellationToken); Assert.True(isSuccessful); Assert.Equal(updatedTextColor, label.TextColor); @@ -105,7 +105,7 @@ public async Task LabelTextColorTo_DoesNotAllowNullVisualElement() Label? label = null; #pragma warning disable CS8603 // Possible null reference return. - await Assert.ThrowsAsync(() => label?.TextColorTo(Colors.Red, token: CancellationToken.None)); + await Assert.ThrowsAsync(() => label?.TextColorTo(Colors.Red, token: TestContext.Current.CancellationToken)); #pragma warning restore CS8603 // Possible null reference return. } @@ -116,7 +116,7 @@ public async Task LabelTextColorTo_DoesNotAllowNullColor() label.EnableAnimations(); #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. - await Assert.ThrowsAsync(() => label.TextColorTo(null, token: CancellationToken.None)); + await Assert.ThrowsAsync(() => label.TextColorTo(null, token: TestContext.Current.CancellationToken)); #pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } @@ -145,7 +145,7 @@ public async Task Extensions_For_Generic_Class() Assert.Equal(originalTextColor, textStyleView.TextColor); - var isSuccessful = await textStyleView.TextColorTo(updatedTextColor, token: CancellationToken.None); + var isSuccessful = await textStyleView.TextColorTo(updatedTextColor, token: TestContext.Current.CancellationToken); Assert.True(isSuccessful); Assert.Equal(updatedTextColor, textStyleView.TextColor); @@ -158,7 +158,7 @@ public async Task GenericPickerShouldUseThePickerExtension() genericPicker.EnableAnimations(); Color updatedTextColor = Colors.Yellow; - var isSuccessful = await genericPicker.TextColorTo(updatedTextColor, token: CancellationToken.None); + var isSuccessful = await genericPicker.TextColorTo(updatedTextColor, token: TestContext.Current.CancellationToken); Assert.True(isSuccessful); } @@ -170,7 +170,7 @@ public async Task MoreGenericPickerShouldUseThePickerExtension() genericPicker.EnableAnimations(); Color updatedTextColor = Colors.Yellow; - var isSuccessful = await genericPicker.TextColorTo(updatedTextColor, token: CancellationToken.None); + var isSuccessful = await genericPicker.TextColorTo(updatedTextColor, token: TestContext.Current.CancellationToken); Assert.True(isSuccessful); } @@ -182,7 +182,7 @@ public async Task BrandNewControlShouldHaveHisOwnExtensionMethod() brandNewControl.EnableAnimations(); Color updatedTextColor = Colors.Yellow; - var isSuccessful = await brandNewControl.TextColorTo(updatedTextColor, token: CancellationToken.None); + var isSuccessful = await brandNewControl.TextColorTo(updatedTextColor, token: TestContext.Current.CancellationToken); Assert.True(isSuccessful); } diff --git a/src/CommunityToolkit.Maui.UnitTests/GlobalUsings.cs b/src/CommunityToolkit.Maui.UnitTests/GlobalUsings.cs new file mode 100644 index 0000000000..70de2d7bb1 --- /dev/null +++ b/src/CommunityToolkit.Maui.UnitTests/GlobalUsings.cs @@ -0,0 +1,3 @@ +using Xunit; + +[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/CommunityToolkit.Maui.UnitTests/Layouts/StateContainerTests.cs b/src/CommunityToolkit.Maui.UnitTests/Layouts/StateContainerTests.cs index 45ec08fdb0..eac1bd697c 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Layouts/StateContainerTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Layouts/StateContainerTests.cs @@ -117,9 +117,9 @@ public async Task StateContainer_CancellationTokenExpired() } // Ensure CancellationToken has expired - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); - await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, cts.Token)); + await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, cts.Token)); } [Fact(Timeout = (int)TestDuration.Short)] @@ -136,7 +136,7 @@ public async Task StateContainer_CancellationTokenCanceled() // Ensure CancellationToken has expired await cts.CancelAsync(); - await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, cts.Token)); + await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, cts.Token)); } [Fact(Timeout = (int)TestDuration.Long)] @@ -148,7 +148,7 @@ public async Task StateContainer_DefaultAnimation() child.EnableAnimations(); } - var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, CancellationToken.None); + var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, TestContext.Current.CancellationToken); Assert.False(StateContainer.GetCanStateChange(layout)); await changeStateWithAnimationTask; @@ -176,7 +176,7 @@ public async Task StateContainer_CustomAnimation() Duration = 0.5 }; - var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, beforeStateChangeAnimation, afterStateChangeAnimation, CancellationToken.None); + var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, beforeStateChangeAnimation, afterStateChangeAnimation, TestContext.Current.CancellationToken); Assert.False(StateContainer.GetCanStateChange(layout)); await changeStateWithAnimationTask; @@ -194,7 +194,7 @@ public async Task StateContainer_FuncAnimation() child.EnableAnimations(); } - var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, null, CustomAnimation, CancellationToken.None); + var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, null, CustomAnimation, TestContext.Current.CancellationToken); Assert.False(StateContainer.GetCanStateChange(layout)); @@ -216,7 +216,8 @@ public async Task StateContainer_DefaultAnimation_Timeout() } var cancelledTokenSource = new CancellationTokenSource(TimeSpan.FromMicroseconds(1)); - await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, cancelledTokenSource.Token)); + await Task.Delay(10, TestContext.Current.CancellationToken); + await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, cancelledTokenSource.Token)); } [Fact(Timeout = (int)TestDuration.Long)] @@ -239,7 +240,8 @@ public async Task StateContainer_CustomAnimation_Timeout() }; var cancelledTokenSource = new CancellationTokenSource(TimeSpan.FromMicroseconds(1)); - await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, beforeStateChangeAnimation, afterStateChangeAnimation, cancelledTokenSource.Token)); + await Task.Delay(10, TestContext.Current.CancellationToken); + await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, beforeStateChangeAnimation, afterStateChangeAnimation, cancelledTokenSource.Token)); } [Fact(Timeout = (int)TestDuration.Long)] @@ -252,7 +254,8 @@ public async Task StateContainer_FuncAnimation_Timeout() } var cancelledTokenSource = new CancellationTokenSource(TimeSpan.FromMicroseconds(1)); - await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, null, CustomAnimation, cancelledTokenSource.Token)); + await Task.Delay(10, TestContext.Current.CancellationToken); + await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, null, CustomAnimation, cancelledTokenSource.Token)); static Task CustomAnimation(VisualElement element, CancellationToken token) => element.RotateTo(0.75, 1000).WaitAsync(token); } @@ -266,13 +269,13 @@ public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_ child.EnableAnimations(); } - var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, CancellationToken.None); + var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, TestContext.Current.CancellationToken); Assert.False(StateContainer.GetCanStateChange(layout)); var exception = Assert.Throws(() => StateContainer.SetCurrentState(layout, StateKey.Anything)); - var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, CancellationToken.None)); - var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, CancellationToken.None)); - var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (layout, _) => layout.FadeTo(1), null, CancellationToken.None)); + var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, TestContext.Current.CancellationToken)); + var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, TestContext.Current.CancellationToken)); + var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (element, _) => element.FadeTo(1), null, TestContext.Current.CancellationToken)); await changeStateWithAnimationTask; @@ -298,13 +301,13 @@ public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_ Duration = 1 }; - var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, beforeStateChangeAnimation, null, CancellationToken.None); + var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, beforeStateChangeAnimation, null, TestContext.Current.CancellationToken); Assert.False(StateContainer.GetCanStateChange(layout)); var exception = Assert.Throws(() => StateContainer.SetCurrentState(layout, StateKey.Anything)); - var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, CancellationToken.None)); - var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, CancellationToken.None)); - var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (layout, _) => layout.FadeTo(1), null, CancellationToken.None)); + var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, TestContext.Current.CancellationToken)); + var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, TestContext.Current.CancellationToken)); + var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (element, _) => element.FadeTo(1), null, TestContext.Current.CancellationToken)); await changeStateWithAnimationTask; @@ -330,13 +333,13 @@ public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_ Duration = 1 }; - var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, null, afterStateChangeAnimation, CancellationToken.None); - + var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, null, afterStateChangeAnimation, TestContext.Current.CancellationToken); + Assert.False(StateContainer.GetCanStateChange(layout)); var exception = Assert.Throws(() => StateContainer.SetCurrentState(layout, StateKey.Anything)); - var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, CancellationToken.None)); - var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, CancellationToken.None)); - var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (layout, _) => layout.FadeTo(1), null, CancellationToken.None)); + var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, TestContext.Current.CancellationToken)); + var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, TestContext.Current.CancellationToken)); + var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (element, _) => element.FadeTo(1), null, TestContext.Current.CancellationToken)); await changeStateWithAnimationTask; @@ -367,13 +370,13 @@ public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_ Duration = 1 }; - var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, beforeStateChangeAnimation, afterStateChangeAnimation, CancellationToken.None); + var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, beforeStateChangeAnimation, afterStateChangeAnimation, TestContext.Current.CancellationToken); Assert.False(StateContainer.GetCanStateChange(layout)); var exception = Assert.Throws(() => StateContainer.SetCurrentState(layout, StateKey.Anything)); - var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, CancellationToken.None)); - var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, CancellationToken.None)); - var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (layout, _) => layout.FadeTo(1), null, CancellationToken.None)); + var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, TestContext.Current.CancellationToken)); + var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, TestContext.Current.CancellationToken)); + var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (element, _) => element.FadeTo(1), null, TestContext.Current.CancellationToken)); await changeStateWithAnimationTask; @@ -388,7 +391,7 @@ public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_ [Fact(Timeout = (int)TestDuration.Short)] public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_NullAnimations() { - var exception = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, (Animation?)null, null, CancellationToken.None)); + var exception = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, (Animation?)null, null, TestContext.Current.CancellationToken)); Assert.Equal("Animation required. Parameters beforeStateChange and afterStateChange cannot both be null", exception.Message); Assert.True(StateContainer.GetCanStateChange(layout)); @@ -397,7 +400,7 @@ public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_ [Fact(Timeout = (int)TestDuration.Short)] public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_NullFuncs() { - var exception = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, (Func?)null, null, CancellationToken.None)); + var exception = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, (Func?)null, null, TestContext.Current.CancellationToken)); Assert.Equal("Animation required. Parameters beforeStateChange and afterStateChange cannot both be null", exception.Message); Assert.True(StateContainer.GetCanStateChange(layout)); @@ -412,13 +415,13 @@ public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_ child.EnableAnimations(); } - var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, CustomAnimation, null, CancellationToken.None); + var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, CustomAnimation, null, TestContext.Current.CancellationToken); Assert.False(StateContainer.GetCanStateChange(layout)); var exception = Assert.Throws(() => StateContainer.SetCurrentState(layout, StateKey.Anything)); - var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, CancellationToken.None)); - var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, CancellationToken.None)); - var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (layout, _) => layout.FadeTo(1), null, CancellationToken.None)); + var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, TestContext.Current.CancellationToken)); + var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, TestContext.Current.CancellationToken)); + var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (element, _) => element.FadeTo(1), null, TestContext.Current.CancellationToken)); await changeStateWithAnimationTask; @@ -441,13 +444,13 @@ public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_ child.EnableAnimations(); } - var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, null, CustomAnimation, CancellationToken.None); + var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, null, CustomAnimation, TestContext.Current.CancellationToken); Assert.False(StateContainer.GetCanStateChange(layout)); var exception = Assert.Throws(() => StateContainer.SetCurrentState(layout, StateKey.Anything)); - var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, CancellationToken.None)); - var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, CancellationToken.None)); - var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (layout, _) => layout.FadeTo(1), null, CancellationToken.None)); + var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, TestContext.Current.CancellationToken)); + var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, TestContext.Current.CancellationToken)); + var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (element, _) => element.FadeTo(1), null, TestContext.Current.CancellationToken)); await changeStateWithAnimationTask; @@ -470,13 +473,13 @@ public async Task StateContainer_ChangingStateWhenCanStateChangePropertyIsFalse_ child.EnableAnimations(); } - var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, CustomAnimation, CustomAnimation, CancellationToken.None); + var changeStateWithAnimationTask = StateContainer.ChangeStateWithAnimation(layout, StateKey.Error, CustomAnimation, CustomAnimation, TestContext.Current.CancellationToken); Assert.False(StateContainer.GetCanStateChange(layout)); var exception = Assert.Throws(() => StateContainer.SetCurrentState(layout, StateKey.Anything)); - var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, CancellationToken.None)); - var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, CancellationToken.None)); - var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (layout, _) => layout.FadeTo(1), null, CancellationToken.None)); + var exception2 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, TestContext.Current.CancellationToken)); + var exception3 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, [], null, TestContext.Current.CancellationToken)); + var exception4 = await Assert.ThrowsAsync(() => StateContainer.ChangeStateWithAnimation(layout, StateKey.Anything, (element, _) => element.FadeTo(1), null, TestContext.Current.CancellationToken)); await changeStateWithAnimationTask; @@ -503,10 +506,10 @@ public void StateContainer_ElementNotInheritsLayoutThrowsException() [Fact] public void StateContainer_CreatesControllerWithLayout() { - var controller = StateContainer.GetContainerController(layout); + var containerController = StateContainer.GetContainerController(layout); - Assert.NotNull(controller); - Assert.IsType(controller.GetLayout()); + Assert.NotNull(containerController); + Assert.IsType(containerController.GetLayout()); } [Fact] diff --git a/src/CommunityToolkit.Maui.UnitTests/Mocks/AnimationExtensions.cs b/src/CommunityToolkit.Maui.UnitTests/Mocks/AnimationExtensions.cs index 4a75589df7..c3bd0f041a 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Mocks/AnimationExtensions.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Mocks/AnimationExtensions.cs @@ -1,6 +1,8 @@ -using System.Diagnostics; +using System.Collections.Concurrent; +using System.Diagnostics; using Microsoft.Maui.Animations; using Microsoft.Maui.Handlers; +using Animation = Microsoft.Maui.Animations.Animation; namespace CommunityToolkit.Maui.UnitTests.Mocks; @@ -9,21 +11,19 @@ static class AnimationExtensions public static void EnableAnimations(this IView view) => MockAnimationHandler.Prepare(view); // Inspired by Microsoft.Maui.Controls.Core.UnitTests.AnimationReadyHandler - class MockAnimationHandler : ViewHandler + sealed class MockAnimationHandler : ViewHandler { const int millisecondTickIncrement = 16; - MockAnimationHandler(IAnimationManager animationManager) : base(new PropertyMapper()) + MockAnimationHandler(IAnimationManager animationManager, IDispatcherProvider dispatcherProvider) : base(new PropertyMapper()) { - SetMauiContext(new AnimationEnabledMauiContext(animationManager)); + SetMauiContext(new AnimationEnabledMauiContext(animationManager, dispatcherProvider)); } - MockAnimationHandler() : this(new TestAnimationManager(new AsyncTicker())) + MockAnimationHandler() : this(new TestAnimationManager(new AsyncTicker()), new MockDispatcherProvider()) { } - public IAnimationManager? AnimationManager => ((AnimationEnabledMauiContext?)MauiContext)?.AnimationManager; - public static T Prepare(T view) where T : IView { view.Handler = new MockAnimationHandler(); @@ -33,12 +33,14 @@ public static T Prepare(T view) where T : IView protected override object CreatePlatformView() => new(); - class AnimationEnabledMauiContext(IAnimationManager manager) : IMauiContext, IServiceProvider + class AnimationEnabledMauiContext(IAnimationManager manager, IDispatcherProvider dispatcherProvider) : IMauiContext, IServiceProvider { public IServiceProvider Services => this; public IAnimationManager AnimationManager { get; } = manager; + public IDispatcherProvider DispatcherProvider { get; } = dispatcherProvider; + IMauiHandlersFactory IMauiContext.Handlers => throw new NotSupportedException(); public object GetService(Type serviceType) @@ -49,7 +51,7 @@ public object GetService(Type serviceType) } else if (serviceType == typeof(IDispatcher)) { - return new MockDispatcherProvider().GetForCurrentThread(); + return DispatcherProvider.GetForCurrentThread() ?? throw new NullReferenceException(); } throw new NotSupportedException(); @@ -127,8 +129,8 @@ public void Remove(Microsoft.Maui.Animations.Animation animation) void OnFire() { - var animations = this.animations.ToList(); - animations.ForEach(AnimationTick); + var animationsList = this.animations.ToList(); + animationsList.ForEach(AnimationTick); if (this.animations.Count <= 0) { diff --git a/src/CommunityToolkit.Maui.UnitTests/Mocks/HandlersContextStub.cs b/src/CommunityToolkit.Maui.UnitTests/Mocks/HandlersContextStub.cs index 969bbf8aad..e830bc0a03 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Mocks/HandlersContextStub.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Mocks/HandlersContextStub.cs @@ -1,6 +1,4 @@ -using Microsoft.Maui.Animations; - -namespace CommunityToolkit.Maui.UnitTests.Mocks; +namespace CommunityToolkit.Maui.UnitTests.Mocks; class HandlersContextStub : IMauiContext { @@ -8,12 +6,9 @@ public HandlersContextStub(IServiceProvider services) { Services = services; Handlers = Services.GetRequiredService(); - AnimationManager = services.GetService() ?? throw new NullReferenceException(); } public IServiceProvider Services { get; } public IMauiHandlersFactory Handlers { get; } - - public IAnimationManager AnimationManager { get; } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.UnitTests/Mocks/MockAppInfo.cs b/src/CommunityToolkit.Maui.UnitTests/Mocks/MockAppInfo.cs index 39560638b8..18720392b2 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Mocks/MockAppInfo.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Mocks/MockAppInfo.cs @@ -1,6 +1,6 @@ namespace CommunityToolkit.Maui.UnitTests.Mocks; -class MockAppInfo : IAppInfo +public class MockAppInfo : IAppInfo { public string PackageName { get; set; } = string.Empty; diff --git a/src/CommunityToolkit.Maui.UnitTests/PopupServiceTests.cs b/src/CommunityToolkit.Maui.UnitTests/PopupServiceTests.cs index fe6ae1521b..76d86dac98 100644 --- a/src/CommunityToolkit.Maui.UnitTests/PopupServiceTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/PopupServiceTests.cs @@ -8,16 +8,6 @@ namespace CommunityToolkit.Maui.UnitTests; public class PopupServiceTests : BaseHandlerTest { - public PopupServiceTests() - { - var page = new ContentPage(); - - CreateViewHandler(page); - - Assert.NotNull(Application.Current); - Application.Current.Windows[0].Page = page; - } - [Fact] public async Task ShowPopupAsyncWithNullOnPresentingShouldThrowArgumentNullException() { @@ -25,7 +15,7 @@ public async Task ShowPopupAsyncWithNullOnPresentingShouldThrowArgumentNullExcep #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. await Assert.ThrowsAsync(() => - popupService.ShowPopupAsync(onPresenting: null, CancellationToken.None)); + popupService.ShowPopupAsync(onPresenting: null, TestContext.Current.CancellationToken)); #pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } @@ -37,7 +27,7 @@ public async Task ShowPopupAsync_CancellationTokenExpired() var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)); // Ensure CancellationToken has expired - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); await Assert.ThrowsAsync(() => popupService.ShowPopupAsync(cts.Token)); } @@ -62,7 +52,7 @@ public async Task ShowPopupAsyncShouldValidateProperBindingContext() var popupInstance = ServiceProvider.GetRequiredService(); var popupViewModel = ServiceProvider.GetRequiredService(); - await popupService.ShowPopupAsync(CancellationToken.None); + await popupService.ShowPopupAsync(TestContext.Current.CancellationToken); Assert.Same(popupInstance.BindingContext, popupViewModel); } @@ -81,7 +71,7 @@ public async Task ShowPopupAsyncWithOnPresenting_CancellationTokenExpired() var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)); // Ensure CancellationToken has expired - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); await Assert.ThrowsAsync(() => popupService.ShowPopupAsync(viewModel => viewModel.HasLoaded = true, cts.Token)); } @@ -105,7 +95,7 @@ public async Task ShowPopupAsyncWithOnPresentingShouldBeInvoked() var popupService = ServiceProvider.GetRequiredService(); var popupViewModel = ServiceProvider.GetRequiredService(); - await popupService.ShowPopupAsync(onPresenting: viewModel => viewModel.HasLoaded = true, CancellationToken.None); + await popupService.ShowPopupAsync(onPresenting: viewModel => viewModel.HasLoaded = true, TestContext.Current.CancellationToken); Assert.True(popupViewModel.HasLoaded); } @@ -116,7 +106,7 @@ public async Task ShowPopupAsyncShouldReturnResultOnceClosed() var mockPopup = ServiceProvider.GetRequiredService(); var popupService = ServiceProvider.GetRequiredService(); - var result = await popupService.ShowPopupAsync(CancellationToken.None); + var result = await popupService.ShowPopupAsync(TestContext.Current.CancellationToken); Assert.Same(mockPopup.Result, result); } diff --git a/src/CommunityToolkit.Maui.UnitTests/Views/CameraView/CameraViewTests.cs b/src/CommunityToolkit.Maui.UnitTests/Views/CameraView/CameraViewTests.cs index 3b8c3d3b5f..bc739198ab 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Views/CameraView/CameraViewTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Views/CameraView/CameraViewTests.cs @@ -33,7 +33,7 @@ public async Task ZoomFactor_WithSelectedCamera_IsCoercedToRange() { if (mockCameraProvider.AvailableCameras is null) { - await mockCameraProvider.RefreshAvailableCameras(CancellationToken.None); + await mockCameraProvider.RefreshAvailableCameras(TestContext.Current.CancellationToken); if (mockCameraProvider.AvailableCameras is null) { diff --git a/src/CommunityToolkit.Maui.UnitTests/Views/DrawingView/DrawingLineTests.cs b/src/CommunityToolkit.Maui.UnitTests/Views/DrawingView/DrawingLineTests.cs index b0c6115154..f101b1e93f 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Views/DrawingView/DrawingLineTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Views/DrawingView/DrawingLineTests.cs @@ -75,7 +75,7 @@ public async Task GetImageStream_CancellationTokenExpired() var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)); // Ensure CancellationToken Expired - await Task.Delay(TimeSpan.FromSeconds(1), CancellationToken.None); + await Task.Delay(TimeSpan.FromSeconds(1), TestContext.Current.CancellationToken); await Assert.ThrowsAsync(async () => await drawingLine.GetImageStream(10, 10, Colors.Blue.AsPaint(), cts.Token)); } @@ -94,14 +94,14 @@ public async Task GetImageStream_CancellationTokenCanceled() [Fact(Timeout = (int)TestDuration.Short)] public async Task GetImageStreamReturnsNullStream() { - var stream = await drawingLine.GetImageStream(10, 10, Colors.Blue.AsPaint(), CancellationToken.None); + var stream = await drawingLine.GetImageStream(10, 10, Colors.Blue.AsPaint(), TestContext.Current.CancellationToken); Assert.Equal(Stream.Null, stream); } [Fact(Timeout = (int)TestDuration.Short)] public async Task GetImageStreamStaticReturnsNullStream() { - var stream = await DrawingLine.GetImageStream(Array.Empty(), new Size(10, 10), 5, Colors.Yellow, Colors.Blue.AsPaint(), CancellationToken.None); + var stream = await DrawingLine.GetImageStream(Array.Empty(), new Size(10, 10), 5, Colors.Yellow, Colors.Blue.AsPaint(), TestContext.Current.CancellationToken); Assert.Equal(Stream.Null, stream); } diff --git a/src/CommunityToolkit.Maui.UnitTests/Views/DrawingView/DrawingViewTests.cs b/src/CommunityToolkit.Maui.UnitTests/Views/DrawingView/DrawingViewTests.cs index f3a60d3467..c7bed37611 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Views/DrawingView/DrawingViewTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Views/DrawingView/DrawingViewTests.cs @@ -157,7 +157,7 @@ public async Task GetImageStream_CancellationTokenExpired() var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)); // Ensure CancellationToken Expired - await Task.Delay(100, CancellationToken.None); + await Task.Delay(100, TestContext.Current.CancellationToken); await Assert.ThrowsAsync(async () => await DrawingView.GetImageStream([new DrawingLine()], Size.Zero, Colors.Blue, cts.Token)); } @@ -180,7 +180,7 @@ public async Task GetImageStreamReturnsNullStream() { var drawingView = new DrawingView(); - var stream = await drawingView.GetImageStream(10, 10, CancellationToken.None); + var stream = await drawingView.GetImageStream(10, 10, TestContext.Current.CancellationToken); stream.Should().BeSameAs(Stream.Null); } @@ -189,7 +189,7 @@ public async Task GetImageStreamStaticReturnsNullStream() { var stream = await DrawingView.GetImageStream([ new DrawingLine() - ], Size.Zero, Colors.Blue, CancellationToken.None); + ], Size.Zero, Colors.Blue, TestContext.Current.CancellationToken); stream.Should().BeSameAs(Stream.Null); } diff --git a/src/CommunityToolkit.Maui.UnitTests/Views/LazyView/LazyViewTests.cs b/src/CommunityToolkit.Maui.UnitTests/Views/LazyView/LazyViewTests.cs index 945a6d907b..3defec7561 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Views/LazyView/LazyViewTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Views/LazyView/LazyViewTests.cs @@ -20,7 +20,7 @@ public async Task LoadViewAsync_CancellationTokenExpired() var lazyView = new LazyView