From 56ea355a3367eb94db58f9d9200d1b5d1cda6470 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sat, 23 Aug 2025 00:34:17 +0100 Subject: [PATCH 01/11] Ensure Splat initialization in builder and tests Added calls to InitializeSplat in ReactiveUIBuilder, builder extension, and RxApp static constructor to ensure Splat services are registered before core ReactiveUI services. Updated test classes to call RxApp.EnsureInitialized in constructors for consistent initialization. Also updated Splat package version in Directory.Packages.props. --- src/Directory.Packages.props | 2 +- src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs | 8 ++++++++ .../ReactiveUIBuilderMauiTests.cs | 1 - src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs | 5 +++++ .../Platforms/winforms/DefaultPropertyBindingTests.cs | 8 ++++++++ .../Platforms/wpf/ReactiveUIBuilderWpfTests.cs | 8 ++++++++ src/ReactiveUI/Builder/ReactiveUIBuilder.cs | 2 ++ src/ReactiveUI/Mixins/ReactiveUIBuilderExtensions.cs | 1 + src/ReactiveUI/RxApp.cs | 2 ++ 9 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index be8926c890..727b9f62b2 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -4,7 +4,7 @@ true - 15.5.3 + 16.0.1 1.13.1.4 2.8.4.1 diff --git a/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs b/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs index a5ca3b26c5..031f49f5f8 100644 --- a/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs +++ b/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs @@ -12,6 +12,14 @@ namespace ReactiveUI.AOTTests; /// public class ViewLocatorAOTMappingTests { + /// + /// Initializes a new instance of the class. + /// + public ViewLocatorAOTMappingTests() + { + RxApp.EnsureInitialized(); + } + /// /// Map/Resolve with contract and default fallback works. /// diff --git a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs index 3c5f3a0908..a92f311f4d 100644 --- a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs +++ b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs @@ -31,7 +31,6 @@ public void WithCoreServices_AndMaui_Should_Register_All_Services() using var locator = new ModernDependencyResolver(); locator.CreateBuilder() - .WithCoreServices() .WithMaui() .Build(); diff --git a/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs b/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs index c74c647efc..1726b6dcf9 100644 --- a/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs +++ b/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs @@ -18,6 +18,11 @@ namespace ReactiveUI.Tests; /// public class ReactiveCommandTest { + public ReactiveCommandTest() + { + RxApp.EnsureInitialized(); + } + /// /// A test that determines whether this instance [can execute changed is available via ICommand]. /// diff --git a/src/ReactiveUI.Tests/Platforms/winforms/DefaultPropertyBindingTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/DefaultPropertyBindingTests.cs index f7d803bd53..3444dcdd37 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/DefaultPropertyBindingTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/DefaultPropertyBindingTests.cs @@ -17,6 +17,14 @@ namespace ReactiveUI.Tests.Winforms; /// public class DefaultPropertyBindingTests { + /// + /// Initializes a new instance of the class. + /// + public DefaultPropertyBindingTests() + { + RxApp.EnsureInitialized(); + } + /// /// Tests Winforms creates observable for property works for textboxes. /// diff --git a/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs b/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs index 119d00c133..8c54bea477 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs @@ -13,6 +13,14 @@ namespace ReactiveUI.Tests.Platforms.Wpf; /// public class ReactiveUIBuilderWpfTests { + /// + /// Initializes a new instance of the class. + /// + public ReactiveUIBuilderWpfTests() + { + RxApp.EnsureInitialized(); + } + /// /// Test that WPF services can be registered using the builder. /// diff --git a/src/ReactiveUI/Builder/ReactiveUIBuilder.cs b/src/ReactiveUI/Builder/ReactiveUIBuilder.cs index 7e9233db65..ee10593605 100644 --- a/src/ReactiveUI/Builder/ReactiveUIBuilder.cs +++ b/src/ReactiveUI/Builder/ReactiveUIBuilder.cs @@ -38,6 +38,8 @@ public override AppBuilder WithCoreServices() return this; } + _resolver.InitializeSplat(); + // Immediately register the core ReactiveUI services into the provided resolver. var registrations = new Registrations(); #pragma warning disable IL2067 // Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations. diff --git a/src/ReactiveUI/Mixins/ReactiveUIBuilderExtensions.cs b/src/ReactiveUI/Mixins/ReactiveUIBuilderExtensions.cs index 96d38b201c..4c64b6d8a8 100644 --- a/src/ReactiveUI/Mixins/ReactiveUIBuilderExtensions.cs +++ b/src/ReactiveUI/Mixins/ReactiveUIBuilderExtensions.cs @@ -26,6 +26,7 @@ public static class ReactiveUIBuilderExtensions public static AppBuilder CreateBuilder(this IMutableDependencyResolver resolver) { resolver.ArgumentNullExceptionThrowIfNull(nameof(resolver)); + resolver.InitializeSplat(); var builder = new Builder.ReactiveUIBuilder(resolver); // Queue core registrations by default so Build() always provides the basics diff --git a/src/ReactiveUI/RxApp.cs b/src/ReactiveUI/RxApp.cs index 2f73954d5f..3d75defd55 100644 --- a/src/ReactiveUI/RxApp.cs +++ b/src/ReactiveUI/RxApp.cs @@ -84,6 +84,7 @@ static RxApp() #if !PORTABLE _taskpoolScheduler = TaskPoolScheduler.Default; #endif + Locator.CurrentMutable.InitializeSplat(); if (!AppBuilder.UsingBuilder) { @@ -94,6 +95,7 @@ static RxApp() return; } + Locator.CurrentMutable.InitializeSplat(); Locator.CurrentMutable.InitializeReactiveUI(PlatformRegistrationManager.NamespacesToRegister); }); } From 44ad6b9adb7131d8348ff1b65efc77ff83e82b71 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 26 Aug 2025 10:52:24 +0100 Subject: [PATCH 02/11] Refactor platform builder extensions to new namespace Moved platform-specific ReactiveUIBuilder extension methods from platform namespaces to ReactiveUI.Builder, consolidating and standardizing their APIs. Updated tests and app code to use the new builder extension methods and removed legacy extension files. Added MultiPlatformReactiveUIBuilderExtensions for multi-platform configuration. This improves AOT compatibility and simplifies platform registration. --- src/Directory.build.props | 2 +- .../AndroidXReactiveUIBuilderExtensions.cs | 54 ++++++ .../ReactiveUIBuilderAndroidXExtensions.cs | 57 ------ .../BlazorReactiveUIBuilderExtensions.cs | 52 +++++ .../ReactiveUIBuilderBlazorExtensions.cs | 57 ------ .../ReactiveUIBuilderMauiTests.cs | 11 +- .../Blazor/ReactiveUIBuilderBlazorTests.cs | 13 +- .../Drawing/ReactiveUIBuilderDrawingTests.cs | 9 +- .../ReactiveUIBuilderWinFormsTests.cs | 13 +- .../Wpf/ReactiveUIBuilderWpfTests.cs | 13 +- .../ReactiveUIBuilderBlockingTests.cs | 8 +- .../ReactiveUIBuilderCoreTests.cs | 50 +++-- src/ReactiveUI.Builder.WpfApp/App.xaml.cs | 11 +- .../ReactiveUIBuilderDrawingExtensions.cs | 27 +++ .../ReactiveUIBuilderDrawingExtensions.cs | 58 ------ .../MauiReactiveUIBuilderExtensions.cs | 55 ++++++ .../ReactiveUIBuilderMauiExtensions.cs | 76 -------- .../ReactiveUIBuilderWinFormsTests.cs | 7 +- .../wpf/ReactiveUIBuilderWpfTests.cs | 13 +- .../WinUIReactiveUIBuilderExtensions.cs | 52 +++++ .../ReactiveUIBuilderWinUIExtensions.cs | 57 ------ .../WinFormsReactiveUIBuilderExtensions.cs | 52 +++++ .../ReactiveUIBuilderWinFormsExtensions.cs | 57 ------ .../Builder/WpfReactiveUIBuilderExtensions.cs | 53 +++++ .../ReactiveUIBuilderWpfExtensions.cs | 57 ------ ...ultiPlatformReactiveUIBuilderExtensions.cs | 55 ++++++ src/ReactiveUI/Builder/ReactiveUIBuilder.cs | 181 ++++++++++-------- src/ReactiveUI/Builder/RxAppBuilder.cs | 170 ++++++++++++++++ .../Interfaces/IWantsToRegisterStuff.cs | 2 +- .../Mixins/ReactiveUIBuilderExtensions.cs | 128 ------------- src/ReactiveUI/Properties/AssemblyInfo.cs | 1 + 31 files changed, 739 insertions(+), 712 deletions(-) create mode 100644 src/ReactiveUI.AndroidX/Builder/AndroidXReactiveUIBuilderExtensions.cs delete mode 100644 src/ReactiveUI.AndroidX/ReactiveUIBuilderAndroidXExtensions.cs create mode 100644 src/ReactiveUI.Blazor/Builder/BlazorReactiveUIBuilderExtensions.cs delete mode 100644 src/ReactiveUI.Blazor/ReactiveUIBuilderBlazorExtensions.cs create mode 100644 src/ReactiveUI.Drawing/Builder/ReactiveUIBuilderDrawingExtensions.cs delete mode 100644 src/ReactiveUI.Drawing/ReactiveUIBuilderDrawingExtensions.cs create mode 100644 src/ReactiveUI.Maui/Builder/MauiReactiveUIBuilderExtensions.cs delete mode 100644 src/ReactiveUI.Maui/ReactiveUIBuilderMauiExtensions.cs create mode 100644 src/ReactiveUI.WinUI/Builder/WinUIReactiveUIBuilderExtensions.cs delete mode 100644 src/ReactiveUI.WinUI/ReactiveUIBuilderWinUIExtensions.cs create mode 100644 src/ReactiveUI.Winforms/Builder/WinFormsReactiveUIBuilderExtensions.cs delete mode 100644 src/ReactiveUI.Winforms/ReactiveUIBuilderWinFormsExtensions.cs create mode 100644 src/ReactiveUI.Wpf/Builder/WpfReactiveUIBuilderExtensions.cs delete mode 100644 src/ReactiveUI.Wpf/ReactiveUIBuilderWpfExtensions.cs create mode 100644 src/ReactiveUI/Builder/MultiPlatformReactiveUIBuilderExtensions.cs create mode 100644 src/ReactiveUI/Builder/RxAppBuilder.cs delete mode 100644 src/ReactiveUI/Mixins/ReactiveUIBuilderExtensions.cs diff --git a/src/Directory.build.props b/src/Directory.build.props index 04c6abd728..197cf3b4c6 100644 --- a/src/Directory.build.props +++ b/src/Directory.build.props @@ -17,7 +17,7 @@ https://github.com/reactiveui/ReactiveUI/releases https://github.com/reactiveui/reactiveui git - $(NoWarn);IDE0060;IDE1006;IDE0130;VSSpell001 + $(NoWarn);IDE0060;IDE1006;IDE0130;VSSpell001;CA1510 true diff --git a/src/ReactiveUI.AndroidX/Builder/AndroidXReactiveUIBuilderExtensions.cs b/src/ReactiveUI.AndroidX/Builder/AndroidXReactiveUIBuilderExtensions.cs new file mode 100644 index 0000000000..4dbcb6aaa8 --- /dev/null +++ b/src/ReactiveUI.AndroidX/Builder/AndroidXReactiveUIBuilderExtensions.cs @@ -0,0 +1,54 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System.Reactive.Concurrency; + +namespace ReactiveUI.Builder; + +/// +/// AndroidX-specific extensions for the ReactiveUI builder. +/// +public static class AndroidXReactiveUIBuilderExtensions +{ + /// + /// Gets the android x main thread scheduler. + /// + /// + /// The android x main thread scheduler. + /// + public static IScheduler AndroidXMainThreadScheduler { get; } = HandlerScheduler.MainThreadScheduler; + + /// + /// Configures ReactiveUI for AndroidX platform with appropriate schedulers. + /// + /// The builder instance. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithAndroidX(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder + .WithMainThreadScheduler(HandlerScheduler.MainThreadScheduler) + .WithPlatformModule(); + } + + /// + /// Withes the android x scheduler. + /// + /// The builder. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithAndroidXScheduler(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithMainThreadScheduler(AndroidXMainThreadScheduler); + } +} diff --git a/src/ReactiveUI.AndroidX/ReactiveUIBuilderAndroidXExtensions.cs b/src/ReactiveUI.AndroidX/ReactiveUIBuilderAndroidXExtensions.cs deleted file mode 100644 index 3ba7c0382b..0000000000 --- a/src/ReactiveUI.AndroidX/ReactiveUIBuilderAndroidXExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Splat.Builder; - -namespace ReactiveUI.AndroidX; - -/// -/// AndroidX-specific extensions for ReactiveUIBuilder. -/// -public static class ReactiveUIBuilderAndroidXExtensions -{ - /// - /// Registers AndroidX-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithAndroidX uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithAndroidX uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithAndroidX(this Builder.ReactiveUIBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - return builder.WithPlatformModule(); - } - - /// - /// Registers AndroidX-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithAndroidX uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithAndroidX uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithAndroidX(this AppBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.WithPlatformModule(); - } -} diff --git a/src/ReactiveUI.Blazor/Builder/BlazorReactiveUIBuilderExtensions.cs b/src/ReactiveUI.Blazor/Builder/BlazorReactiveUIBuilderExtensions.cs new file mode 100644 index 0000000000..7e417c9ec8 --- /dev/null +++ b/src/ReactiveUI.Blazor/Builder/BlazorReactiveUIBuilderExtensions.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Builder; + +/// +/// Blazor-specific extensions for the ReactiveUI builder. +/// +public static class BlazorReactiveUIBuilderExtensions +{ + /// + /// Gets the blazor main thread scheduler. + /// + /// + /// The blazor main thread scheduler. + /// + public static IScheduler BlazorMainThreadScheduler { get; } = CurrentThreadScheduler.Instance; + + /// + /// Configures ReactiveUI for Blazor platform with appropriate schedulers. + /// + /// The builder instance. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithBlazor(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder + .WithBlazorScheduler() + .WithPlatformModule(); + } + + /// + /// Withes the blazor scheduler. + /// + /// The builder. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithBlazorScheduler(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithMainThreadScheduler(BlazorMainThreadScheduler); + } +} diff --git a/src/ReactiveUI.Blazor/ReactiveUIBuilderBlazorExtensions.cs b/src/ReactiveUI.Blazor/ReactiveUIBuilderBlazorExtensions.cs deleted file mode 100644 index 36c2bd2699..0000000000 --- a/src/ReactiveUI.Blazor/ReactiveUIBuilderBlazorExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Splat.Builder; - -namespace ReactiveUI.Blazor; - -/// -/// Blazor-specific extensions for ReactiveUIBuilder. -/// -public static class ReactiveUIBuilderBlazorExtensions -{ - /// - /// Registers Blazor-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithBlazor uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithBlazor uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithBlazor(this Builder.ReactiveUIBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - return builder.WithPlatformModule(); - } - - /// - /// Registers Blazor-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithBlazor uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithBlazor uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithBlazor(this AppBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.WithPlatformModule(); - } -} diff --git a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs index a92f311f4d..8d6c375a56 100644 --- a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs +++ b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs @@ -3,9 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Maui; -using Splat.Builder; - namespace ReactiveUI.Builder.Maui.Tests; public class ReactiveUIBuilderMauiTests @@ -13,10 +10,10 @@ public class ReactiveUIBuilderMauiTests [Fact] public void WithMaui_Should_Register_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - locator.CreateBuilder() + locator.CreateReactiveUIBuilder() .WithMaui() .Build(); @@ -27,10 +24,10 @@ public void WithMaui_Should_Register_Services() [Fact] public void WithCoreServices_AndMaui_Should_Register_All_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - locator.CreateBuilder() + locator.CreateReactiveUIBuilder() .WithMaui() .Build(); diff --git a/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs index e78a7286e5..2e9ad4b4a0 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs @@ -3,9 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Blazor; -using Splat.Builder; - namespace ReactiveUI.Builder.Tests.Platforms.Blazor; public class ReactiveUIBuilderBlazorTests @@ -13,9 +10,9 @@ public class ReactiveUIBuilderBlazorTests [Fact] public void WithBlazor_Should_Register_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); builder.WithBlazor().Build(); @@ -29,11 +26,11 @@ public void WithBlazor_Should_Register_Services() [Fact] public void WithCoreServices_AndBlazor_Should_Register_All_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithCoreServices().WithBlazor().Build(); + builder.WithBlazor().Build(); var observableProperty = locator.GetService(); Assert.NotNull(observableProperty); diff --git a/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs index 70cd440bee..5b92ce0605 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs @@ -3,9 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Drawing; -using Splat.Builder; - namespace ReactiveUI.Builder.Tests.Platforms.Drawing; public class ReactiveUIBuilderDrawingTests @@ -13,14 +10,14 @@ public class ReactiveUIBuilderDrawingTests [Fact] public void WithDrawing_Should_Register_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); builder.WithDrawing().Build(); // Drawing registers bitmap loader in non-NETSTANDARD contexts; we can still assert no exception and core services with chaining - locator.CreateBuilder().WithCoreServices().WithDrawing().Build(); + locator.CreateReactiveUIBuilder().WithDrawing().Build(); var bindingConverters = locator.GetServices(); Assert.NotNull(bindingConverters); } diff --git a/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs index dc89d61423..ed9e9eb114 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs @@ -3,9 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Winforms; -using Splat.Builder; - namespace ReactiveUI.Builder.Tests.Platforms.WinForms; public class ReactiveUIBuilderWinFormsTests @@ -13,9 +10,9 @@ public class ReactiveUIBuilderWinFormsTests [Fact] public void WithWinForms_Should_Register_WinForms_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); builder.WithWinForms().Build(); @@ -29,11 +26,11 @@ public void WithWinForms_Should_Register_WinForms_Services() [Fact] public void WithCoreServices_AndWinForms_Should_Register_All_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithCoreServices().WithWinForms().Build(); + builder.WithWinForms().Build(); var observableProperty = locator.GetService(); Assert.NotNull(observableProperty); diff --git a/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs index 093c9bb15a..6606f3fffd 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs @@ -3,9 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Wpf; -using Splat.Builder; - namespace ReactiveUI.Builder.Tests.Platforms.Wpf; public class ReactiveUIBuilderWpfTests @@ -13,9 +10,9 @@ public class ReactiveUIBuilderWpfTests [Fact] public void WithWpf_Should_Register_Wpf_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); builder.WithWpf().Build(); @@ -29,11 +26,11 @@ public void WithWpf_Should_Register_Wpf_Services() [Fact] public void WithCoreServices_AndWpf_Should_Register_All_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithCoreServices().WithWpf().Build(); + builder.WithWpf().Build(); var observableProperty = locator.GetService(); Assert.NotNull(observableProperty); diff --git a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs index 82abbe5687..844173f910 100644 --- a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs +++ b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs @@ -3,8 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using Splat.Builder; - namespace ReactiveUI.Builder.Tests; /// @@ -15,11 +13,11 @@ public class ReactiveUIBuilderBlockingTests [Fact] public void Build_SetsFlag_AndBlocks_InitializeReactiveUI() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); - builder.WithCoreServices().Build(); + var builder = locator.CreateReactiveUIBuilder(); + builder.Build(); locator.InitializeReactiveUI(); diff --git a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs index 149f238bb1..843db8b123 100644 --- a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs +++ b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs @@ -3,8 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using Splat.Builder; - namespace ReactiveUI.Builder.Tests; /// @@ -15,9 +13,9 @@ public class ReactiveUIBuilderCoreTests [Fact] public void CreateBuilder_Should_Return_Builder_Instance() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); Assert.NotNull(builder); Assert.IsType(builder); } @@ -25,10 +23,10 @@ public void CreateBuilder_Should_Return_Builder_Instance() [Fact] public void WithCoreServices_Should_Register_Core_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); - builder.WithCoreServices().Build(); + var builder = locator.CreateReactiveUIBuilder(); + builder.Build(); var observableProperty = locator.GetService(); Assert.NotNull(observableProperty); @@ -40,10 +38,10 @@ public void WithCoreServices_Should_Register_Core_Services() [Fact] public void WithPlatformServices_Should_Register_Platform_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); - builder.WithPlatformServices().Build(); + var builder = locator.CreateReactiveUIBuilder(); + builder.Build(); var services = locator.GetServices(); Assert.NotNull(services); @@ -53,9 +51,9 @@ public void WithPlatformServices_Should_Register_Platform_Services() [Fact] public void WithCustomRegistration_Should_Execute_Custom_Action() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); var customServiceRegistered = false; builder.WithCustomRegistration(r => @@ -72,9 +70,9 @@ public void WithCustomRegistration_Should_Execute_Custom_Action() [Fact] public void Build_Should_Always_Register_Core_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); builder.Build(); @@ -85,18 +83,18 @@ public void Build_Should_Always_Register_Core_Services() [Fact] public void WithCustomRegistration_With_Null_Action_Should_Throw() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); Assert.Throws(() => builder.WithCustomRegistration(null!)); } [Fact] public void WithViewsFromAssembly_Should_Register_Views() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); var assembly = typeof(ReactiveUIBuilderCoreTests).Assembly; builder.WithViewsFromAssembly(assembly).Build(); @@ -106,18 +104,18 @@ public void WithViewsFromAssembly_Should_Register_Views() [Fact] public void WithViewsFromAssembly_With_Null_Assembly_Should_Throw() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); Assert.Throws(() => builder.WithViewsFromAssembly(null!)); } [Fact] public void WithCoreServices_Called_Multiple_Times_Should_Not_Register_Twice() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); builder.WithCoreServices().WithCoreServices().Build(); @@ -129,14 +127,12 @@ public void WithCoreServices_Called_Multiple_Times_Should_Not_Register_Twice() [Fact] public void Builder_Should_Support_Fluent_Chaining() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var locator = new ModernDependencyResolver(); var customServiceRegistered = false; - locator.CreateBuilder() - .WithCoreServices() - .WithPlatformServices() - .WithCustomRegistration(r => + locator.CreateReactiveUIBuilder() + .WithRegistration(r => { r.RegisterConstant("Test", typeof(string)); customServiceRegistered = true; diff --git a/src/ReactiveUI.Builder.WpfApp/App.xaml.cs b/src/ReactiveUI.Builder.WpfApp/App.xaml.cs index 05dd978b4b..247c9ef36d 100644 --- a/src/ReactiveUI.Builder.WpfApp/App.xaml.cs +++ b/src/ReactiveUI.Builder.WpfApp/App.xaml.cs @@ -9,7 +9,6 @@ using System.Reactive.Linq; using System.Windows; using ReactiveUI.Builder.WpfApp.Models; -using ReactiveUI.Wpf; using Splat; namespace ReactiveUI.Builder.WpfApp; @@ -33,11 +32,13 @@ protected override void OnStartup(StartupEventArgs e) base.OnStartup(e); // Initialize ReactiveUI via the Builder only - Locator.CurrentMutable.CreateBuilder() - .WithCoreServices() + RxAppBuilder.CreateReactiveUIBuilder() .WithWpf() - .WithViewsFromAssembly(typeof(App).Assembly) - .WithCustomRegistration(r => + .WithViewsFromAssembly(typeof(App).Assembly) // auto-register all IViewFor in this assembly + ////.RegisterView() + ////.RegisterView() + ////.RegisterView() + .WithRegistration(r => { // Register IScreen as a singleton so all resolutions share the same Router r.RegisterLazySingleton(() => new ViewModels.AppBootstrapper()); diff --git a/src/ReactiveUI.Drawing/Builder/ReactiveUIBuilderDrawingExtensions.cs b/src/ReactiveUI.Drawing/Builder/ReactiveUIBuilderDrawingExtensions.cs new file mode 100644 index 0000000000..36fa5df418 --- /dev/null +++ b/src/ReactiveUI.Drawing/Builder/ReactiveUIBuilderDrawingExtensions.cs @@ -0,0 +1,27 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Builder; + +/// +/// Drawing-specific extensions for ReactiveUIBuilder. +/// +public static class ReactiveUIBuilderDrawingExtensions +{ + /// + /// Registers Drawing-specific services. + /// + /// The builder instance. + /// The builder instance for method chaining. + public static ReactiveUIBuilder WithDrawing(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithPlatformModule(); + } +} diff --git a/src/ReactiveUI.Drawing/ReactiveUIBuilderDrawingExtensions.cs b/src/ReactiveUI.Drawing/ReactiveUIBuilderDrawingExtensions.cs deleted file mode 100644 index 3bbb406ef1..0000000000 --- a/src/ReactiveUI.Drawing/ReactiveUIBuilderDrawingExtensions.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Diagnostics.CodeAnalysis; -using Splat.Builder; - -namespace ReactiveUI.Drawing; - -/// -/// Drawing-specific extensions for ReactiveUIBuilder. -/// -public static class ReactiveUIBuilderDrawingExtensions -{ - /// - /// Registers Drawing-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithDrawing uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithDrawing uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithDrawing(this Builder.ReactiveUIBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - return builder.WithPlatformModule(); - } - - /// - /// Registers Drawing-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithDrawing uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithDrawing uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithDrawing(this AppBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.WithPlatformModule(); - } -} diff --git a/src/ReactiveUI.Maui/Builder/MauiReactiveUIBuilderExtensions.cs b/src/ReactiveUI.Maui/Builder/MauiReactiveUIBuilderExtensions.cs new file mode 100644 index 0000000000..7db88f5631 --- /dev/null +++ b/src/ReactiveUI.Maui/Builder/MauiReactiveUIBuilderExtensions.cs @@ -0,0 +1,55 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Microsoft.Maui.Dispatching; + +namespace ReactiveUI.Builder; + +/// +/// MAUI-specific extensions for the ReactiveUI builder. +/// +public static class MauiReactiveUIBuilderExtensions +{ + /// + /// Gets the maui main thread scheduler. + /// + /// + /// The maui main thread scheduler. + /// + public static IScheduler MauiMainThreadScheduler { get; } = DefaultScheduler.Instance; + + /// + /// Configures ReactiveUI for MAUI platform with appropriate schedulers. + /// + /// The builder instance. + /// The MAUI dispatcher to use for the main thread scheduler. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithMaui(this ReactiveUIBuilder builder, IDispatcher? dispatcher = null) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder + .WithMauiScheduler() + .WithPlatformModule(); + } + + /// + /// Withes the maui scheduler. + /// + /// The builder. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithMauiScheduler(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithMainThreadScheduler(MauiMainThreadScheduler); + } +} diff --git a/src/ReactiveUI.Maui/ReactiveUIBuilderMauiExtensions.cs b/src/ReactiveUI.Maui/ReactiveUIBuilderMauiExtensions.cs deleted file mode 100644 index 284ba6a6ff..0000000000 --- a/src/ReactiveUI.Maui/ReactiveUIBuilderMauiExtensions.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Splat.Builder; - -namespace ReactiveUI.Maui; - -/// -/// MAUI-specific extensions for ReactiveUIBuilder. -/// -public static class ReactiveUIBuilderMauiExtensions -{ - /// - /// Registers MAUI-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithMaui uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithMaui uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithMaui(this Builder.ReactiveUIBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - return builder.WithPlatformModule(); - } - - /// - /// Registers MAUI-specific services (AOT-friendly shortcut for non-builder code). - /// - /// Resolver to register into. - /// The resolver for chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithMaui uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithMaui uses methods that may require unreferenced code")] -#endif - public static IMutableDependencyResolver WithMaui(this IMutableDependencyResolver resolver) - { - resolver.ArgumentNullExceptionThrowIfNull(nameof(resolver)); - - // Use the same module the builder uses to avoid duplication. - var reg = new Registrations(); - reg.Register((f, t) => resolver.RegisterConstant(f(), t)); - return resolver; - } - - /// - /// Registers MAUI-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithMaui uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithMaui uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithMaui(this AppBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.WithPlatformModule(); - } -} diff --git a/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs index d25bd85899..ee3382a83f 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs @@ -3,6 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using ReactiveUI.Builder; using ReactiveUI.Winforms; using Splat.Builder; @@ -23,7 +24,7 @@ public void WithWinForms_Should_Register_WinForms_Services() // Arrange using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); // Act builder.WithWinForms().Build(); @@ -46,10 +47,10 @@ public void WithCoreServices_AndWinForms_Should_Register_All_Services() // Arrange using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); // Act - builder.WithCoreServices().WithWinForms().Build(); + builder.WithWinForms().Build(); // Assert // Core services diff --git a/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs b/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs index 8c54bea477..4409b87946 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs @@ -3,8 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Wpf; -using Splat.Builder; +using ReactiveUI.Builder; namespace ReactiveUI.Tests.Platforms.Wpf; @@ -27,11 +26,11 @@ public ReactiveUIBuilderWpfTests() [Fact] public void WithWpf_Should_Register_Wpf_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); // Arrange using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); // Act builder.WithWpf().Build(); @@ -50,14 +49,14 @@ public void WithWpf_Should_Register_Wpf_Services() [Fact] public void WithCoreServices_AndWpf_Should_Register_All_Services() { - AppBuilder.ResetBuilderStateForTests(); + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); // Arrange using var locator = new ModernDependencyResolver(); - var builder = locator.CreateBuilder(); + var builder = locator.CreateReactiveUIBuilder(); // Act - builder.WithCoreServices().WithWpf().Build(); + builder.WithWpf().Build(); // Assert // Core services diff --git a/src/ReactiveUI.WinUI/Builder/WinUIReactiveUIBuilderExtensions.cs b/src/ReactiveUI.WinUI/Builder/WinUIReactiveUIBuilderExtensions.cs new file mode 100644 index 0000000000..5b9a306ea1 --- /dev/null +++ b/src/ReactiveUI.WinUI/Builder/WinUIReactiveUIBuilderExtensions.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Builder; + +/// +/// WinUI-specific extensions for the ReactiveUI builder. +/// +public static class WinUIReactiveUIBuilderExtensions +{ + /// + /// Gets the win UI main thread scheduler. + /// + /// + /// The win UI main thread scheduler. + /// + public static IScheduler WinUIMainThreadScheduler { get; } = new WaitForDispatcherScheduler(() => DispatcherQueueScheduler.Current); + + /// + /// Configures ReactiveUI for WinUI platform with appropriate schedulers. + /// + /// The builder instance. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithWinUI(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder + .WithWinUIScheduler() + .WithPlatformModule(); + } + + /// + /// Withes the win UI scheduler. + /// + /// The builder. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithWinUIScheduler(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithMainThreadScheduler(WinUIMainThreadScheduler); + } +} diff --git a/src/ReactiveUI.WinUI/ReactiveUIBuilderWinUIExtensions.cs b/src/ReactiveUI.WinUI/ReactiveUIBuilderWinUIExtensions.cs deleted file mode 100644 index ec7fdb1efa..0000000000 --- a/src/ReactiveUI.WinUI/ReactiveUIBuilderWinUIExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Splat.Builder; - -namespace ReactiveUI.WinUI; - -/// -/// WinUI-specific extensions for ReactiveUIBuilder. -/// -public static class ReactiveUIBuilderWinUIExtensions -{ - /// - /// Registers WinUI-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithWinUI uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithWinUI uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithWinUI(this Builder.ReactiveUIBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - return builder.WithPlatformModule(); - } - - /// - /// Registers WinUI-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithWinUI uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithWinUI uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithWinUI(this AppBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.WithPlatformModule(); - } -} diff --git a/src/ReactiveUI.Winforms/Builder/WinFormsReactiveUIBuilderExtensions.cs b/src/ReactiveUI.Winforms/Builder/WinFormsReactiveUIBuilderExtensions.cs new file mode 100644 index 0000000000..ce675c96f0 --- /dev/null +++ b/src/ReactiveUI.Winforms/Builder/WinFormsReactiveUIBuilderExtensions.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Builder; + +/// +/// WinForms-specific extensions for the ReactiveUI builder. +/// +public static class WinFormsReactiveUIBuilderExtensions +{ + /// + /// Gets the win forms main thread scheduler. + /// + /// + /// The win forms main thread scheduler. + /// + public static IScheduler WinFormsMainThreadScheduler { get; } = new WaitForDispatcherScheduler(() => new SynchronizationContextScheduler(new WindowsFormsSynchronizationContext())); + + /// + /// Configures ReactiveUI for WinForms platform with appropriate schedulers. + /// + /// The builder instance. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithWinForms(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder + .WithMainThreadScheduler(WinFormsMainThreadScheduler) + .WithPlatformModule(); + } + + /// + /// Withes the win UI scheduler. + /// + /// The builder. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithWinFormsScheduler(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithMainThreadScheduler(WinFormsMainThreadScheduler); + } +} diff --git a/src/ReactiveUI.Winforms/ReactiveUIBuilderWinFormsExtensions.cs b/src/ReactiveUI.Winforms/ReactiveUIBuilderWinFormsExtensions.cs deleted file mode 100644 index 3c3fae50f7..0000000000 --- a/src/ReactiveUI.Winforms/ReactiveUIBuilderWinFormsExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Splat.Builder; - -namespace ReactiveUI.Winforms; - -/// -/// WinForms-specific extensions for ReactiveUIBuilder. -/// -public static class ReactiveUIBuilderWinFormsExtensions -{ - /// - /// Registers WinForms-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithWinForms uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithWinForms uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithWinForms(this Builder.ReactiveUIBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - return builder.WithPlatformModule(); - } - - /// - /// Registers WinForms-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithWinForms uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithWinForms uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithWinForms(this AppBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.WithPlatformModule(); - } -} diff --git a/src/ReactiveUI.Wpf/Builder/WpfReactiveUIBuilderExtensions.cs b/src/ReactiveUI.Wpf/Builder/WpfReactiveUIBuilderExtensions.cs new file mode 100644 index 0000000000..1b0dc6142f --- /dev/null +++ b/src/ReactiveUI.Wpf/Builder/WpfReactiveUIBuilderExtensions.cs @@ -0,0 +1,53 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Builder; + +/// +/// WPF-specific extensions for the ReactiveUI builder. +/// +public static class WpfReactiveUIBuilderExtensions +{ + /// + /// Gets the WPF main thread scheduler. + /// + /// + /// The WPF main thread scheduler. + /// + public static IScheduler WpfMainThreadScheduler { get; } = new WaitForDispatcherScheduler(() => DispatcherScheduler.Current); + + /// + /// Configures ReactiveUI for WPF platform with appropriate schedulers. + /// + /// The builder instance. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithWpf(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder + .WithPlatformModule() + .WithPlatformServices() + .WithWpfScheduler(); + } + + /// + /// Withes the WPF scheduler. + /// + /// The builder. + /// The builder instance for chaining. + public static ReactiveUIBuilder WithWpfScheduler(this ReactiveUIBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithMainThreadScheduler(WpfMainThreadScheduler); + } +} diff --git a/src/ReactiveUI.Wpf/ReactiveUIBuilderWpfExtensions.cs b/src/ReactiveUI.Wpf/ReactiveUIBuilderWpfExtensions.cs deleted file mode 100644 index 2388e0294b..0000000000 --- a/src/ReactiveUI.Wpf/ReactiveUIBuilderWpfExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Splat.Builder; - -namespace ReactiveUI.Wpf; - -/// -/// WPF-specific extensions for ReactiveUIBuilder. -/// -public static class ReactiveUIBuilderWpfExtensions -{ - /// - /// Registers WPF-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithWpf uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithWpf uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithWpf(this Builder.ReactiveUIBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - return builder.WithPlatformModule(); - } - - /// - /// Registers WPF-specific services. - /// - /// The builder instance. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithWpf uses methods that require dynamic code generation")] - [RequiresUnreferencedCode("WithWpf uses methods that may require unreferenced code")] -#endif - public static AppBuilder WithWpf(this AppBuilder builder) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.WithPlatformModule(); - } -} diff --git a/src/ReactiveUI/Builder/MultiPlatformReactiveUIBuilderExtensions.cs b/src/ReactiveUI/Builder/MultiPlatformReactiveUIBuilderExtensions.cs new file mode 100644 index 0000000000..c1a2c7940e --- /dev/null +++ b/src/ReactiveUI/Builder/MultiPlatformReactiveUIBuilderExtensions.cs @@ -0,0 +1,55 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Builder; + +/// +/// Extensions for configuring multiple platforms with ReactiveUI. +/// +public static class MultiPlatformReactiveUIBuilderExtensions +{ + /// + /// Configures ReactiveUI for multiple platforms simultaneously. + /// + /// The builder instance. + /// The platform configuration actions. + /// The builder instance for chaining. + public static ReactiveUIBuilder ForPlatforms(this ReactiveUIBuilder builder, params Action[] platformConfigurations) + { + if (platformConfigurations is null) + { + throw new ArgumentNullException(nameof(platformConfigurations)); + } + + foreach (var configurePlatform in platformConfigurations) + { + configurePlatform(builder); + } + + return builder; + } + + /// + /// Configures a custom platform implementation for ReactiveUI. + /// + /// The builder instance. + /// The main thread scheduler for the platform. + /// The platform-specific service registrations. + /// The builder instance for chaining. + public static ReactiveUIBuilder ForCustomPlatform( + this ReactiveUIBuilder builder, + IScheduler mainThreadScheduler, + Action platformServices) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder + .WithMainThreadScheduler(mainThreadScheduler) + .WithRegistrationOnBuild(platformServices); + } +} diff --git a/src/ReactiveUI/Builder/ReactiveUIBuilder.cs b/src/ReactiveUI/Builder/ReactiveUIBuilder.cs index ee10593605..6394c130a0 100644 --- a/src/ReactiveUI/Builder/ReactiveUIBuilder.cs +++ b/src/ReactiveUI/Builder/ReactiveUIBuilder.cs @@ -1,53 +1,84 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using System.Reflection; using Splat.Builder; namespace ReactiveUI.Builder; /// -/// A builder class for configuring ReactiveUI without using reflection. -/// This provides an AOT-compatible alternative to the reflection-based InitializeReactiveUI method. +/// A builder class for configuring ReactiveUI services with AOT compatibility. +/// Extends the Splat AppBuilder to provide ReactiveUI-specific configuration. /// -/// -/// Initializes a new instance of the class. -/// -/// The dependency resolver to configure. -public sealed class ReactiveUIBuilder(IMutableDependencyResolver resolver) : AppBuilder(resolver) +public sealed class ReactiveUIBuilder : AppBuilder { - // Ensure we always register against the resolver provided to the builder, - // not Locator.Current, so tests that read from the local resolver see the services. - private readonly IMutableDependencyResolver _resolver = resolver; - - private bool _coreRegistered; + private readonly IMutableDependencyResolver _resolver; + private IScheduler? _mainThreadScheduler; + private IScheduler? _taskPoolScheduler; private bool _platformRegistered; + private bool _coreRegistered; /// - /// Registers the core ReactiveUI services. + /// Initializes a new instance of the class. /// - /// The builder instance for method chaining. - [SuppressMessage("Trimming", "IL2046:'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides.", Justification = "Does not use reflection")] - [SuppressMessage("AOT", "IL3051:'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides.", Justification = "Does not use reflection")] - public override AppBuilder WithCoreServices() + /// The dependency resolver to configure. + public ReactiveUIBuilder(IMutableDependencyResolver resolver) + : base(resolver) { - if (_coreRegistered) - { - return this; - } + _resolver = resolver ?? throw new ArgumentNullException(nameof(resolver)); _resolver.InitializeSplat(); + } + + /// + /// Configures the main thread scheduler for ReactiveUI. + /// + /// The main thread scheduler to use. + /// The builder instance for chaining. + public ReactiveUIBuilder WithMainThreadScheduler(IScheduler scheduler) + { + _mainThreadScheduler = scheduler; + return this; + } + + /// + /// Configures the task pool scheduler for ReactiveUI. + /// + /// The task pool scheduler to use. + /// The builder instance for chaining. + public ReactiveUIBuilder WithTaskPoolScheduler(IScheduler scheduler) + { + _taskPoolScheduler = scheduler; + return this; + } - // Immediately register the core ReactiveUI services into the provided resolver. - var registrations = new Registrations(); -#pragma warning disable IL2067 // Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations. - registrations.Register((f, t) => _resolver.RegisterConstant(f(), t)); -#pragma warning restore IL2067 // Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations. + /// + /// Adds a custom ReactiveUI registration action. + /// + /// The configuration action. + /// The builder instance for chaining. + public ReactiveUIBuilder WithRegistrationOnBuild(Action configureAction) + { + WithCustomRegistration(configureAction); + return this; + } - _coreRegistered = true; + /// + /// Adds a custom ReactiveUI registration action. + /// + /// The configuration action. + /// The builder instance for chaining. + public ReactiveUIBuilder WithRegistration(Action configureAction) + { + if (configureAction is null) + { + throw new ArgumentNullException(nameof(configureAction)); + } + configureAction(_resolver); return this; } @@ -55,11 +86,7 @@ public override AppBuilder WithCoreServices() /// Registers the platform-specific ReactiveUI services. /// /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithPlatformServices may use reflection and will not work in AOT environments.")] - [RequiresUnreferencedCode("WithPlatformServices may use reflection and will not work in AOT environments.")] -#endif - public AppBuilder WithPlatformServices() + public ReactiveUIBuilder WithPlatformServices() { if (_platformRegistered) { @@ -67,72 +94,50 @@ public AppBuilder WithPlatformServices() } // Immediately register the platform ReactiveUI services into the provided resolver. - var platformRegistrations = new PlatformRegistrations(); -#if NET6_0_OR_GREATER - platformRegistrations.Register((f, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] t) => _resolver.RegisterConstant(f(), t)); -#else - platformRegistrations.Register((f, t) => _resolver.RegisterConstant(f(), t)); -#endif + WithPlatformModule(); _platformRegistered = true; return this; } /// - /// Automatically registers all views that implement IViewFor from the specified assembly. + /// Registers the core ReactiveUI services in an AOT-compatible manner. /// - /// The assembly to scan for views. - /// The builder instance for method chaining. + /// The builder instance for chaining. #if NET6_0_OR_GREATER - [RequiresDynamicCode("The method uses reflection and will not work in AOT environments.")] - [RequiresUnreferencedCode("The method uses reflection and will not work in AOT environments.")] + [RequiresUnreferencedCode("ReactiveUI uses reflection to register some services. Ensure that the necessary types are preserved.")] + [RequiresDynamicCode("ReactiveUI uses reflection to register some services. Ensure that the necessary types are preserved.")] #endif - public AppBuilder WithViewsFromAssembly(Assembly assembly) + public override AppBuilder WithCoreServices() { - assembly.ArgumentNullExceptionThrowIfNull(nameof(assembly)); + if (!_coreRegistered) + { + // Immediately register the core ReactiveUI services into the provided resolver. + WithPlatformModule(); + _coreRegistered = true; + } - // Register views immediately against the builder's resolver - _resolver.RegisterViewsForViewModels(assembly); - return this; - } + // Configure schedulers if specified + ConfigureSchedulers(); - /// - /// Registers a view type for a specific view model using generics and a parameterless constructor. - /// This avoids reflection and is AOT-friendly. - /// - /// The concrete view type. - /// The view model type. - /// Optional contract. - /// The builder instance for method chaining. -#if NET6_0_OR_GREATER - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Generic registration does not use reflection")] - [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Generic registration does not use dynamic code")] -#endif - public AppBuilder RegisterViewForViewModel(string? contract = null) - where TView : class, IViewFor, new() - where TViewModel : class - { - _resolver.Register(() => new TView(), typeof(IViewFor), contract ?? string.Empty); return this; } /// - /// Registers a view type as a lazy singleton for a specific view model using generics. - /// This avoids reflection and is AOT-friendly. + /// Automatically registers all views that implement IViewFor from the specified assembly. /// - /// The concrete view type. - /// The view model type. - /// Optional contract. + /// The assembly to scan for views. /// The builder instance for method chaining. #if NET6_0_OR_GREATER - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Generic registration does not use reflection")] - [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Generic registration does not use dynamic code")] + [RequiresDynamicCode("The method uses reflection and will not work in AOT environments.")] + [RequiresUnreferencedCode("The method uses reflection and will not work in AOT environments.")] #endif - public AppBuilder RegisterSingletonViewForViewModel(string? contract = null) - where TView : class, IViewFor, new() - where TViewModel : class + public ReactiveUIBuilder WithViewsFromAssembly(Assembly assembly) { - _resolver.RegisterLazySingleton(() => new TView(), typeof(IViewFor), contract ?? string.Empty); + assembly.ArgumentNullExceptionThrowIfNull(nameof(assembly)); + + // Register views immediately against the builder's resolver + _resolver.RegisterViewsForViewModels(assembly); return this; } @@ -142,7 +147,7 @@ public AppBuilder RegisterSingletonViewForViewModel(string? c /// The type of the registration module that implements IWantsToRegisterStuff. /// The builder instance for method chaining. [SuppressMessage("Trimming", "IL2111:Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method.", Justification = "Does not use reflection")] - internal AppBuilder WithPlatformModule() + public ReactiveUIBuilder WithPlatformModule() where T : IWantsToRegisterStuff, new() { var registration = new T(); @@ -153,4 +158,22 @@ internal AppBuilder WithPlatformModule() #endif return this; } + +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("ReactiveUI uses reflection to register some services. Ensure that the necessary types are preserved.")] + [RequiresDynamicCode("ReactiveUI uses reflection to register some services. Ensure that the necessary types are preserved.")] +#endif + private void ConfigureSchedulers() => + WithCustomRegistration(_ => + { + if (_mainThreadScheduler != null) + { + RxApp.MainThreadScheduler = _mainThreadScheduler; + } + + if (_taskPoolScheduler != null) + { + RxApp.TaskpoolScheduler = _taskPoolScheduler; + } + }); } diff --git a/src/ReactiveUI/Builder/RxAppBuilder.cs b/src/ReactiveUI/Builder/RxAppBuilder.cs new file mode 100644 index 0000000000..f6c632f4c3 --- /dev/null +++ b/src/ReactiveUI/Builder/RxAppBuilder.cs @@ -0,0 +1,170 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Builder; + +/// +/// Extension methods for configuring ReactiveUI with the Splat builder. +/// +public static class RxAppBuilder +{ + /// + /// Creates a ReactiveUI builder with the Splat Locator instance. + /// + /// The ReactiveUI builder instance. + public static ReactiveUIBuilder CreateReactiveUIBuilder() => + new(AppLocator.CurrentMutable); + + /// + /// Creates a ReactiveUI builder with the specified dependency resolver. + /// + /// The dependency resolver to use. + /// The ReactiveUI builder instance. + public static ReactiveUIBuilder CreateReactiveUIBuilder(this IMutableDependencyResolver resolver) => + new(resolver); + + /// + /// Configures the ReactiveUI message bus. + /// + /// The builder instance. + /// The configuration action. + /// The builder instance for chaining. + public static ReactiveUIBuilder ConfigureMessageBus(this ReactiveUIBuilder builder, Action configure) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithRegistrationOnBuild(resolver => + resolver.Register(() => + { + var messageBus = new MessageBus(); + configure(messageBus); + return messageBus; + })); + } + + /// + /// Configures the ReactiveUI view locator. + /// + /// The builder instance. + /// The configuration action. + /// The builder instance for chaining. + public static ReactiveUIBuilder ConfigureViewLocator(this ReactiveUIBuilder builder, Action configure) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithRegistrationOnBuild(resolver => + resolver.Register(() => + { + var viewLocator = new DefaultViewLocator(); + configure(viewLocator); + return viewLocator; + })); + } + + /// + /// Configures the ReactiveUI suspension driver. + /// + /// The builder instance. + /// The configuration action. + /// The builder instance for chaining. + public static ReactiveUIBuilder ConfigureSuspensionDriver(this ReactiveUIBuilder builder, Action configure) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithRegistrationOnBuild(resolver => + { + var currentDriver = AppLocator.Current.GetService(); + if (currentDriver != null) + { + configure(currentDriver); + } + }); + } + + /// + /// Registers a custom view model with the dependency resolver. + /// + /// The view model type. + /// The builder instance. + /// The builder instance for chaining. + public static ReactiveUIBuilder RegisterViewModel(this ReactiveUIBuilder builder) + where TViewModel : class, IReactiveObject, new() + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithRegistration(resolver => resolver.Register(() => new())); + } + + /// + /// Registers a custom view model with the dependency resolver. + /// + /// The view model type. + /// The builder instance. + /// The builder instance for chaining. +#if NET6_0_OR_GREATER + [RequiresDynamicCode("This method uses 'new()' constraint which may require dynamic code generation.")] + [RequiresUnreferencedCode("This method uses 'new()' constraint which may require dynamic code generation.")] +#endif + public static ReactiveUIBuilder RegisterSingletonViewModel(this ReactiveUIBuilder builder) + where TViewModel : class, IReactiveObject, new() + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithRegistration(resolver => resolver.RegisterLazySingleton(() => new())); + } + + /// + /// Registers a custom view for a specific view model. + /// + /// The view type. + /// The view model type. + /// The builder instance. + /// The builder instance for chaining. + public static ReactiveUIBuilder RegisterView(this ReactiveUIBuilder builder) + where TView : class, IViewFor, new() + where TViewModel : class, IReactiveObject + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithRegistration(resolver => resolver.Register>(() => new TView())); + } + + /// + /// Registers a custom view for a specific view model. + /// + /// The view type. + /// The view model type. + /// The builder instance. + /// The builder instance for chaining. + public static ReactiveUIBuilder RegisterSingletonView(this ReactiveUIBuilder builder) + where TView : class, IViewFor, new() + where TViewModel : class, IReactiveObject + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.WithRegistration(resolver => resolver.RegisterLazySingleton>(() => new TView())); + } +} diff --git a/src/ReactiveUI/Interfaces/IWantsToRegisterStuff.cs b/src/ReactiveUI/Interfaces/IWantsToRegisterStuff.cs index bfa30386f7..62fab3c106 100644 --- a/src/ReactiveUI/Interfaces/IWantsToRegisterStuff.cs +++ b/src/ReactiveUI/Interfaces/IWantsToRegisterStuff.cs @@ -10,7 +10,7 @@ namespace ReactiveUI; /// inside our own ReactiveUI projects. The implemented methods will /// register with Splat their dependencies. /// -internal interface IWantsToRegisterStuff +public interface IWantsToRegisterStuff { /// /// Register platform dependencies inside Splat. diff --git a/src/ReactiveUI/Mixins/ReactiveUIBuilderExtensions.cs b/src/ReactiveUI/Mixins/ReactiveUIBuilderExtensions.cs deleted file mode 100644 index 4c64b6d8a8..0000000000 --- a/src/ReactiveUI/Mixins/ReactiveUIBuilderExtensions.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Reflection; -using Splat.Builder; - -namespace ReactiveUI; - -/// -/// Extension methods for ReactiveUI Builder functionality. -/// -public static class ReactiveUIBuilderExtensions -{ - /// - /// Creates a builder for configuring ReactiveUI without using reflection. - /// This provides an AOT-compatible alternative to the reflection-based InitializeReactiveUI method. - /// - /// The dependency resolver to configure. - /// A ReactiveUIBuilder instance for fluent configuration. - #if NET6_0_OR_GREATER - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Does not access unreferenced members or use reflection")] - [UnconditionalSuppressMessage("AOT", "IL3050:Members annotated with 'RequiresDynamicCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Does not use dynamic code generation")] -#endif - public static AppBuilder CreateBuilder(this IMutableDependencyResolver resolver) - { - resolver.ArgumentNullExceptionThrowIfNull(nameof(resolver)); - resolver.InitializeSplat(); - var builder = new Builder.ReactiveUIBuilder(resolver); - - // Queue core registrations by default so Build() always provides the basics - builder.WithCoreServices(); - return builder; - } - - /// - /// Automatically registers all views that implement IViewFor from the specified assembly. - /// - /// The builder. - /// The assembly to scan for views. - /// - /// The builder instance for method chaining. - /// - /// The builder must be of type ReactiveUIBuilder. - builder. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithViewsFromAssembly scans the provided assembly for IViewFor<> implementations via reflection and type discovery, which requires dynamic code in AOT.")] - [RequiresUnreferencedCode("WithViewsFromAssembly uses reflection-based type discovery; referenced view types may be trimmed.")] -#endif - public static AppBuilder WithViewsFromAssembly(this AppBuilder builder, Assembly assembly) - { - builder.ArgumentNullExceptionThrowIfNull(nameof(builder)); - assembly.ArgumentNullExceptionThrowIfNull(nameof(assembly)); - - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.WithViewsFromAssembly(assembly); - } - - /// - /// Registers the platform-specific ReactiveUI services. - /// - /// The builder. - /// - /// The builder instance for method chaining. - /// - /// The builder must be of type ReactiveUIBuilder. - builder. -#if NET6_0_OR_GREATER - [RequiresDynamicCode("WithPlatformServices performs platform-specific service registration via reflection and type discovery which requires dynamic code in AOT.")] - [RequiresUnreferencedCode("WithPlatformServices uses reflection-based type discovery during registration; referenced platform types may be trimmed.")] -#endif - public static AppBuilder WithPlatformServices(this AppBuilder builder) - { - builder.ArgumentNullExceptionThrowIfNull(nameof(builder)); - - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.WithPlatformServices(); - } - - /// - /// Registers a view for a view model via generics without reflection. - /// - /// The view type. - /// The view model type. - /// The builder. - /// An optional contract. - /// The builder instance for chaining. - public static AppBuilder RegisterViewForViewModel(this AppBuilder builder, string? contract = null) - where TView : class, IViewFor, new() - where TViewModel : class - { - builder.ArgumentNullExceptionThrowIfNull(nameof(builder)); - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.RegisterViewForViewModel(contract); - } - - /// - /// Registers a singleton view for a view model via generics without reflection. - /// - /// The view type. - /// The view model type. - /// The builder. - /// An optional contract. - /// The builder instance for chaining. - public static AppBuilder RegisterSingletonViewForViewModel(this AppBuilder builder, string? contract = null) - where TView : class, IViewFor, new() - where TViewModel : class - { - builder.ArgumentNullExceptionThrowIfNull(nameof(builder)); - if (builder is not Builder.ReactiveUIBuilder reactiveUIBuilder) - { - throw new ArgumentException("The builder must be of type ReactiveUIBuilder.", nameof(builder)); - } - - return reactiveUIBuilder.RegisterSingletonViewForViewModel(contract); - } -} diff --git a/src/ReactiveUI/Properties/AssemblyInfo.cs b/src/ReactiveUI/Properties/AssemblyInfo.cs index e40a9d4082..319fef98a9 100644 --- a/src/ReactiveUI/Properties/AssemblyInfo.cs +++ b/src/ReactiveUI/Properties/AssemblyInfo.cs @@ -17,3 +17,4 @@ [assembly: InternalsVisibleTo("ReactiveUI.AndroidX")] [assembly: InternalsVisibleTo("ReactiveUI.Builder.Tests")] [assembly: InternalsVisibleTo("ReactiveUI.AOT.Tests")] +[assembly: InternalsVisibleTo("ReactiveUI.Avalonia")] From 1ac3e4ea93f40d44af706f4d9de43044fe2ec7fc Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 26 Aug 2025 12:38:33 +0100 Subject: [PATCH 03/11] Update API tests --- ...valTests.ReactiveUI.DotNet8_0.verified.txt | 84 ++++++++++--------- ...valTests.ReactiveUI.DotNet9_0.verified.txt | 84 ++++++++++--------- ...provalTests.ReactiveUI.Net4_7.verified.txt | 58 ++++++++----- ...rovalTests.Winforms.DotNet8_0.verified.txt | 20 ++--- ...rovalTests.Winforms.DotNet9_0.verified.txt | 20 ++--- ...ApprovalTests.Winforms.Net4_7.verified.txt | 16 ++-- .../Platforms/winforms/CommandBindingTests.cs | 6 ++ ...piApprovalTests.Wpf.DotNet8_0.verified.txt | 18 ++-- ...piApprovalTests.Wpf.DotNet9_0.verified.txt | 18 ++-- ...pfApiApprovalTests.Wpf.Net4_7.verified.txt | 14 ++-- 10 files changed, 188 insertions(+), 150 deletions(-) diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.DotNet8_0.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.DotNet8_0.verified.txt index ee59bf6f47..4badcd8c11 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.DotNet8_0.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.DotNet8_0.verified.txt @@ -1,5 +1,6 @@ [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.AOT.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.AndroidX")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Avalonia")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Blazor")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Builder.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Drawing")] @@ -537,6 +538,10 @@ namespace ReactiveUI "e")] ReactiveUI.IViewFor? ResolveView(T? viewModel, string? contract = null); } + public interface IWantsToRegisterStuff + { + void Register(System.Action, System.Type> registerFunction); + } public class IntegerToStringTypeConverter : ReactiveUI.IBindingTypeConverter, Splat.IEnableLogger { public IntegerToStringTypeConverter() { } @@ -826,7 +831,7 @@ namespace ReactiveUI { public static void SetRegistrationNamespaces(params ReactiveUI.RegistrationNamespace[] namespaces) { } } - public class PlatformRegistrations + public class PlatformRegistrations : ReactiveUI.IWantsToRegisterStuff { public PlatformRegistrations() { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Platform registration uses ComponentModelTypeConverter and RxApp which require dy" + @@ -1228,30 +1233,6 @@ namespace ReactiveUI "code")] public System.IDisposable SuppressChangeNotifications() { } } - public static class ReactiveUIBuilderExtensions - { - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("AOT", "IL3050:Members annotated with \'RequiresDynamicCodeAttribute\' require dynamic acce" + - "ss otherwise can break functionality when trimming application code", Justification="Does not use dynamic code generation")] - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="Does not access unreferenced members or use reflection")] - public static Splat.Builder.AppBuilder CreateBuilder(this Splat.IMutableDependencyResolver resolver) { } - public static Splat.Builder.AppBuilder RegisterSingletonViewForViewModel(this Splat.Builder.AppBuilder builder, string? contract = null) - where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } - public static Splat.Builder.AppBuilder RegisterViewForViewModel(this Splat.Builder.AppBuilder builder, string? contract = null) - where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithPlatformServices performs platform-specific service registration via reflecti" + - "on and type discovery which requires dynamic code in AOT.")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithPlatformServices uses reflection-based type discovery during registration; re" + - "ferenced platform types may be trimmed.")] - public static Splat.Builder.AppBuilder WithPlatformServices(this Splat.Builder.AppBuilder builder) { } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithViewsFromAssembly scans the provided assembly for IViewFor<> implementations " + - "via reflection and type discovery, which requires dynamic code in AOT.")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithViewsFromAssembly uses reflection-based type discovery; referenced view types" + - " may be trimmed.")] - public static Splat.Builder.AppBuilder WithViewsFromAssembly(this Splat.Builder.AppBuilder builder, System.Reflection.Assembly assembly) { } - } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Expression rewriting requires dynamic code generation")] [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Expression rewriting may reference members that could be trimmed")] public static class Reflection @@ -1309,7 +1290,7 @@ namespace ReactiveUI Uwp = 10, WinUI = 11, } - public class Registrations + public class Registrations : ReactiveUI.IWantsToRegisterStuff { public Registrations() { } public void Register(System.Action, System.Type> registerFunction) { } @@ -2196,25 +2177,48 @@ namespace ReactiveUI } namespace ReactiveUI.Builder { + public static class MultiPlatformReactiveUIBuilderExtensions + { + public static ReactiveUI.Builder.ReactiveUIBuilder ForCustomPlatform(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Reactive.Concurrency.IScheduler mainThreadScheduler, System.Action platformServices) { } + public static ReactiveUI.Builder.ReactiveUIBuilder ForPlatforms(this ReactiveUI.Builder.ReactiveUIBuilder builder, params System.Action[] platformConfigurations) { } + } public sealed class ReactiveUIBuilder : Splat.Builder.AppBuilder { public ReactiveUIBuilder(Splat.IMutableDependencyResolver resolver) { } - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("AOT", "IL3050", Justification="Generic registration does not use dynamic code")] - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026", Justification="Generic registration does not use reflection")] - public Splat.Builder.AppBuilder RegisterSingletonViewForViewModel(string? contract = null) - where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("AOT", "IL3050", Justification="Generic registration does not use dynamic code")] - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026", Justification="Generic registration does not use reflection")] - public Splat.Builder.AppBuilder RegisterViewForViewModel(string? contract = null) - where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("ReactiveUI uses reflection to register some services. Ensure that the necessary t" + + "ypes are preserved.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("ReactiveUI uses reflection to register some services. Ensure that the necessary t" + + "ypes are preserved.")] public override Splat.Builder.AppBuilder WithCoreServices() { } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithPlatformServices may use reflection and will not work in AOT environments.")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithPlatformServices may use reflection and will not work in AOT environments.")] - public Splat.Builder.AppBuilder WithPlatformServices() { } + public ReactiveUI.Builder.ReactiveUIBuilder WithMainThreadScheduler(System.Reactive.Concurrency.IScheduler scheduler) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithPlatformModule() + where T : ReactiveUI.IWantsToRegisterStuff, new () { } + public ReactiveUI.Builder.ReactiveUIBuilder WithPlatformServices() { } + public ReactiveUI.Builder.ReactiveUIBuilder WithRegistration(System.Action configureAction) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithRegistrationOnBuild(System.Action configureAction) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithTaskPoolScheduler(System.Reactive.Concurrency.IScheduler scheduler) { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The method uses reflection and will not work in AOT environments.")] [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("The method uses reflection and will not work in AOT environments.")] - public Splat.Builder.AppBuilder WithViewsFromAssembly(System.Reflection.Assembly assembly) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithViewsFromAssembly(System.Reflection.Assembly assembly) { } + } + public static class RxAppBuilder + { + public static ReactiveUI.Builder.ReactiveUIBuilder ConfigureMessageBus(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Action configure) { } + public static ReactiveUI.Builder.ReactiveUIBuilder ConfigureSuspensionDriver(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Action configure) { } + public static ReactiveUI.Builder.ReactiveUIBuilder ConfigureViewLocator(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Action configure) { } + public static ReactiveUI.Builder.ReactiveUIBuilder CreateReactiveUIBuilder() { } + public static ReactiveUI.Builder.ReactiveUIBuilder CreateReactiveUIBuilder(this Splat.IMutableDependencyResolver resolver) { } + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterSingletonView(this ReactiveUI.Builder.ReactiveUIBuilder builder) + where TView : class, ReactiveUI.IViewFor, new () + where TViewModel : class, ReactiveUI.IReactiveObject { } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("This method uses \'new()\' constraint which may require dynamic code generation.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("This method uses \'new()\' constraint which may require dynamic code generation.")] + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterSingletonViewModel(this ReactiveUI.Builder.ReactiveUIBuilder builder) + where TViewModel : class, ReactiveUI.IReactiveObject, new () { } + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterView(this ReactiveUI.Builder.ReactiveUIBuilder builder) + where TView : class, ReactiveUI.IViewFor, new () + where TViewModel : class, ReactiveUI.IReactiveObject { } + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterViewModel(this ReactiveUI.Builder.ReactiveUIBuilder builder) + where TViewModel : class, ReactiveUI.IReactiveObject, new () { } } } \ No newline at end of file diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.DotNet9_0.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.DotNet9_0.verified.txt index 88bdcd10b4..5b28b8c733 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.DotNet9_0.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.DotNet9_0.verified.txt @@ -1,5 +1,6 @@ [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.AOT.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.AndroidX")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Avalonia")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Blazor")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Builder.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Drawing")] @@ -537,6 +538,10 @@ namespace ReactiveUI "e")] ReactiveUI.IViewFor? ResolveView(T? viewModel, string? contract = null); } + public interface IWantsToRegisterStuff + { + void Register(System.Action, System.Type> registerFunction); + } public class IntegerToStringTypeConverter : ReactiveUI.IBindingTypeConverter, Splat.IEnableLogger { public IntegerToStringTypeConverter() { } @@ -826,7 +831,7 @@ namespace ReactiveUI { public static void SetRegistrationNamespaces(params ReactiveUI.RegistrationNamespace[] namespaces) { } } - public class PlatformRegistrations + public class PlatformRegistrations : ReactiveUI.IWantsToRegisterStuff { public PlatformRegistrations() { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Platform registration uses ComponentModelTypeConverter and RxApp which require dy" + @@ -1228,30 +1233,6 @@ namespace ReactiveUI "code")] public System.IDisposable SuppressChangeNotifications() { } } - public static class ReactiveUIBuilderExtensions - { - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("AOT", "IL3050:Members annotated with \'RequiresDynamicCodeAttribute\' require dynamic acce" + - "ss otherwise can break functionality when trimming application code", Justification="Does not use dynamic code generation")] - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="Does not access unreferenced members or use reflection")] - public static Splat.Builder.AppBuilder CreateBuilder(this Splat.IMutableDependencyResolver resolver) { } - public static Splat.Builder.AppBuilder RegisterSingletonViewForViewModel(this Splat.Builder.AppBuilder builder, string? contract = null) - where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } - public static Splat.Builder.AppBuilder RegisterViewForViewModel(this Splat.Builder.AppBuilder builder, string? contract = null) - where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithPlatformServices performs platform-specific service registration via reflecti" + - "on and type discovery which requires dynamic code in AOT.")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithPlatformServices uses reflection-based type discovery during registration; re" + - "ferenced platform types may be trimmed.")] - public static Splat.Builder.AppBuilder WithPlatformServices(this Splat.Builder.AppBuilder builder) { } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithViewsFromAssembly scans the provided assembly for IViewFor<> implementations " + - "via reflection and type discovery, which requires dynamic code in AOT.")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithViewsFromAssembly uses reflection-based type discovery; referenced view types" + - " may be trimmed.")] - public static Splat.Builder.AppBuilder WithViewsFromAssembly(this Splat.Builder.AppBuilder builder, System.Reflection.Assembly assembly) { } - } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Expression rewriting requires dynamic code generation")] [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Expression rewriting may reference members that could be trimmed")] public static class Reflection @@ -1309,7 +1290,7 @@ namespace ReactiveUI Uwp = 10, WinUI = 11, } - public class Registrations + public class Registrations : ReactiveUI.IWantsToRegisterStuff { public Registrations() { } public void Register(System.Action, System.Type> registerFunction) { } @@ -2196,25 +2177,48 @@ namespace ReactiveUI } namespace ReactiveUI.Builder { + public static class MultiPlatformReactiveUIBuilderExtensions + { + public static ReactiveUI.Builder.ReactiveUIBuilder ForCustomPlatform(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Reactive.Concurrency.IScheduler mainThreadScheduler, System.Action platformServices) { } + public static ReactiveUI.Builder.ReactiveUIBuilder ForPlatforms(this ReactiveUI.Builder.ReactiveUIBuilder builder, params System.Action[] platformConfigurations) { } + } public sealed class ReactiveUIBuilder : Splat.Builder.AppBuilder { public ReactiveUIBuilder(Splat.IMutableDependencyResolver resolver) { } - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("AOT", "IL3050", Justification="Generic registration does not use dynamic code")] - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026", Justification="Generic registration does not use reflection")] - public Splat.Builder.AppBuilder RegisterSingletonViewForViewModel(string? contract = null) - where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("AOT", "IL3050", Justification="Generic registration does not use dynamic code")] - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026", Justification="Generic registration does not use reflection")] - public Splat.Builder.AppBuilder RegisterViewForViewModel(string? contract = null) - where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("ReactiveUI uses reflection to register some services. Ensure that the necessary t" + + "ypes are preserved.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("ReactiveUI uses reflection to register some services. Ensure that the necessary t" + + "ypes are preserved.")] public override Splat.Builder.AppBuilder WithCoreServices() { } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithPlatformServices may use reflection and will not work in AOT environments.")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithPlatformServices may use reflection and will not work in AOT environments.")] - public Splat.Builder.AppBuilder WithPlatformServices() { } + public ReactiveUI.Builder.ReactiveUIBuilder WithMainThreadScheduler(System.Reactive.Concurrency.IScheduler scheduler) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithPlatformModule() + where T : ReactiveUI.IWantsToRegisterStuff, new () { } + public ReactiveUI.Builder.ReactiveUIBuilder WithPlatformServices() { } + public ReactiveUI.Builder.ReactiveUIBuilder WithRegistration(System.Action configureAction) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithRegistrationOnBuild(System.Action configureAction) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithTaskPoolScheduler(System.Reactive.Concurrency.IScheduler scheduler) { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The method uses reflection and will not work in AOT environments.")] [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("The method uses reflection and will not work in AOT environments.")] - public Splat.Builder.AppBuilder WithViewsFromAssembly(System.Reflection.Assembly assembly) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithViewsFromAssembly(System.Reflection.Assembly assembly) { } + } + public static class RxAppBuilder + { + public static ReactiveUI.Builder.ReactiveUIBuilder ConfigureMessageBus(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Action configure) { } + public static ReactiveUI.Builder.ReactiveUIBuilder ConfigureSuspensionDriver(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Action configure) { } + public static ReactiveUI.Builder.ReactiveUIBuilder ConfigureViewLocator(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Action configure) { } + public static ReactiveUI.Builder.ReactiveUIBuilder CreateReactiveUIBuilder() { } + public static ReactiveUI.Builder.ReactiveUIBuilder CreateReactiveUIBuilder(this Splat.IMutableDependencyResolver resolver) { } + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterSingletonView(this ReactiveUI.Builder.ReactiveUIBuilder builder) + where TView : class, ReactiveUI.IViewFor, new () + where TViewModel : class, ReactiveUI.IReactiveObject { } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("This method uses \'new()\' constraint which may require dynamic code generation.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("This method uses \'new()\' constraint which may require dynamic code generation.")] + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterSingletonViewModel(this ReactiveUI.Builder.ReactiveUIBuilder builder) + where TViewModel : class, ReactiveUI.IReactiveObject, new () { } + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterView(this ReactiveUI.Builder.ReactiveUIBuilder builder) + where TView : class, ReactiveUI.IViewFor, new () + where TViewModel : class, ReactiveUI.IReactiveObject { } + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterViewModel(this ReactiveUI.Builder.ReactiveUIBuilder builder) + where TViewModel : class, ReactiveUI.IReactiveObject, new () { } } } \ No newline at end of file diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.Net4_7.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.Net4_7.verified.txt index 7d614e7d98..787d5875d8 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.Net4_7.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.Net4_7.verified.txt @@ -1,5 +1,6 @@ [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.AOT.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.AndroidX")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Avalonia")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Blazor")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Builder.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ReactiveUI.Drawing")] @@ -405,6 +406,10 @@ namespace ReactiveUI { ReactiveUI.IViewFor? ResolveView(T? viewModel, string? contract = null); } + public interface IWantsToRegisterStuff + { + void Register(System.Action, System.Type> registerFunction); + } public class IntegerToStringTypeConverter : ReactiveUI.IBindingTypeConverter, Splat.IEnableLogger { public IntegerToStringTypeConverter() { } @@ -605,7 +610,7 @@ namespace ReactiveUI { public static void SetRegistrationNamespaces(params ReactiveUI.RegistrationNamespace[] namespaces) { } } - public class PlatformRegistrations + public class PlatformRegistrations : ReactiveUI.IWantsToRegisterStuff { public PlatformRegistrations() { } public void Register(System.Action, System.Type> registerFunction) { } @@ -842,18 +847,6 @@ namespace ReactiveUI public System.IDisposable DelayChangeNotifications() { } public System.IDisposable SuppressChangeNotifications() { } } - public static class ReactiveUIBuilderExtensions - { - public static Splat.Builder.AppBuilder CreateBuilder(this Splat.IMutableDependencyResolver resolver) { } - public static Splat.Builder.AppBuilder RegisterSingletonViewForViewModel(this Splat.Builder.AppBuilder builder, string? contract = null) - where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } - public static Splat.Builder.AppBuilder RegisterViewForViewModel(this Splat.Builder.AppBuilder builder, string? contract = null) - where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } - public static Splat.Builder.AppBuilder WithPlatformServices(this Splat.Builder.AppBuilder builder) { } - public static Splat.Builder.AppBuilder WithViewsFromAssembly(this Splat.Builder.AppBuilder builder, System.Reflection.Assembly assembly) { } - } public static class Reflection { public static string ExpressionToPropertyNames(System.Linq.Expressions.Expression? expression) { } @@ -885,7 +878,7 @@ namespace ReactiveUI Uwp = 10, WinUI = 11, } - public class Registrations + public class Registrations : ReactiveUI.IWantsToRegisterStuff { public Registrations() { } public void Register(System.Action, System.Type> registerFunction) { } @@ -1249,17 +1242,40 @@ namespace ReactiveUI } namespace ReactiveUI.Builder { + public static class MultiPlatformReactiveUIBuilderExtensions + { + public static ReactiveUI.Builder.ReactiveUIBuilder ForCustomPlatform(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Reactive.Concurrency.IScheduler mainThreadScheduler, System.Action platformServices) { } + public static ReactiveUI.Builder.ReactiveUIBuilder ForPlatforms(this ReactiveUI.Builder.ReactiveUIBuilder builder, params System.Action[] platformConfigurations) { } + } public sealed class ReactiveUIBuilder : Splat.Builder.AppBuilder { public ReactiveUIBuilder(Splat.IMutableDependencyResolver resolver) { } - public Splat.Builder.AppBuilder RegisterSingletonViewForViewModel(string? contract = null) + public override Splat.Builder.AppBuilder WithCoreServices() { } + public ReactiveUI.Builder.ReactiveUIBuilder WithMainThreadScheduler(System.Reactive.Concurrency.IScheduler scheduler) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithPlatformModule() + where T : ReactiveUI.IWantsToRegisterStuff, new () { } + public ReactiveUI.Builder.ReactiveUIBuilder WithPlatformServices() { } + public ReactiveUI.Builder.ReactiveUIBuilder WithRegistration(System.Action configureAction) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithRegistrationOnBuild(System.Action configureAction) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithTaskPoolScheduler(System.Reactive.Concurrency.IScheduler scheduler) { } + public ReactiveUI.Builder.ReactiveUIBuilder WithViewsFromAssembly(System.Reflection.Assembly assembly) { } + } + public static class RxAppBuilder + { + public static ReactiveUI.Builder.ReactiveUIBuilder ConfigureMessageBus(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Action configure) { } + public static ReactiveUI.Builder.ReactiveUIBuilder ConfigureSuspensionDriver(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Action configure) { } + public static ReactiveUI.Builder.ReactiveUIBuilder ConfigureViewLocator(this ReactiveUI.Builder.ReactiveUIBuilder builder, System.Action configure) { } + public static ReactiveUI.Builder.ReactiveUIBuilder CreateReactiveUIBuilder() { } + public static ReactiveUI.Builder.ReactiveUIBuilder CreateReactiveUIBuilder(this Splat.IMutableDependencyResolver resolver) { } + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterSingletonView(this ReactiveUI.Builder.ReactiveUIBuilder builder) where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } - public Splat.Builder.AppBuilder RegisterViewForViewModel(string? contract = null) + where TViewModel : class, ReactiveUI.IReactiveObject { } + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterSingletonViewModel(this ReactiveUI.Builder.ReactiveUIBuilder builder) + where TViewModel : class, ReactiveUI.IReactiveObject, new () { } + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterView(this ReactiveUI.Builder.ReactiveUIBuilder builder) where TView : class, ReactiveUI.IViewFor, new () - where TViewModel : class { } - public override Splat.Builder.AppBuilder WithCoreServices() { } - public Splat.Builder.AppBuilder WithPlatformServices() { } - public Splat.Builder.AppBuilder WithViewsFromAssembly(System.Reflection.Assembly assembly) { } + where TViewModel : class, ReactiveUI.IReactiveObject { } + public static ReactiveUI.Builder.ReactiveUIBuilder RegisterViewModel(this ReactiveUI.Builder.ReactiveUIBuilder builder) + where TViewModel : class, ReactiveUI.IReactiveObject, new () { } } } \ No newline at end of file diff --git a/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.DotNet8_0.verified.txt b/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.DotNet8_0.verified.txt index 7558dd8d2e..73e6bba19d 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.DotNet8_0.verified.txt +++ b/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.DotNet8_0.verified.txt @@ -1,6 +1,15 @@ [assembly: System.Runtime.Versioning.SupportedOSPlatform("Windows10.0.17763.0")] [assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName=".NET 8.0")] [assembly: System.Runtime.Versioning.TargetPlatform("Windows10.0.17763.0")] +namespace ReactiveUI.Builder +{ + public static class WinFormsReactiveUIBuilderExtensions + { + public static System.Reactive.Concurrency.IScheduler WinFormsMainThreadScheduler { get; } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWinForms(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWinFormsScheduler(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } + } +} namespace ReactiveUI.Winforms { public class ActivationForViewFetcher : ReactiveUI.IActivationForViewFetcher, Splat.IEnableLogger @@ -44,15 +53,6 @@ namespace ReactiveUI.Winforms public PlatformOperations() { } public string? GetOrientation() { } } - public static class ReactiveUIBuilderWinFormsExtensions - { - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithWinForms uses methods that require dynamic code generation")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithWinForms uses methods that may require unreferenced code")] - public static Splat.Builder.AppBuilder WithWinForms(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithWinForms uses methods that require dynamic code generation")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithWinForms uses methods that may require unreferenced code")] - public static Splat.Builder.AppBuilder WithWinForms(this Splat.Builder.AppBuilder builder) { } - } public class ReactiveUserControlNonGeneric : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor { public ReactiveUserControlNonGeneric() { } @@ -73,7 +73,7 @@ namespace ReactiveUI.Winforms public TViewModel ViewModel { get; set; } protected override void Dispose(bool disposing) { } } - public class Registrations + public class Registrations : ReactiveUI.IWantsToRegisterStuff { public Registrations() { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Register uses methods that require dynamic code generation")] diff --git a/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.DotNet9_0.verified.txt b/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.DotNet9_0.verified.txt index 4ed0cabe25..36e6f94b61 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.DotNet9_0.verified.txt +++ b/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.DotNet9_0.verified.txt @@ -1,6 +1,15 @@ [assembly: System.Runtime.Versioning.SupportedOSPlatform("Windows10.0.17763.0")] [assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v9.0", FrameworkDisplayName=".NET 9.0")] [assembly: System.Runtime.Versioning.TargetPlatform("Windows10.0.17763.0")] +namespace ReactiveUI.Builder +{ + public static class WinFormsReactiveUIBuilderExtensions + { + public static System.Reactive.Concurrency.IScheduler WinFormsMainThreadScheduler { get; } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWinForms(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWinFormsScheduler(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } + } +} namespace ReactiveUI.Winforms { public class ActivationForViewFetcher : ReactiveUI.IActivationForViewFetcher, Splat.IEnableLogger @@ -44,15 +53,6 @@ namespace ReactiveUI.Winforms public PlatformOperations() { } public string? GetOrientation() { } } - public static class ReactiveUIBuilderWinFormsExtensions - { - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithWinForms uses methods that require dynamic code generation")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithWinForms uses methods that may require unreferenced code")] - public static Splat.Builder.AppBuilder WithWinForms(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithWinForms uses methods that require dynamic code generation")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithWinForms uses methods that may require unreferenced code")] - public static Splat.Builder.AppBuilder WithWinForms(this Splat.Builder.AppBuilder builder) { } - } public class ReactiveUserControlNonGeneric : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor { public ReactiveUserControlNonGeneric() { } @@ -73,7 +73,7 @@ namespace ReactiveUI.Winforms public TViewModel ViewModel { get; set; } protected override void Dispose(bool disposing) { } } - public class Registrations + public class Registrations : ReactiveUI.IWantsToRegisterStuff { public Registrations() { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Register uses methods that require dynamic code generation")] diff --git a/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.Net4_7.verified.txt b/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.Net4_7.verified.txt index 84c87d15d7..9ad8265cca 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.Net4_7.verified.txt +++ b/src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.Net4_7.verified.txt @@ -1,4 +1,13 @@ [assembly: System.Runtime.Versioning.TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName=".NET Framework 4.7.2")] +namespace ReactiveUI.Builder +{ + public static class WinFormsReactiveUIBuilderExtensions + { + public static System.Reactive.Concurrency.IScheduler WinFormsMainThreadScheduler { get; } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWinForms(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWinFormsScheduler(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } + } +} namespace ReactiveUI.Winforms { public class ActivationForViewFetcher : ReactiveUI.IActivationForViewFetcher, Splat.IEnableLogger @@ -30,11 +39,6 @@ namespace ReactiveUI.Winforms public PlatformOperations() { } public string? GetOrientation() { } } - public static class ReactiveUIBuilderWinFormsExtensions - { - public static Splat.Builder.AppBuilder WithWinForms(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } - public static Splat.Builder.AppBuilder WithWinForms(this Splat.Builder.AppBuilder builder) { } - } public class ReactiveUserControlNonGeneric : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor { public ReactiveUserControlNonGeneric() { } @@ -51,7 +55,7 @@ namespace ReactiveUI.Winforms public TViewModel ViewModel { get; set; } protected override void Dispose(bool disposing) { } } - public class Registrations + public class Registrations : ReactiveUI.IWantsToRegisterStuff { public Registrations() { } public void Register(System.Action, System.Type> registerFunction) { } diff --git a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs index f5c39b9278..87dd7f4f21 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs @@ -6,6 +6,7 @@ using System.Windows.Forms; using ReactiveUI.Testing; using ReactiveUI.Winforms; +using Splat.Builder; namespace ReactiveUI.Tests.Winforms; @@ -21,6 +22,7 @@ public class CommandBindingTests [Fact] public async Task CommandBinderBindsToButtonAsync() { + AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var fixture = new CreatesWinformsCommandBinding(); var cmd = ReactiveCommand.CreateRunInBackground(_ => { }); @@ -52,6 +54,7 @@ public async Task CommandBinderBindsToButtonAsync() [Fact] public void CommandBinderBindsToCustomControl() { + AppBuilder.ResetBuilderStateForTests(); var fixture = new CreatesWinformsCommandBinding(); var cmd = ReactiveCommand.Create(_ => { }); var input = new CustomClickableControl(); @@ -81,6 +84,7 @@ public void CommandBinderBindsToCustomControl() [Fact] public void CommandBinderBindsToCustomComponent() { + AppBuilder.ResetBuilderStateForTests(); var fixture = new CreatesWinformsCommandBinding(); var cmd = ReactiveCommand.Create(_ => { }); var input = new CustomClickableComponent(); @@ -110,6 +114,7 @@ public void CommandBinderBindsToCustomComponent() [Fact] public void CommandBinderAffectsEnabledState() { + AppBuilder.ResetBuilderStateForTests(); var fixture = new CreatesWinformsCommandBinding(); var canExecute = new Subject(); canExecute.OnNext(true); @@ -133,6 +138,7 @@ public void CommandBinderAffectsEnabledState() [Fact] public void CommandBinderAffectsEnabledStateForComponents() { + AppBuilder.ResetBuilderStateForTests(); var fixture = new CreatesWinformsCommandBinding(); var canExecute = new Subject(); canExecute.OnNext(true); diff --git a/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.DotNet8_0.verified.txt b/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.DotNet8_0.verified.txt index 6e88507060..05e43e887c 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.DotNet8_0.verified.txt +++ b/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.DotNet8_0.verified.txt @@ -158,18 +158,18 @@ namespace ReactiveUI protected virtual void ResolveViewForViewModel(object? viewModel, string? contract) { } } } -namespace ReactiveUI.Wpf +namespace ReactiveUI.Builder { - public static class ReactiveUIBuilderWpfExtensions + public static class WpfReactiveUIBuilderExtensions { - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithWpf uses methods that require dynamic code generation")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithWpf uses methods that may require unreferenced code")] - public static Splat.Builder.AppBuilder WithWpf(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithWpf uses methods that require dynamic code generation")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithWpf uses methods that may require unreferenced code")] - public static Splat.Builder.AppBuilder WithWpf(this Splat.Builder.AppBuilder builder) { } + public static System.Reactive.Concurrency.IScheduler WpfMainThreadScheduler { get; } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWpf(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWpfScheduler(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } } - public class Registrations +} +namespace ReactiveUI.Wpf +{ + public class Registrations : ReactiveUI.IWantsToRegisterStuff { public Registrations() { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Register uses methods that require dynamic code generation")] diff --git a/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.DotNet9_0.verified.txt b/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.DotNet9_0.verified.txt index 2077280b5e..871af41e14 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.DotNet9_0.verified.txt +++ b/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.DotNet9_0.verified.txt @@ -158,18 +158,18 @@ namespace ReactiveUI protected virtual void ResolveViewForViewModel(object? viewModel, string? contract) { } } } -namespace ReactiveUI.Wpf +namespace ReactiveUI.Builder { - public static class ReactiveUIBuilderWpfExtensions + public static class WpfReactiveUIBuilderExtensions { - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithWpf uses methods that require dynamic code generation")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithWpf uses methods that may require unreferenced code")] - public static Splat.Builder.AppBuilder WithWpf(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("WithWpf uses methods that require dynamic code generation")] - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("WithWpf uses methods that may require unreferenced code")] - public static Splat.Builder.AppBuilder WithWpf(this Splat.Builder.AppBuilder builder) { } + public static System.Reactive.Concurrency.IScheduler WpfMainThreadScheduler { get; } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWpf(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWpfScheduler(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } } - public class Registrations +} +namespace ReactiveUI.Wpf +{ + public class Registrations : ReactiveUI.IWantsToRegisterStuff { public Registrations() { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Register uses methods that require dynamic code generation")] diff --git a/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.Net4_7.verified.txt b/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.Net4_7.verified.txt index 4ef51491bf..7583f7bb45 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.Net4_7.verified.txt +++ b/src/ReactiveUI.Tests/Platforms/wpf/API/WpfApiApprovalTests.Wpf.Net4_7.verified.txt @@ -136,14 +136,18 @@ namespace ReactiveUI protected virtual void ResolveViewForViewModel(object? viewModel, string? contract) { } } } -namespace ReactiveUI.Wpf +namespace ReactiveUI.Builder { - public static class ReactiveUIBuilderWpfExtensions + public static class WpfReactiveUIBuilderExtensions { - public static Splat.Builder.AppBuilder WithWpf(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } - public static Splat.Builder.AppBuilder WithWpf(this Splat.Builder.AppBuilder builder) { } + public static System.Reactive.Concurrency.IScheduler WpfMainThreadScheduler { get; } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWpf(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } + public static ReactiveUI.Builder.ReactiveUIBuilder WithWpfScheduler(this ReactiveUI.Builder.ReactiveUIBuilder builder) { } } - public class Registrations +} +namespace ReactiveUI.Wpf +{ + public class Registrations : ReactiveUI.IWantsToRegisterStuff { public Registrations() { } public void Register(System.Action, System.Type> registerFunction) { } From ad9108627d817e4fca713b48bfe76afdb860a883 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 26 Aug 2025 20:21:45 +0100 Subject: [PATCH 04/11] Reset the Builder for tests --- .../Commands/ReactiveCommandTest.cs | 56 +++++++++++++++++++ src/ReactiveUI.Tests/RxAppTest.cs | 1 + 2 files changed, 57 insertions(+) diff --git a/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs b/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs index 1726b6dcf9..6b79b06259 100644 --- a/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs +++ b/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs @@ -29,6 +29,7 @@ public ReactiveCommandTest() [Fact] public void CanExecuteChangedIsAvailableViaICommand() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); ICommand? fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); var canExecuteChanged = new List(); @@ -48,6 +49,7 @@ public void CanExecuteChangedIsAvailableViaICommand() [Fact] public void CanExecuteIsAvailableViaICommand() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); ICommand? fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); @@ -66,6 +68,7 @@ public void CanExecuteIsAvailableViaICommand() [Fact] public void CanExecuteIsBehavioral() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.Create(() => Observables.Unit, outputScheduler: ImmediateScheduler.Instance); fixture.CanExecute.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var canExecute).Subscribe(); @@ -103,6 +106,7 @@ public void CanExecuteIsFalseIfAlreadyExecuting() => [Fact] public void CanExecuteIsFalseIfCallerDictatesAsSuch() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); var fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); fixture.CanExecute.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var canExecute).Subscribe(); @@ -122,6 +126,7 @@ public void CanExecuteIsFalseIfCallerDictatesAsSuch() [Fact] public void CanExecuteIsUnsubscribedAfterCommandDisposal() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); var fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); @@ -138,6 +143,7 @@ public void CanExecuteIsUnsubscribedAfterCommandDisposal() [Fact] public void CanExecuteOnlyTicksDistinctValues() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); var fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); fixture.CanExecute.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var canExecute).Subscribe(); @@ -160,6 +166,7 @@ public void CanExecuteOnlyTicksDistinctValues() [Fact] public void CanExecuteTicksFailuresThroughThrownExceptions() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); var fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); fixture.ThrownExceptions.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var thrownExceptions).Subscribe(); @@ -176,6 +183,7 @@ public void CanExecuteTicksFailuresThroughThrownExceptions() [Fact] public void CreateTaskFacilitatesTPLIntegration() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromTask(() => Task.FromResult(13), outputScheduler: ImmediateScheduler.Instance); fixture.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var results).Subscribe(); @@ -191,6 +199,7 @@ public void CreateTaskFacilitatesTPLIntegration() [Fact] public void CreateTaskFacilitatesTPLIntegrationWithParameter() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromTask(param => Task.FromResult(param + 1), outputScheduler: ImmediateScheduler.Instance); fixture.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var results).Subscribe(); @@ -208,6 +217,7 @@ public void CreateTaskFacilitatesTPLIntegrationWithParameter() [Fact] public void CreateThrowsIfExecutionParameterIsNull() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. #pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. Assert.Throws(() => ReactiveCommand.Create(null)); @@ -228,6 +238,7 @@ public void CreateThrowsIfExecutionParameterIsNull() [Fact] public void CreateRunInBackgroundThrowsIfExecutionParameterIsNull() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. #pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. Assert.Throws(() => ReactiveCommand.CreateRunInBackground(null)); @@ -291,6 +302,7 @@ public void ExecuteCanBeCancelled() => [Fact] public void ExecuteCanTickThroughMultipleResults() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => new[] { 1, 2, 3 }.ToObservable(), outputScheduler: ImmediateScheduler.Instance); fixture.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var results).Subscribe(); @@ -345,6 +357,7 @@ public void ExecuteFacilitatesAnyNumberOfInFlightExecutions() => [Fact] public void ExecuteIsAvailableViaICommand() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; ICommand? fixture = ReactiveCommand.Create( () => @@ -364,6 +377,7 @@ public void ExecuteIsAvailableViaICommand() [Fact] public void ExecutePassesThroughParameter() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var parameters = new List(); var fixture = ReactiveCommand.CreateFromObservable( param => @@ -389,6 +403,7 @@ public void ExecutePassesThroughParameter() [Fact] public void ExecuteReenablesExecutionEvenAfterFailure() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => Observable.Throw(new InvalidOperationException("oops")), outputScheduler: ImmediateScheduler.Instance); fixture.CanExecute.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var canExecute).Subscribe(); fixture.ThrownExceptions.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var thrownExceptions).Subscribe(); @@ -429,6 +444,7 @@ public void ExecuteResultIsDeliveredOnSpecifiedScheduler() => [Fact] public void ExecuteTicksAnyException() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => Observable.Throw(new InvalidOperationException()), outputScheduler: ImmediateScheduler.Instance); fixture.ThrownExceptions.Subscribe(); Exception? exception = null; @@ -443,6 +459,7 @@ public void ExecuteTicksAnyException() [Fact] public void ExecuteTicksAnyLambdaException() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => throw new InvalidOperationException(), outputScheduler: ImmediateScheduler.Instance); fixture.ThrownExceptions.Subscribe(); Exception? exception = null; @@ -457,6 +474,7 @@ public void ExecuteTicksAnyLambdaException() [Fact] public void ExecuteTicksErrorsThroughThrownExceptions() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => Observable.Throw(new InvalidOperationException("oops")), outputScheduler: ImmediateScheduler.Instance); fixture.ThrownExceptions.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var thrownExceptions).Subscribe(); @@ -472,6 +490,7 @@ public void ExecuteTicksErrorsThroughThrownExceptions() [Fact] public void ExecuteTicksLambdaErrorsThroughThrownExceptions() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => throw new InvalidOperationException("oops"), outputScheduler: ImmediateScheduler.Instance); fixture.ThrownExceptions.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var thrownExceptions).Subscribe(); @@ -488,6 +507,7 @@ public void ExecuteTicksLambdaErrorsThroughThrownExceptions() [Fact] public void ExecuteTicksThroughTheResult() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var num = 0; var fixture = ReactiveCommand.CreateFromObservable(() => Observable.Return(num), outputScheduler: ImmediateScheduler.Instance); fixture.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var results).Subscribe(); @@ -511,6 +531,7 @@ public void ExecuteTicksThroughTheResult() [Fact] public void ExecuteViaICommandThrowsIfParameterTypeIsIncorrect() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); ICommand? fixture = ReactiveCommand.Create(_ => { }, outputScheduler: ImmediateScheduler.Instance); var ex = Assert.Throws(() => fixture.Execute("foo")); Assert.Equal("Command requires parameters of type System.Int32, but received parameter of type System.String.", ex.Message); @@ -526,6 +547,7 @@ public void ExecuteViaICommandThrowsIfParameterTypeIsIncorrect() [Fact] public void ExecuteViaICommandWorksWithNullableTypes() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); int? value = null; ICommand? fixture = ReactiveCommand.Create(param => value = param, outputScheduler: ImmediateScheduler.Instance); @@ -542,6 +564,7 @@ public void ExecuteViaICommandWorksWithNullableTypes() [Fact] public void InvokeCommandAgainstICommandInTargetInvokesTheCommand() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; var fixture = new ICommandHolder(); var source = new Subject(); @@ -561,6 +584,7 @@ public void InvokeCommandAgainstICommandInTargetInvokesTheCommand() [Fact] public void InvokeCommandAgainstICommandInTargetPassesTheSpecifiedValueToCanExecuteAndExecute() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = new ICommandHolder(); var source = new Subject(); source.InvokeCommand(fixture, x => x!.TheCommand!); @@ -578,6 +602,7 @@ public void InvokeCommandAgainstICommandInTargetPassesTheSpecifiedValueToCanExec [Fact] public void InvokeCommandAgainstICommandInNullableTargetPassesTheSpecifiedValueToCanExecuteAndExecute() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = new ICommandHolder(); var source = new Subject(); source.InvokeCommand(fixture, x => x.TheCommand); @@ -595,6 +620,7 @@ public void InvokeCommandAgainstICommandInNullableTargetPassesTheSpecifiedValueT [Fact] public void InvokeCommandAgainstICommandInTargetRespectsCanExecute() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = new ICommandHolder(); @@ -616,6 +642,7 @@ public void InvokeCommandAgainstICommandInTargetRespectsCanExecute() [Fact] public void InvokeCommandAgainstICommandInNullableTargetRespectsCanExecute() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = new ICommandHolder(); @@ -637,6 +664,7 @@ public void InvokeCommandAgainstICommandInNullableTargetRespectsCanExecute() [Fact] public void InvokeCommandAgainstICommandInTargetRespectsCanExecuteWindow() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = new ICommandHolder(); @@ -659,6 +687,7 @@ public void InvokeCommandAgainstICommandInTargetRespectsCanExecuteWindow() [Fact] public void InvokeCommandAgainstICommandInTargetSwallowsExceptions() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var count = 0; var fixture = new ICommandHolder(); var command = ReactiveCommand.Create( @@ -685,6 +714,7 @@ public void InvokeCommandAgainstICommandInTargetSwallowsExceptions() [Fact] public void InvokeCommandAgainstICommandInvokesTheCommand() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; ICommand fixture = ReactiveCommand.Create(() => ++executionCount, outputScheduler: ImmediateScheduler.Instance); var source = new Subject(); @@ -703,6 +733,7 @@ public void InvokeCommandAgainstICommandInvokesTheCommand() [Fact] public void InvokeCommandAgainstNullableICommandInvokesTheCommand() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; ICommand? fixture = ReactiveCommand.Create(() => ++executionCount, outputScheduler: ImmediateScheduler.Instance); var source = new Subject(); @@ -721,6 +752,7 @@ public void InvokeCommandAgainstNullableICommandInvokesTheCommand() [Fact] public void InvokeCommandAgainstICommandPassesTheSpecifiedValueToCanExecuteAndExecute() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = new FakeCommand(); var source = new Subject(); source.InvokeCommand(fixture); @@ -736,6 +768,7 @@ public void InvokeCommandAgainstICommandPassesTheSpecifiedValueToCanExecuteAndEx [Fact] public void InvokeCommandAgainstICommandRespectsCanExecute() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); ICommand fixture = ReactiveCommand.Create(() => executed = true, canExecute, ImmediateScheduler.Instance); @@ -756,6 +789,7 @@ public void InvokeCommandAgainstICommandRespectsCanExecute() [Fact] public void InvokeCommandAgainstICommandRespectsCanExecuteWindow() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); ICommand fixture = ReactiveCommand.Create(() => executed = true, canExecute, ImmediateScheduler.Instance); @@ -777,6 +811,7 @@ public void InvokeCommandAgainstICommandRespectsCanExecuteWindow() [Fact] public void InvokeCommandAgainstICommandSwallowsExceptions() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var count = 0; var fixture = ReactiveCommand.Create( () => @@ -801,6 +836,7 @@ public void InvokeCommandAgainstICommandSwallowsExceptions() [Fact] public void InvokeCommandAgainstReactiveCommandInTargetInvokesTheCommand() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; var fixture = new ReactiveCommandHolder(); var source = new Subject(); @@ -820,6 +856,7 @@ public void InvokeCommandAgainstReactiveCommandInTargetInvokesTheCommand() [Fact] public void InvokeCommandAgainstReactiveCommandInTargetPassesTheSpecifiedValueToExecute() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executeReceived = 0; var fixture = new ReactiveCommandHolder(); var source = new Subject(); @@ -836,6 +873,7 @@ public void InvokeCommandAgainstReactiveCommandInTargetPassesTheSpecifiedValueTo [Fact] public void InvokeCommandAgainstReactiveCommandInTargetRespectsCanExecute() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = new ReactiveCommandHolder(); @@ -857,6 +895,7 @@ public void InvokeCommandAgainstReactiveCommandInTargetRespectsCanExecute() [Fact] public void InvokeCommandAgainstReactiveCommandInTargetRespectsCanExecuteWindow() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = new ReactiveCommandHolder(); @@ -879,6 +918,7 @@ public void InvokeCommandAgainstReactiveCommandInTargetRespectsCanExecuteWindow( [Fact] public void InvokeCommandAgainstReactiveCommandInTargetSwallowsExceptions() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var count = 0; var fixture = new ReactiveCommandHolder() { @@ -906,6 +946,7 @@ public void InvokeCommandAgainstReactiveCommandInTargetSwallowsExceptions() [Fact] public void InvokeCommandAgainstReactiveCommandInvokesTheCommand() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; var fixture = ReactiveCommand.Create(() => ++executionCount, outputScheduler: ImmediateScheduler.Instance); var source = new Subject(); @@ -924,6 +965,7 @@ public void InvokeCommandAgainstReactiveCommandInvokesTheCommand() [Fact] public void InvokeCommandAgainstReactiveCommandPassesTheSpecifiedValueToExecute() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executeReceived = 0; var fixture = ReactiveCommand.Create(x => executeReceived = x, outputScheduler: ImmediateScheduler.Instance); var source = new Subject(); @@ -939,6 +981,7 @@ public void InvokeCommandAgainstReactiveCommandPassesTheSpecifiedValueToExecute( [Fact] public void InvokeCommandAgainstReactiveCommandRespectsCanExecute() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = ReactiveCommand.Create(() => executed = true, canExecute, ImmediateScheduler.Instance); @@ -959,6 +1002,7 @@ public void InvokeCommandAgainstReactiveCommandRespectsCanExecute() [Fact] public void InvokeCommandAgainstReactiveCommandRespectsCanExecuteWindow() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = ReactiveCommand.Create(() => executed = true, canExecute, outputScheduler: ImmediateScheduler.Instance); @@ -980,6 +1024,7 @@ public void InvokeCommandAgainstReactiveCommandRespectsCanExecuteWindow() [Fact] public void InvokeCommandAgainstReactiveCommandSwallowsExceptions() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var count = 0; var fixture = ReactiveCommand.Create( () => @@ -1004,6 +1049,7 @@ public void InvokeCommandAgainstReactiveCommandSwallowsExceptions() [Fact] public void InvokeCommandWorksEvenIfTheSourceIsCold() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; var fixture = ReactiveCommand.Create(() => ++executionCount, outputScheduler: ImmediateScheduler.Instance); var source = Observable.Return(Unit.Default); @@ -1018,6 +1064,7 @@ public void InvokeCommandWorksEvenIfTheSourceIsCold() [Fact] public void IsExecutingIsBehavioral() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.Create(() => Observables.Unit, outputScheduler: ImmediateScheduler.Instance); fixture.IsExecuting.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var isExecuting).Subscribe(); @@ -1031,6 +1078,7 @@ public void IsExecutingIsBehavioral() [Fact] public void IsExecutingRemainsTrueAsLongAsExecutionPipelineHasNotCompleted() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var execute = new Subject(); var fixture = ReactiveCommand.CreateFromObservable(() => execute, outputScheduler: ImmediateScheduler.Instance); @@ -1098,6 +1146,7 @@ public void ResultIsTickedThroughSpecifiedScheduler() => [Fact] public void SynchronousCommandExecuteLazily() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; #pragma warning disable IDE0053 // Use expression body for lambda expressions #pragma warning disable RCS1021 // Convert lambda expression body to expression-body. @@ -1145,6 +1194,7 @@ public void SynchronousCommandExecuteLazily() [Fact] public void SynchronousCommandsFailCorrectly() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture1 = ReactiveCommand.Create(() => throw new InvalidOperationException(), outputScheduler: ImmediateScheduler.Instance); var fixture2 = ReactiveCommand.Create(_ => throw new InvalidOperationException(), outputScheduler: ImmediateScheduler.Instance); var fixture3 = ReactiveCommand.Create(() => throw new InvalidOperationException(), outputScheduler: ImmediateScheduler.Instance); @@ -1169,6 +1219,7 @@ public void SynchronousCommandsFailCorrectly() [Fact] public async Task ReactiveCommandCreateFromTaskHandlesTaskExceptionAsync() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var subj = new Subject(); var isExecuting = false; @@ -1214,6 +1265,7 @@ public async Task ReactiveCommandCreateFromTaskHandlesTaskExceptionAsync() [Fact] public async Task ReactiveCommandCreateFromTaskThenCancelSetsIsExecutingFalseOnlyAfterCancellationCompleteAsync() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var statusTrail = new List<(int Position, string Status)>(); var position = 0; @@ -1281,6 +1333,7 @@ public async Task ReactiveCommandCreateFromTaskThenCancelSetsIsExecutingFalseOnl [Fact] public async Task ReactiveCommandExecutesFromInvokeCommand() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var command = ReactiveCommand.Create(async () => await testSequencer.AdvancePhaseAsync("Phase 1")); @@ -1325,6 +1378,7 @@ public void ShouldCallAsyncMethodOnSettingReactiveSetpoint() => [Fact] public async Task ReactiveCommandCreateFromTaskHandlesExecuteCancellation() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var statusTrail = new List<(int Position, string Status)>(); var position = 0; @@ -1429,6 +1483,7 @@ public void ReactiveCommandCreateFromTaskHandlesTaskException() => [Fact] public async Task ReactiveCommandCreateFromTaskHandlesCancellation() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var statusTrail = new List<(int Position, string Status)>(); var position = 0; @@ -1497,6 +1552,7 @@ public async Task ReactiveCommandCreateFromTaskHandlesCancellation() [Fact] public async Task ReactiveCommandCreateFromTaskHandlesCompletion() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var statusTrail = new List<(int Position, string Status)>(); var position = 0; diff --git a/src/ReactiveUI.Tests/RxAppTest.cs b/src/ReactiveUI.Tests/RxAppTest.cs index 3592dc66cb..9977708eae 100644 --- a/src/ReactiveUI.Tests/RxAppTest.cs +++ b/src/ReactiveUI.Tests/RxAppTest.cs @@ -18,6 +18,7 @@ public class RxAppTest [Fact] public void SchedulerShouldBeCurrentThreadInTestRunner() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); Debug.WriteLine(RxApp.MainThreadScheduler.GetType().FullName); Assert.Equal(CurrentThreadScheduler.Instance, RxApp.MainThreadScheduler); } From 5fd6074d1a32cb0131d608a97972654e82ab96c1 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 26 Aug 2025 21:17:19 +0100 Subject: [PATCH 05/11] Update RxAppTest.cs --- src/ReactiveUI.Tests/RxAppTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ReactiveUI.Tests/RxAppTest.cs b/src/ReactiveUI.Tests/RxAppTest.cs index 9977708eae..40a9f030be 100644 --- a/src/ReactiveUI.Tests/RxAppTest.cs +++ b/src/ReactiveUI.Tests/RxAppTest.cs @@ -18,6 +18,7 @@ public class RxAppTest [Fact] public void SchedulerShouldBeCurrentThreadInTestRunner() { + RxApp.MainThreadScheduler = CurrentThreadScheduler.Instance; Splat.Builder.AppBuilder.ResetBuilderStateForTests(); Debug.WriteLine(RxApp.MainThreadScheduler.GetType().FullName); Assert.Equal(CurrentThreadScheduler.Instance, RxApp.MainThreadScheduler); From d29bd6824481110e9dee7450298b8b84220d9dd3 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Wed, 27 Aug 2025 02:24:04 +0100 Subject: [PATCH 06/11] Update parallel testing --- src/Directory.build.props | 2 ++ src/ReactiveUI.AOTTests/TestConfiguration.cs | 8 ++++++++ src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs | 8 ++++++++ src/ReactiveUI.Builder.Tests/TestConfiguration.cs | 8 ++++++++ src/ReactiveUI.LeakTests/TestConfiguration.cs | 8 ++++++++ src/ReactiveUI.Splat.Tests/TestConfiguration.cs | 8 ++++++++ src/ReactiveUI.Testing.Tests/TestConfiguration.cs | 8 ++++++++ src/ReactiveUI.Testing.Tests/xunit.runner.json | 4 +++- src/ReactiveUI.Tests/xunit.runner.json | 4 +++- src/tests.runsettings | 9 +++++++++ 10 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 src/ReactiveUI.AOTTests/TestConfiguration.cs create mode 100644 src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs create mode 100644 src/ReactiveUI.Builder.Tests/TestConfiguration.cs create mode 100644 src/ReactiveUI.LeakTests/TestConfiguration.cs create mode 100644 src/ReactiveUI.Splat.Tests/TestConfiguration.cs create mode 100644 src/ReactiveUI.Testing.Tests/TestConfiguration.cs create mode 100644 src/tests.runsettings diff --git a/src/Directory.build.props b/src/Directory.build.props index 197cf3b4c6..79415949e6 100644 --- a/src/Directory.build.props +++ b/src/Directory.build.props @@ -35,6 +35,8 @@ net462;net472;net8.0-windows10.0.17763.0;net9.0-windows10.0.17763.0;net8.0-windows10.0.19041.0;net9.0-windows10.0.19041.0 net8.0-android;net8.0-ios;net8.0-tvos;net8.0-macos;net8.0-maccatalyst;net9.0-android;net9.0-ios;net9.0-tvos;net9.0-macos;net9.0-maccatalyst netstandard2.0;net8.0;net9.0 + + $(MSBuildThisFileDirectory)tests.runsettings true diff --git a/src/ReactiveUI.AOTTests/TestConfiguration.cs b/src/ReactiveUI.AOTTests/TestConfiguration.cs new file mode 100644 index 0000000000..3d24fd781a --- /dev/null +++ b/src/ReactiveUI.AOTTests/TestConfiguration.cs @@ -0,0 +1,8 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs b/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs new file mode 100644 index 0000000000..3d24fd781a --- /dev/null +++ b/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs @@ -0,0 +1,8 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Builder.Tests/TestConfiguration.cs b/src/ReactiveUI.Builder.Tests/TestConfiguration.cs new file mode 100644 index 0000000000..3d24fd781a --- /dev/null +++ b/src/ReactiveUI.Builder.Tests/TestConfiguration.cs @@ -0,0 +1,8 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.LeakTests/TestConfiguration.cs b/src/ReactiveUI.LeakTests/TestConfiguration.cs new file mode 100644 index 0000000000..3d24fd781a --- /dev/null +++ b/src/ReactiveUI.LeakTests/TestConfiguration.cs @@ -0,0 +1,8 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Splat.Tests/TestConfiguration.cs b/src/ReactiveUI.Splat.Tests/TestConfiguration.cs new file mode 100644 index 0000000000..3d24fd781a --- /dev/null +++ b/src/ReactiveUI.Splat.Tests/TestConfiguration.cs @@ -0,0 +1,8 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Testing.Tests/TestConfiguration.cs b/src/ReactiveUI.Testing.Tests/TestConfiguration.cs new file mode 100644 index 0000000000..3d24fd781a --- /dev/null +++ b/src/ReactiveUI.Testing.Tests/TestConfiguration.cs @@ -0,0 +1,8 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Testing.Tests/xunit.runner.json b/src/ReactiveUI.Testing.Tests/xunit.runner.json index 503b7481f6..d29baba233 100644 --- a/src/ReactiveUI.Testing.Tests/xunit.runner.json +++ b/src/ReactiveUI.Testing.Tests/xunit.runner.json @@ -1,4 +1,6 @@ { "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", - "parallelAlgorithm": "aggressive" + "parallelizeAssembly": false, + "parallelizeTestCollections": false, + "maxParallelThreads": 1 } diff --git a/src/ReactiveUI.Tests/xunit.runner.json b/src/ReactiveUI.Tests/xunit.runner.json index 503b7481f6..d29baba233 100644 --- a/src/ReactiveUI.Tests/xunit.runner.json +++ b/src/ReactiveUI.Tests/xunit.runner.json @@ -1,4 +1,6 @@ { "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", - "parallelAlgorithm": "aggressive" + "parallelizeAssembly": false, + "parallelizeTestCollections": false, + "maxParallelThreads": 1 } diff --git a/src/tests.runsettings b/src/tests.runsettings new file mode 100644 index 0000000000..1fcb7c1ae3 --- /dev/null +++ b/src/tests.runsettings @@ -0,0 +1,9 @@ + + + + + 1 + + true + + From ea4a246e50805684645162421a9eb171a1b59f2d Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Wed, 27 Aug 2025 13:17:58 +0100 Subject: [PATCH 07/11] Update tests --- .../AOTCompatibilityTests.cs | 1 + src/ReactiveUI.AOTTests/AdvancedAOTTests.cs | 1 + .../ComprehensiveAOTMarkupTests.cs | 1 + .../ComprehensiveAOTTests.cs | 1 + .../FinalAOTValidationTests.cs | 1 + .../{ => Mocks}/TestActivatableViewModel.cs | 2 +- .../{ => Mocks}/TestReactiveObject.cs | 2 +- .../{ => Mocks}/TestRoutableViewModel.cs | 2 +- .../{ => Properties}/TestConfiguration.cs | 0 .../StringBasedSemanticsTests.cs | 1 + .../ReactiveUI.Builder.Maui.Tests.csproj | 1 + .../ReactiveUIBuilderMauiTests.cs | 49 +- .../Blazor/ReactiveUIBuilderBlazorTests.cs | 48 +- .../Drawing/ReactiveUIBuilderDrawingTests.cs | 26 +- .../ReactiveUIBuilderWinFormsTests.cs | 48 +- .../Wpf/ReactiveUIBuilderWpfTests.cs | 48 +- .../ReactiveUI.Builder.Tests.csproj | 1 + .../ReactiveUIBuilderBlockingTests.cs | 24 +- .../ReactiveUIBuilderCoreTests.cs | 220 ++++---- src/ReactiveUI.Testing/AppBuilderTestBase.cs | 32 ++ src/ReactiveUI.Testing/RxTest.cs | 53 ++ ...provalTests.Testing.DotNet8_0.verified.txt | 10 + ...provalTests.Testing.DotNet9_0.verified.txt | 10 + ...iApprovalTests.Testing.Net4_7.verified.txt | 10 + src/ReactiveUI.Tests/API/ApiApprovalTests.cs | 2 +- .../Activation/ActivatingViewModelTests.cs | 78 +-- .../Activation/ActivatingViewTests.cs | 265 ++++----- .../Activation/CanActivateViewFetcherTests.cs | 83 +-- .../Activation/{ => Mocks}/ActivatingView.cs | 2 +- .../{ => Mocks}/ActivatingViewFetcher.cs | 2 +- .../{ => Mocks}/ActivatingViewModel.cs | 2 +- .../{ => Mocks}/DerivedActivatingViewModel.cs | 2 +- .../Activation/ViewModelActivatorTests.cs | 96 ++-- .../AutoPersist/AutoPersistCollectionTests.cs | 4 +- .../AutoPersist/AutoPersistHelperTest.cs | 4 +- src/ReactiveUI.Tests/AwaiterTest.cs | 2 +- .../BindingTypeConvertersTest.cs | 2 +- .../Commands/CombinedReactiveCommandTest.cs | 4 +- .../Commands/CreatesCommandBindingTests.cs | 36 +- .../Commands/ReactiveCommandTest.cs | 60 +- .../Comparers/OrderedComparerTests.cs | 2 +- src/ReactiveUI.Tests/GlobalUsings.cs | 3 + .../InteractionBinderImplementationTests.cs | 2 +- src/ReactiveUI.Tests/InteractionsTest.cs | 4 +- .../Locator/DefaultViewLocatorTests.cs | 2 +- src/ReactiveUI.Tests/MessageBusTest.cs | 326 +++++------ .../ObservableAsPropertyHelperTest.cs | 4 +- .../ObservedChanged/NewGameViewModelTests.cs | 2 +- .../ObservedChangedMixinTest.cs | 4 +- .../CommandBindingImplementationTests.cs | 260 +++++---- .../windows-xaml/PropertyBindingTest.cs | 436 +++------------ .../RxAppDependencyObjectTests.cs | 16 +- .../WhenAnyThroughDependencyObjectTests.cs | 44 +- .../XamlViewDependencyResolverTests.cs | 36 +- .../Platforms/winforms/ActivationTests.cs | 194 +++---- .../CommandBindingImplementationTests.cs | 127 ++--- .../Platforms/winforms/CommandBindingTests.cs | 213 +++---- .../ReactiveUIBuilderWinFormsTests.cs | 73 ++- .../WinFormsViewDependencyResolverTests.cs | 2 - .../wpf/ReactiveUIBuilderWpfTests.cs | 66 +-- .../wpf/WpfActivationForViewFetcherTest.cs | 192 ++++--- .../Platforms/wpf/WpfActiveContentTests.cs | 519 +++++++++--------- .../{ => Properties}/TestConfiguration.cs | 0 .../ReactiveObject/ReactiveObjectTests.cs | 2 +- .../ReactiveProperty/ReactivePropertyTest.cs | 3 +- .../Resolvers/DependencyResolverTests.cs | 2 +- .../INPCObservableForPropertyTests.cs | 2 +- .../PocoObservableForPropertyTests.cs | 2 +- .../Routing/RoutableViewModelMixinTests.cs | 2 +- .../Routing/RoutedViewHostTests.cs | 2 +- .../Routing/RoutingStateTests.cs | 4 +- .../Routing/ViewModelViewHostTests.cs | 2 +- src/ReactiveUI.Tests/RxAppTest.cs | 17 +- .../SuspensionHostExtensionsTests.cs | 2 +- .../WaitForDispatcherSchedulerTests.cs | 2 +- .../ReactiveNotifyPropertyChangedMixinTest.cs | 4 +- .../WhenAny/WhenAnyObservableTests.cs | 2 +- 77 files changed, 1868 insertions(+), 1943 deletions(-) rename src/ReactiveUI.AOTTests/{ => Mocks}/TestActivatableViewModel.cs (93%) rename src/ReactiveUI.AOTTests/{ => Mocks}/TestReactiveObject.cs (98%) rename src/ReactiveUI.AOTTests/{ => Mocks}/TestRoutableViewModel.cs (94%) rename src/ReactiveUI.AOTTests/{ => Properties}/TestConfiguration.cs (100%) create mode 100644 src/ReactiveUI.Testing/AppBuilderTestBase.cs create mode 100644 src/ReactiveUI.Testing/RxTest.cs rename src/ReactiveUI.Tests/Activation/{ => Mocks}/ActivatingView.cs (97%) rename src/ReactiveUI.Tests/Activation/{ => Mocks}/ActivatingViewFetcher.cs (97%) rename src/ReactiveUI.Tests/Activation/{ => Mocks}/ActivatingViewModel.cs (96%) rename src/ReactiveUI.Tests/Activation/{ => Mocks}/DerivedActivatingViewModel.cs (95%) rename src/ReactiveUI.Tests/{ => Properties}/TestConfiguration.cs (100%) diff --git a/src/ReactiveUI.AOTTests/AOTCompatibilityTests.cs b/src/ReactiveUI.AOTTests/AOTCompatibilityTests.cs index aab6a4ca7d..2db7ce8bc1 100644 --- a/src/ReactiveUI.AOTTests/AOTCompatibilityTests.cs +++ b/src/ReactiveUI.AOTTests/AOTCompatibilityTests.cs @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reactive.Linq; +using ReactiveUI.AOT.Tests.Mocks; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/AdvancedAOTTests.cs b/src/ReactiveUI.AOTTests/AdvancedAOTTests.cs index a51b5bffde..69a3e40d79 100644 --- a/src/ReactiveUI.AOTTests/AdvancedAOTTests.cs +++ b/src/ReactiveUI.AOTTests/AdvancedAOTTests.cs @@ -7,6 +7,7 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; +using ReactiveUI.AOT.Tests.Mocks; using Splat; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/ComprehensiveAOTMarkupTests.cs b/src/ReactiveUI.AOTTests/ComprehensiveAOTMarkupTests.cs index 0a4398c7ed..b7a32c343a 100644 --- a/src/ReactiveUI.AOTTests/ComprehensiveAOTMarkupTests.cs +++ b/src/ReactiveUI.AOTTests/ComprehensiveAOTMarkupTests.cs @@ -8,6 +8,7 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; +using ReactiveUI.AOT.Tests.Mocks; using Splat; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/ComprehensiveAOTTests.cs b/src/ReactiveUI.AOTTests/ComprehensiveAOTTests.cs index 2ee1dab559..9a6332cecd 100644 --- a/src/ReactiveUI.AOTTests/ComprehensiveAOTTests.cs +++ b/src/ReactiveUI.AOTTests/ComprehensiveAOTTests.cs @@ -8,6 +8,7 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; +using ReactiveUI.AOT.Tests.Mocks; using Splat; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/FinalAOTValidationTests.cs b/src/ReactiveUI.AOTTests/FinalAOTValidationTests.cs index 1650608ca1..84044a9dbc 100644 --- a/src/ReactiveUI.AOTTests/FinalAOTValidationTests.cs +++ b/src/ReactiveUI.AOTTests/FinalAOTValidationTests.cs @@ -9,6 +9,7 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; +using ReactiveUI.AOT.Tests.Mocks; using Splat; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/TestActivatableViewModel.cs b/src/ReactiveUI.AOTTests/Mocks/TestActivatableViewModel.cs similarity index 93% rename from src/ReactiveUI.AOTTests/TestActivatableViewModel.cs rename to src/ReactiveUI.AOTTests/Mocks/TestActivatableViewModel.cs index 594bc9b107..9184596ad5 100644 --- a/src/ReactiveUI.AOTTests/TestActivatableViewModel.cs +++ b/src/ReactiveUI.AOTTests/Mocks/TestActivatableViewModel.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.AOTTests; +namespace ReactiveUI.AOT.Tests.Mocks; /// /// Test activatable view model for AOT testing. diff --git a/src/ReactiveUI.AOTTests/TestReactiveObject.cs b/src/ReactiveUI.AOTTests/Mocks/TestReactiveObject.cs similarity index 98% rename from src/ReactiveUI.AOTTests/TestReactiveObject.cs rename to src/ReactiveUI.AOTTests/Mocks/TestReactiveObject.cs index 5c8776e8f5..b69cbb9182 100644 --- a/src/ReactiveUI.AOTTests/TestReactiveObject.cs +++ b/src/ReactiveUI.AOTTests/Mocks/TestReactiveObject.cs @@ -6,7 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reactive.Linq; -namespace ReactiveUI.AOTTests; +namespace ReactiveUI.AOT.Tests.Mocks; /// /// Test ReactiveObject for AOT compatibility testing. diff --git a/src/ReactiveUI.AOTTests/TestRoutableViewModel.cs b/src/ReactiveUI.AOTTests/Mocks/TestRoutableViewModel.cs similarity index 94% rename from src/ReactiveUI.AOTTests/TestRoutableViewModel.cs rename to src/ReactiveUI.AOTTests/Mocks/TestRoutableViewModel.cs index 83b0bb9b7b..894aa3b586 100644 --- a/src/ReactiveUI.AOTTests/TestRoutableViewModel.cs +++ b/src/ReactiveUI.AOTTests/Mocks/TestRoutableViewModel.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.AOTTests; +namespace ReactiveUI.AOT.Tests.Mocks; /// /// Test routable view model for AOT testing. diff --git a/src/ReactiveUI.AOTTests/TestConfiguration.cs b/src/ReactiveUI.AOTTests/Properties/TestConfiguration.cs similarity index 100% rename from src/ReactiveUI.AOTTests/TestConfiguration.cs rename to src/ReactiveUI.AOTTests/Properties/TestConfiguration.cs diff --git a/src/ReactiveUI.AOTTests/StringBasedSemanticsTests.cs b/src/ReactiveUI.AOTTests/StringBasedSemanticsTests.cs index c1ecf8cc7e..6f000ba150 100644 --- a/src/ReactiveUI.AOTTests/StringBasedSemanticsTests.cs +++ b/src/ReactiveUI.AOTTests/StringBasedSemanticsTests.cs @@ -4,6 +4,7 @@ // See the LICENSE file in the project root for full license information. using System.Reactive.Linq; +using ReactiveUI.AOT.Tests.Mocks; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUI.Builder.Maui.Tests.csproj b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUI.Builder.Maui.Tests.csproj index e823efff5c..6ff58cd528 100644 --- a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUI.Builder.Maui.Tests.csproj +++ b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUI.Builder.Maui.Tests.csproj @@ -8,6 +8,7 @@ + diff --git a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs index 8d6c375a56..ef9738d390 100644 --- a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs +++ b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs @@ -3,38 +3,41 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Threading.Tasks; +using ReactiveUI.Testing; + namespace ReactiveUI.Builder.Maui.Tests; -public class ReactiveUIBuilderMauiTests +public class ReactiveUIBuilderMauiTests : AppBuilderTestBase { [Fact] - public void WithMaui_Should_Register_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); + public async Task WithMaui_Should_Register_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); - locator.CreateReactiveUIBuilder() - .WithMaui() - .Build(); + locator.CreateReactiveUIBuilder() + .WithMaui() + .Build(); - var typeConverters = locator.GetServices(); - Assert.NotNull(typeConverters); - } + var typeConverters = locator.GetServices(); + Assert.NotNull(typeConverters); + }); [Fact] - public void WithCoreServices_AndMaui_Should_Register_All_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); + public async Task WithCoreServices_AndMaui_Should_Register_All_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); - locator.CreateReactiveUIBuilder() - .WithMaui() - .Build(); + locator.CreateReactiveUIBuilder() + .WithMaui() + .Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - var typeConverters = locator.GetServices(); - Assert.NotNull(typeConverters); - } + var typeConverters = locator.GetServices(); + Assert.NotNull(typeConverters); + }); } diff --git a/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs index 2e9ad4b4a0..57d066fb2e 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs @@ -3,39 +3,41 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using ReactiveUI.Testing; + namespace ReactiveUI.Builder.Tests.Platforms.Blazor; -public class ReactiveUIBuilderBlazorTests +public class ReactiveUIBuilderBlazorTests : AppBuilderTestBase { [Fact] - public void WithBlazor_Should_Register_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task WithBlazor_Should_Register_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithBlazor().Build(); + builder.WithBlazor().Build(); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); - var typeConverters = locator.GetServices(); - Assert.NotEmpty(typeConverters); - } + var typeConverters = locator.GetServices(); + Assert.NotEmpty(typeConverters); + }); [Fact] - public void WithCoreServices_AndBlazor_Should_Register_All_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task WithCoreServices_AndBlazor_Should_Register_All_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithBlazor().Build(); + builder.WithBlazor().Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - } + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); + }); } diff --git a/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs index 5b92ce0605..98675c3e9e 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs @@ -3,22 +3,24 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using ReactiveUI.Testing; + namespace ReactiveUI.Builder.Tests.Platforms.Drawing; -public class ReactiveUIBuilderDrawingTests +public class ReactiveUIBuilderDrawingTests : AppBuilderTestBase { [Fact] - public void WithDrawing_Should_Register_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task WithDrawing_Should_Register_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithDrawing().Build(); + builder.WithDrawing().Build(); - // Drawing registers bitmap loader in non-NETSTANDARD contexts; we can still assert no exception and core services with chaining - locator.CreateReactiveUIBuilder().WithDrawing().Build(); - var bindingConverters = locator.GetServices(); - Assert.NotNull(bindingConverters); - } + // Drawing registers bitmap loader in non-NETSTANDARD contexts; we can still assert no exception and core services with chaining + locator.CreateReactiveUIBuilder().WithDrawing().Build(); + var bindingConverters = locator.GetServices(); + Assert.NotNull(bindingConverters); + }); } diff --git a/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs index ed9e9eb114..1ee8170120 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs @@ -3,39 +3,41 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using ReactiveUI.Testing; + namespace ReactiveUI.Builder.Tests.Platforms.WinForms; -public class ReactiveUIBuilderWinFormsTests +public class ReactiveUIBuilderWinFormsTests : AppBuilderTestBase { [Fact] - public void WithWinForms_Should_Register_WinForms_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task WithWinForms_Should_Register_WinForms_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithWinForms().Build(); + builder.WithWinForms().Build(); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); - var activationFetcher = locator.GetService(); - Assert.NotNull(activationFetcher); - } + var activationFetcher = locator.GetService(); + Assert.NotNull(activationFetcher); + }); [Fact] - public void WithCoreServices_AndWinForms_Should_Register_All_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task WithCoreServices_AndWinForms_Should_Register_All_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithWinForms().Build(); + builder.WithWinForms().Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - } + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); + }); } diff --git a/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs index 6606f3fffd..e3f06cbc68 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs @@ -3,39 +3,41 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using ReactiveUI.Testing; + namespace ReactiveUI.Builder.Tests.Platforms.Wpf; -public class ReactiveUIBuilderWpfTests +public class ReactiveUIBuilderWpfTests : AppBuilderTestBase { [Fact] - public void WithWpf_Should_Register_Wpf_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task WithWpf_Should_Register_Wpf_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithWpf().Build(); + builder.WithWpf().Build(); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); - var activationFetcher = locator.GetService(); - Assert.NotNull(activationFetcher); - } + var activationFetcher = locator.GetService(); + Assert.NotNull(activationFetcher); + }); [Fact] - public void WithCoreServices_AndWpf_Should_Register_All_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task WithCoreServices_AndWpf_Should_Register_All_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithWpf().Build(); + builder.WithWpf().Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - } + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); + }); } diff --git a/src/ReactiveUI.Builder.Tests/ReactiveUI.Builder.Tests.csproj b/src/ReactiveUI.Builder.Tests/ReactiveUI.Builder.Tests.csproj index f17d6c2922..fc9cb971df 100644 --- a/src/ReactiveUI.Builder.Tests/ReactiveUI.Builder.Tests.csproj +++ b/src/ReactiveUI.Builder.Tests/ReactiveUI.Builder.Tests.csproj @@ -16,6 +16,7 @@ + diff --git a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs index 844173f910..a0cc16b947 100644 --- a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs +++ b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs @@ -3,25 +3,27 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using ReactiveUI.Testing; + namespace ReactiveUI.Builder.Tests; /// /// Tests ensuring the builder blocks reflection-based initialization. /// -public class ReactiveUIBuilderBlockingTests +public class ReactiveUIBuilderBlockingTests : AppBuilderTestBase { [Fact] - public void Build_SetsFlag_AndBlocks_InitializeReactiveUI() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); + public async Task Build_SetsFlag_AndBlocks_InitializeReactiveUI() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - builder.Build(); + var builder = locator.CreateReactiveUIBuilder(); + builder.Build(); - locator.InitializeReactiveUI(); + locator.InitializeReactiveUI(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); - } + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); + }); } diff --git a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs index 843db8b123..59c8f0b8ec 100644 --- a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs +++ b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs @@ -3,147 +3,149 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using ReactiveUI.Testing; + namespace ReactiveUI.Builder.Tests; /// /// Tests for the ReactiveUIBuilder core functionality. /// -public class ReactiveUIBuilderCoreTests +public class ReactiveUIBuilderCoreTests : AppBuilderTestBase { [Fact] - public void CreateBuilder_Should_Return_Builder_Instance() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - Assert.NotNull(builder); - Assert.IsType(builder); - } + public async Task CreateBuilder_Should_Return_Builder_Instance() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + Assert.NotNull(builder); + Assert.IsType(builder); + }); [Fact] - public void WithCoreServices_Should_Register_Core_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - builder.Build(); + public async Task WithCoreServices_Should_Register_Core_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + builder.Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - var typeConverter = locator.GetService(); - Assert.NotNull(typeConverter); - } + var typeConverter = locator.GetService(); + Assert.NotNull(typeConverter); + }); [Fact] - public void WithPlatformServices_Should_Register_Platform_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - builder.Build(); - - var services = locator.GetServices(); - Assert.NotNull(services); - Assert.True(services.Any()); - } + public async Task WithPlatformServices_Should_Register_Platform_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + builder.Build(); + + var services = locator.GetServices(); + Assert.NotNull(services); + Assert.True(services.Any()); + }); [Fact] - public void WithCustomRegistration_Should_Execute_Custom_Action() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - var customServiceRegistered = false; - - builder.WithCustomRegistration(r => + public async Task WithCustomRegistration_Should_Execute_Custom_Action() => + await RunAppBuilderTestAsync(() => { - r.RegisterConstant("TestValue", typeof(string)); - customServiceRegistered = true; - }).Build(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + var customServiceRegistered = false; + + builder.WithCustomRegistration(r => + { + r.RegisterConstant("TestValue", typeof(string)); + customServiceRegistered = true; + }).Build(); - Assert.True(customServiceRegistered); - var service = locator.GetService(); - Assert.Equal("TestValue", service); - } + Assert.True(customServiceRegistered); + var service = locator.GetService(); + Assert.Equal("TestValue", service); + }); [Fact] - public void Build_Should_Always_Register_Core_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task Build_Should_Always_Register_Core_Services() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.Build(); + builder.Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); - } + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); + }); [Fact] - public void WithCustomRegistration_With_Null_Action_Should_Throw() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - Assert.Throws(() => builder.WithCustomRegistration(null!)); - } + public async Task WithCustomRegistration_With_Null_Action_Should_Throw() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + Assert.Throws(() => builder.WithCustomRegistration(null!)); + }); [Fact] - public void WithViewsFromAssembly_Should_Register_Views() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - var assembly = typeof(ReactiveUIBuilderCoreTests).Assembly; + public async Task WithViewsFromAssembly_Should_Register_Views() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + var assembly = typeof(ReactiveUIBuilderCoreTests).Assembly; - builder.WithViewsFromAssembly(assembly).Build(); - Assert.NotNull(builder); - } + builder.WithViewsFromAssembly(assembly).Build(); + Assert.NotNull(builder); + }); [Fact] - public void WithViewsFromAssembly_With_Null_Assembly_Should_Throw() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - Assert.Throws(() => builder.WithViewsFromAssembly(null!)); - } + public async Task WithViewsFromAssembly_With_Null_Assembly_Should_Throw() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + Assert.Throws(() => builder.WithViewsFromAssembly(null!)); + }); [Fact] - public void WithCoreServices_Called_Multiple_Times_Should_Not_Register_Twice() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task WithCoreServices_Called_Multiple_Times_Should_Not_Register_Twice() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithCoreServices().WithCoreServices().Build(); + builder.WithCoreServices().WithCoreServices().Build(); - var services = locator.GetServices(); - Assert.NotNull(services); - Assert.True(services.Any()); - } + var services = locator.GetServices(); + Assert.NotNull(services); + Assert.True(services.Any()); + }); [Fact] - public void Builder_Should_Support_Fluent_Chaining() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - using var locator = new ModernDependencyResolver(); - var customServiceRegistered = false; - - locator.CreateReactiveUIBuilder() - .WithRegistration(r => - { - r.RegisterConstant("Test", typeof(string)); - customServiceRegistered = true; - }) - .Build(); - - Assert.True(customServiceRegistered); - var service = locator.GetService(); - Assert.Equal("Test", service); - - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); - } + public async Task Builder_Should_Support_Fluent_Chaining() => + await RunAppBuilderTestAsync(() => + { + using var locator = new ModernDependencyResolver(); + var customServiceRegistered = false; + + locator.CreateReactiveUIBuilder() + .WithRegistration(r => + { + r.RegisterConstant("Test", typeof(string)); + customServiceRegistered = true; + }) + .Build(); + + Assert.True(customServiceRegistered); + var service = locator.GetService(); + Assert.Equal("Test", service); + + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); + }); } diff --git a/src/ReactiveUI.Testing/AppBuilderTestBase.cs b/src/ReactiveUI.Testing/AppBuilderTestBase.cs new file mode 100644 index 0000000000..a06f9a6eaa --- /dev/null +++ b/src/ReactiveUI.Testing/AppBuilderTestBase.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Testing; + +/// +/// AppBuilderTestBase. +/// +public abstract class AppBuilderTestBase +{ + /// + /// Runs the application builder test asynchronous. + /// + /// The test body. + /// A representing the asynchronous operation. + protected static Task RunAppBuilderTestAsync(Func testBody) => + RxTest.AppBuilderTestAsync(testBody); + + /// + /// Runs the application builder test asynchronous. + /// + /// The test body. + /// A representing the asynchronous operation. + protected static Task RunAppBuilderTestAsync(Action testBody) => + RxTest.AppBuilderTestAsync(() => + { + testBody(); + return Task.CompletedTask; + }); +} diff --git a/src/ReactiveUI.Testing/RxTest.cs b/src/ReactiveUI.Testing/RxTest.cs new file mode 100644 index 0000000000..7e9a653bc4 --- /dev/null +++ b/src/ReactiveUI.Testing/RxTest.cs @@ -0,0 +1,53 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Splat.Builder; + +namespace ReactiveUI.Testing; + +/// +/// RxTest. +/// +public static class RxTest +{ + private static readonly SemaphoreSlim TestGate = new(1, 1); + + /// + /// Applications the builder test asynchronous. + /// + /// The test body. + /// The maximum wait ms. + /// testBody. + /// A representing the asynchronous operation. + public static async Task AppBuilderTestAsync(Func testBody, int maxWaitMs = 5000) + { + if (testBody is null) + { + throw new ArgumentNullException(nameof(testBody)); + } + + await TestGate.WaitAsync().ConfigureAwait(false); + try + { + // Force-reset any previous builder state to avoid waiting deadlocks. + AppBuilder.ResetBuilderStateForTests(); + + try + { + // Execute actual test + await testBody().ConfigureAwait(false); + } + finally + { + // Final reset after test + AppBuilder.ResetBuilderStateForTests(); + } + } + finally + { + TestGate.Release(); + } + } +} diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt index 0e493f7b21..57ed4e8ce2 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt @@ -1,6 +1,12 @@ [assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName=".NET 8.0")] namespace ReactiveUI.Testing { + public abstract class AppBuilderTestBase + { + protected AppBuilderTestBase() { } + protected static System.Threading.Tasks.Task RunAppBuilderTestAsync(System.Action testBody) { } + protected static System.Threading.Tasks.Task RunAppBuilderTestAsync(System.Func testBody) { } + } public interface IBuilder { } public static class IBuilderExtensions { @@ -25,6 +31,10 @@ namespace ReactiveUI.Testing public static TRet With(this ReactiveUI.IMessageBus messageBus, System.Func block) { } public static System.IDisposable WithMessageBus(this ReactiveUI.IMessageBus messageBus) { } } + public static class RxTest + { + public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 5000) { } + } public static class SchedulerExtensions { public static void AdvanceByMs(this Microsoft.Reactive.Testing.TestScheduler scheduler, double milliseconds) { } diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt index 7866ae32fc..312c10e8d9 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt @@ -1,6 +1,12 @@ [assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v9.0", FrameworkDisplayName=".NET 9.0")] namespace ReactiveUI.Testing { + public abstract class AppBuilderTestBase + { + protected AppBuilderTestBase() { } + protected static System.Threading.Tasks.Task RunAppBuilderTestAsync(System.Action testBody) { } + protected static System.Threading.Tasks.Task RunAppBuilderTestAsync(System.Func testBody) { } + } public interface IBuilder { } public static class IBuilderExtensions { @@ -25,6 +31,10 @@ namespace ReactiveUI.Testing public static TRet With(this ReactiveUI.IMessageBus messageBus, System.Func block) { } public static System.IDisposable WithMessageBus(this ReactiveUI.IMessageBus messageBus) { } } + public static class RxTest + { + public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 5000) { } + } public static class SchedulerExtensions { public static void AdvanceByMs(this Microsoft.Reactive.Testing.TestScheduler scheduler, double milliseconds) { } diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt index f11db08cc5..3f835a248f 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt @@ -1,6 +1,12 @@ [assembly: System.Runtime.Versioning.TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName=".NET Framework 4.7.2")] namespace ReactiveUI.Testing { + public abstract class AppBuilderTestBase + { + protected AppBuilderTestBase() { } + protected static System.Threading.Tasks.Task RunAppBuilderTestAsync(System.Action testBody) { } + protected static System.Threading.Tasks.Task RunAppBuilderTestAsync(System.Func testBody) { } + } public interface IBuilder { } public static class IBuilderExtensions { @@ -25,6 +31,10 @@ namespace ReactiveUI.Testing public static TRet With(this ReactiveUI.IMessageBus messageBus, System.Func block) { } public static System.IDisposable WithMessageBus(this ReactiveUI.IMessageBus messageBus) { } } + public static class RxTest + { + public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 5000) { } + } public static class SchedulerExtensions { public static void AdvanceByMs(this Microsoft.Reactive.Testing.TestScheduler scheduler, double milliseconds) { } diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.cs b/src/ReactiveUI.Tests/API/ApiApprovalTests.cs index 0a32fa1f74..5e31a9e9e2 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.cs +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.cs @@ -9,7 +9,7 @@ namespace ReactiveUI.Tests.API; /// Checks to make sure that the API is consistent with previous releases, and new API changes are highlighted. /// [ExcludeFromCodeCoverage] -public class ApiApprovalTests +public class ApiApprovalTests : AppBuilderTestBase { /// /// Generates public API for the ReactiveUI.Testing API. diff --git a/src/ReactiveUI.Tests/Activation/ActivatingViewModelTests.cs b/src/ReactiveUI.Tests/Activation/ActivatingViewModelTests.cs index 5d07a34c30..fca5480cf3 100644 --- a/src/ReactiveUI.Tests/Activation/ActivatingViewModelTests.cs +++ b/src/ReactiveUI.Tests/Activation/ActivatingViewModelTests.cs @@ -8,55 +8,59 @@ namespace ReactiveUI.Tests; /// /// Tests associated with activating view models. /// -public class ActivatingViewModelTests +public class ActivatingViewModelTests : AppBuilderTestBase { /// /// Tests for the activation to make sure it activates the appropriate number of times. /// + /// A representing the asynchronous operation. [Fact] - public void ActivationsGetRefCounted() - { - var fixture = new ActivatingViewModel(); - Assert.Equal(0, fixture.IsActiveCount); + public async Task ActivationsGetRefCounted() => + await RunAppBuilderTestAsync(() => + { + var fixture = new ActivatingViewModel(); + Assert.Equal(0, fixture.IsActiveCount); - fixture.Activator.Activate(); - Assert.Equal(1, fixture.IsActiveCount); + fixture.Activator.Activate(); + Assert.Equal(1, fixture.IsActiveCount); - fixture.Activator.Activate(); - Assert.Equal(1, fixture.IsActiveCount); + fixture.Activator.Activate(); + Assert.Equal(1, fixture.IsActiveCount); - fixture.Activator.Deactivate(); - Assert.Equal(1, fixture.IsActiveCount); + fixture.Activator.Deactivate(); + Assert.Equal(1, fixture.IsActiveCount); - // RefCount drops to zero - fixture.Activator.Deactivate(); - Assert.Equal(0, fixture.IsActiveCount); - } + // RefCount drops to zero + fixture.Activator.Deactivate(); + Assert.Equal(0, fixture.IsActiveCount); + }); /// /// Tests to make sure the activations of derived classes don't get stomped. /// + /// A representing the asynchronous operation. [Fact] - public void DerivedActivationsDontGetStomped() - { - var fixture = new DerivedActivatingViewModel(); - Assert.Equal(0, fixture.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCountAlso); - - fixture.Activator.Activate(); - Assert.Equal(1, fixture.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCountAlso); - - fixture.Activator.Activate(); - Assert.Equal(1, fixture.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCountAlso); - - fixture.Activator.Deactivate(); - Assert.Equal(1, fixture.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCountAlso); - - fixture.Activator.Deactivate(); - Assert.Equal(0, fixture.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCountAlso); - } + public async Task DerivedActivationsDontGetStomped() => + await RunAppBuilderTestAsync(() => + { + var fixture = new DerivedActivatingViewModel(); + Assert.Equal(0, fixture.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCountAlso); + + fixture.Activator.Activate(); + Assert.Equal(1, fixture.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCountAlso); + + fixture.Activator.Activate(); + Assert.Equal(1, fixture.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCountAlso); + + fixture.Activator.Deactivate(); + Assert.Equal(1, fixture.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCountAlso); + + fixture.Activator.Deactivate(); + Assert.Equal(0, fixture.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCountAlso); + }); } diff --git a/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs b/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs index 4a26de35a2..8561c6d1a9 100644 --- a/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs +++ b/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs @@ -10,172 +10,177 @@ namespace ReactiveUI.Tests; /// /// Tests for activating views. /// -public class ActivatingViewTests +public class ActivatingViewTests : AppBuilderTestBase { /// /// Tests to make sure that views generally activate. /// + /// A representing the asynchronous operation. [Fact] - public void ActivatingViewSmokeTest() - { - AppBuilder.ResetBuilderStateForTests(); - var locator = new ModernDependencyResolver(); - locator.InitializeSplat(); - locator.InitializeReactiveUI(); - locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - - using (locator.WithResolver()) + public async Task ActivatingViewSmokeTest() => + await RunAppBuilderTestAsync(() => { - var vm = new ActivatingViewModel(); - var fixture = new ActivatingView - { - ViewModel = vm - }; - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); - - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, vm.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCount); + var locator = new ModernDependencyResolver(); + locator.InitializeSplat(); + locator.InitializeReactiveUI(); + locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - fixture.Unloaded.OnNext(Unit.Default); - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); - } - } + using (locator.WithResolver()) + { + var vm = new ActivatingViewModel(); + var fixture = new ActivatingView + { + ViewModel = vm + }; + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, vm.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCount); + + fixture.Unloaded.OnNext(Unit.Default); + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + } + }); /// /// Tests for making sure nulling the view model deactivate it. /// + /// A representing the asynchronous operation. [Fact] - public void NullingViewModelDeactivateIt() - { - AppBuilder.ResetBuilderStateForTests(); - var locator = new ModernDependencyResolver(); - locator.InitializeSplat(); - locator.InitializeReactiveUI(); - locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - - using (locator.WithResolver()) + public async Task NullingViewModelDeactivateIt() => + await RunAppBuilderTestAsync(() => { - var vm = new ActivatingViewModel(); - var fixture = new ActivatingView - { - ViewModel = vm - }; - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); + var locator = new ModernDependencyResolver(); + locator.InitializeSplat(); + locator.InitializeReactiveUI(); + locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, vm.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCount); - - fixture.ViewModel = null; - Assert.Equal(0, vm.IsActiveCount); - } - } + using (locator.WithResolver()) + { + var vm = new ActivatingViewModel(); + var fixture = new ActivatingView + { + ViewModel = vm + }; + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, vm.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCount); + + fixture.ViewModel = null; + Assert.Equal(0, vm.IsActiveCount); + } + }); /// /// Tests switching the view model deactivates it. /// + /// A representing the asynchronous operation. [Fact] - public void SwitchingViewModelDeactivatesIt() - { - AppBuilder.ResetBuilderStateForTests(); - var locator = new ModernDependencyResolver(); - locator.InitializeSplat(); - locator.InitializeReactiveUI(); - locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - - using (locator.WithResolver()) + public async Task SwitchingViewModelDeactivatesIt() => + await RunAppBuilderTestAsync(() => { - var vm = new ActivatingViewModel(); - var fixture = new ActivatingView - { - ViewModel = vm - }; - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); + var locator = new ModernDependencyResolver(); + locator.InitializeSplat(); + locator.InitializeReactiveUI(); + locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, vm.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCount); - - var newVm = new ActivatingViewModel(); - Assert.Equal(0, newVm.IsActiveCount); - - fixture.ViewModel = newVm; - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(1, newVm.IsActiveCount); - } - } + using (locator.WithResolver()) + { + var vm = new ActivatingViewModel(); + var fixture = new ActivatingView + { + ViewModel = vm + }; + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, vm.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCount); + + var newVm = new ActivatingViewModel(); + Assert.Equal(0, newVm.IsActiveCount); + + fixture.ViewModel = newVm; + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(1, newVm.IsActiveCount); + } + }); /// /// Tests setting the view model after loaded loads it. /// + /// A representing the asynchronous operation. [Fact] - public void SettingViewModelAfterLoadedLoadsIt() - { - AppBuilder.ResetBuilderStateForTests(); - var locator = new ModernDependencyResolver(); - locator.InitializeSplat(); - locator.InitializeReactiveUI(); - locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - - using (locator.WithResolver()) + public async Task SettingViewModelAfterLoadedLoadsIt() => + await RunAppBuilderTestAsync(() => { - var vm = new ActivatingViewModel(); - var fixture = new ActivatingView(); + var locator = new ModernDependencyResolver(); + locator.InitializeSplat(); + locator.InitializeReactiveUI(); + locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); + using (locator.WithResolver()) + { + var vm = new ActivatingViewModel(); + var fixture = new ActivatingView(); + + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, fixture.IsActiveCount); + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, fixture.IsActiveCount); - fixture.ViewModel = vm; - Assert.Equal(1, fixture.IsActiveCount); - Assert.Equal(1, vm.IsActiveCount); + fixture.ViewModel = vm; + Assert.Equal(1, fixture.IsActiveCount); + Assert.Equal(1, vm.IsActiveCount); - fixture.Unloaded.OnNext(Unit.Default); - Assert.Equal(0, fixture.IsActiveCount); - Assert.Equal(0, vm.IsActiveCount); - } - } + fixture.Unloaded.OnNext(Unit.Default); + Assert.Equal(0, fixture.IsActiveCount); + Assert.Equal(0, vm.IsActiveCount); + } + }); /// /// Tests the can unload and load view again. /// + /// A representing the asynchronous operation. [Fact] - public void CanUnloadAndLoadViewAgain() - { - AppBuilder.ResetBuilderStateForTests(); - var locator = new ModernDependencyResolver(); - locator.InitializeSplat(); - locator.InitializeReactiveUI(); - locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - - using (locator.WithResolver()) + public async Task CanUnloadAndLoadViewAgain() => + await RunAppBuilderTestAsync(() => { - var vm = new ActivatingViewModel(); - var fixture = new ActivatingView + var locator = new ModernDependencyResolver(); + locator.InitializeSplat(); + locator.InitializeReactiveUI(); + locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); + + using (locator.WithResolver()) { - ViewModel = vm - }; - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); - - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, vm.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCount); - - fixture.Unloaded.OnNext(Unit.Default); - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); - - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, vm.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCount); - } - } + var vm = new ActivatingViewModel(); + var fixture = new ActivatingView + { + ViewModel = vm + }; + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, vm.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCount); + + fixture.Unloaded.OnNext(Unit.Default); + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, vm.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCount); + } + }); } diff --git a/src/ReactiveUI.Tests/Activation/CanActivateViewFetcherTests.cs b/src/ReactiveUI.Tests/Activation/CanActivateViewFetcherTests.cs index a4a502c9f3..41814ca127 100644 --- a/src/ReactiveUI.Tests/Activation/CanActivateViewFetcherTests.cs +++ b/src/ReactiveUI.Tests/Activation/CanActivateViewFetcherTests.cs @@ -4,7 +4,6 @@ // See the LICENSE file in the project root for full license information. using Microsoft.Reactive.Testing; - using ReactiveUI.Tests.Winforms; namespace ReactiveUI.Tests; @@ -12,71 +11,83 @@ namespace ReactiveUI.Tests; /// /// Tests to make sure the can activate view fetcher works correctly. /// -public class CanActivateViewFetcherTests +public class CanActivateViewFetcherTests : AppBuilderTestBase { /// /// Tests return negative for ICanActivate. /// + /// A representing the asynchronous operation. [Fact] - public void CanNotFetchActivatorForNonCanActivateableForm() - { - var form = new TestFormNotCanActivate(); - var canActivateViewFetcher = new CanActivateViewFetcher(); - canActivateViewFetcher.GetActivationForView(form).AssertEqual(Observable.Return(false)); - } + public async Task CanNotFetchActivatorForNonCanActivateableForm() => + await RunAppBuilderTestAsync(() => + { + var form = new TestFormNotCanActivate(); + var canActivateViewFetcher = new CanActivateViewFetcher(); + canActivateViewFetcher.GetActivationForView(form).AssertEqual(Observable.Return(false)); + }); /// /// Tests return positive for ICanActivate. /// + /// A representing the asynchronous operation. [Fact] - public void CanGetActivationForViewForCanActivateableFormActivated() - { - var canActivateViewFetcher = new CanActivateViewFetcher(); - canActivateViewFetcher.GetActivationForView(new TestForm(1)).FirstAsync().AssertEqual(Observable.Return(true)); - } + public async Task CanGetActivationForViewForCanActivateableFormActivated() => + await RunAppBuilderTestAsync(() => + { + var canActivateViewFetcher = new CanActivateViewFetcher(); + canActivateViewFetcher.GetActivationForView(new TestForm(1)).FirstAsync().AssertEqual(Observable.Return(true)); + }); /// /// Tests return negative for ICanActivate. /// + /// A representing the asynchronous operation. [Fact] - public void CanGetActivationForViewForCanActivateableFormDeactivated() - { - var canActivateViewFetcher = new CanActivateViewFetcher(); - canActivateViewFetcher.GetActivationForView(new TestForm(2)).FirstAsync().AssertEqual(Observable.Return(false)); - } + public async Task CanGetActivationForViewForCanActivateableFormDeactivated() => + await RunAppBuilderTestAsync(() => + { + var canActivateViewFetcher = new CanActivateViewFetcher(); + canActivateViewFetcher.GetActivationForView(new TestForm(2)).FirstAsync().AssertEqual(Observable.Return(false)); + }); /// /// Tests return positive for ICanActivate. /// + /// A representing the asynchronous operation. [Fact] - public void ReturnPositiveForICanActivate() - { - var canActivateViewFetcher = new CanActivateViewFetcher(); - var affinity = canActivateViewFetcher.GetAffinityForView(typeof(ICanActivate)); - Assert.True(affinity > 0); - } + public async Task ReturnPositiveForICanActivate() => + await RunAppBuilderTestAsync(() => + { + var canActivateViewFetcher = new CanActivateViewFetcher(); + var affinity = canActivateViewFetcher.GetAffinityForView(typeof(ICanActivate)); + Assert.True(affinity > 0); + }); /// /// Tests return positive for ICanActivate derivatives. /// + /// A representing the asynchronous operation. [Fact] - public void ReturnPositiveForICanActivateDerivatives() - { - var canActivateViewFetcher = new CanActivateViewFetcher(); - var affinity = canActivateViewFetcher.GetAffinityForView(typeof(CanActivateStub)); - Assert.True(affinity > 0); - } + public async Task ReturnPositiveForICanActivateDerivatives() => + await RunAppBuilderTestAsync(() => + { + var canActivateViewFetcher = new CanActivateViewFetcher(); + var affinity = canActivateViewFetcher.GetAffinityForView(typeof(CanActivateStub)); + Assert.True(affinity > 0); + }); /// /// Tests return zero for non ICanActivate derivatives. /// + /// A representing the asynchronous operation. [Fact] - public void ReturnZeroForNonICanActivateDerivatives() - { - var canActivateViewFetcher = new CanActivateViewFetcher(); - var affinity = canActivateViewFetcher.GetAffinityForView(typeof(CanActivateViewFetcherTests)); - Assert.Equal(0, affinity); - } + public async Task ReturnZeroForNonICanActivateDerivatives() => + await RunAppBuilderTestAsync(() => + { + var canActivateViewFetcher = new CanActivateViewFetcher(); + var affinity = canActivateViewFetcher.GetAffinityForView(typeof(CanActivateViewFetcherTests)); + Assert.Equal(0, affinity); + }); #pragma warning disable CA1812 // Class is not instantiated diff --git a/src/ReactiveUI.Tests/Activation/ActivatingView.cs b/src/ReactiveUI.Tests/Activation/Mocks/ActivatingView.cs similarity index 97% rename from src/ReactiveUI.Tests/Activation/ActivatingView.cs rename to src/ReactiveUI.Tests/Activation/Mocks/ActivatingView.cs index fd59ba885f..92a443427f 100644 --- a/src/ReactiveUI.Tests/Activation/ActivatingView.cs +++ b/src/ReactiveUI.Tests/Activation/Mocks/ActivatingView.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.Tests; +namespace ReactiveUI.Tests.Activation.Mocks; /// /// A view which simulates a activation. diff --git a/src/ReactiveUI.Tests/Activation/ActivatingViewFetcher.cs b/src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewFetcher.cs similarity index 97% rename from src/ReactiveUI.Tests/Activation/ActivatingViewFetcher.cs rename to src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewFetcher.cs index 550eed6129..ec2c03a8a0 100644 --- a/src/ReactiveUI.Tests/Activation/ActivatingViewFetcher.cs +++ b/src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewFetcher.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.Tests; +namespace ReactiveUI.Tests.Activation.Mocks; /// /// Simulates a activating view fetcher. diff --git a/src/ReactiveUI.Tests/Activation/ActivatingViewModel.cs b/src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewModel.cs similarity index 96% rename from src/ReactiveUI.Tests/Activation/ActivatingViewModel.cs rename to src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewModel.cs index 832ea63332..08e457535c 100644 --- a/src/ReactiveUI.Tests/Activation/ActivatingViewModel.cs +++ b/src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewModel.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.Tests; +namespace ReactiveUI.Tests.Activation.Mocks; /// /// Simulates a activating view model. diff --git a/src/ReactiveUI.Tests/Activation/DerivedActivatingViewModel.cs b/src/ReactiveUI.Tests/Activation/Mocks/DerivedActivatingViewModel.cs similarity index 95% rename from src/ReactiveUI.Tests/Activation/DerivedActivatingViewModel.cs rename to src/ReactiveUI.Tests/Activation/Mocks/DerivedActivatingViewModel.cs index 5505b326c9..3b7796502f 100644 --- a/src/ReactiveUI.Tests/Activation/DerivedActivatingViewModel.cs +++ b/src/ReactiveUI.Tests/Activation/Mocks/DerivedActivatingViewModel.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.Tests; +namespace ReactiveUI.Tests.Activation.Mocks; /// /// A activating view model which is derived from another ActivatingViewModel. diff --git a/src/ReactiveUI.Tests/Activation/ViewModelActivatorTests.cs b/src/ReactiveUI.Tests/Activation/ViewModelActivatorTests.cs index 881814efe2..86d8640fb5 100644 --- a/src/ReactiveUI.Tests/Activation/ViewModelActivatorTests.cs +++ b/src/ReactiveUI.Tests/Activation/ViewModelActivatorTests.cs @@ -10,82 +10,92 @@ namespace ReactiveUI.Tests; /// /// Tests for the view model activator. /// -public class ViewModelActivatorTests +public class ViewModelActivatorTests : AppBuilderTestBase { /// /// Tests the activating ticks activated observable. /// + /// A representing the asynchronous operation. [Fact] - public void TestActivatingTicksActivatedObservable() - { - var viewModelActivator = new ViewModelActivator(); - viewModelActivator.Activated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + public async Task TestActivatingTicksActivatedObservable() => + await RunAppBuilderTestAsync(() => + { + var viewModelActivator = new ViewModelActivator(); + viewModelActivator.Activated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - viewModelActivator.Activate(); + viewModelActivator.Activate(); - Assert.Equal(1, activated.Count); - } + Assert.Equal(1, activated.Count); + }); /// /// Tests the deactivating ignoring reference count ticks deactivated observable. /// + /// A representing the asynchronous operation. [Fact] - public void TestDeactivatingIgnoringRefCountTicksDeactivatedObservable() - { - var viewModelActivator = new ViewModelActivator(); - viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); + public async Task TestDeactivatingIgnoringRefCountTicksDeactivatedObservable() => + await RunAppBuilderTestAsync(() => + { + var viewModelActivator = new ViewModelActivator(); + viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); - viewModelActivator.Deactivate(true); + viewModelActivator.Deactivate(true); - Assert.Equal(1, deactivated.Count); - } + Assert.Equal(1, deactivated.Count); + }); /// /// Tests the deactivating count doesnt tick deactivated observable. /// + /// A representing the asynchronous operation. [Fact] - public void TestDeactivatingCountDoesntTickDeactivatedObservable() - { - var viewModelActivator = new ViewModelActivator(); - viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); + public async Task TestDeactivatingCountDoesntTickDeactivatedObservable() => + await RunAppBuilderTestAsync(() => + { + var viewModelActivator = new ViewModelActivator(); + viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); - viewModelActivator.Deactivate(false); + viewModelActivator.Deactivate(false); - Assert.Equal(0, deactivated.Count); - } + Assert.Equal(0, deactivated.Count); + }); /// /// Tests the deactivating following activating ticks deactivated observable. /// + /// A representing the asynchronous operation. [Fact] - public void TestDeactivatingFollowingActivatingTicksDeactivatedObservable() - { - var viewModelActivator = new ViewModelActivator(); - viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); + public async Task TestDeactivatingFollowingActivatingTicksDeactivatedObservable() => + await RunAppBuilderTestAsync(() => + { + var viewModelActivator = new ViewModelActivator(); + viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); - viewModelActivator.Activate(); - viewModelActivator.Deactivate(false); + viewModelActivator.Activate(); + viewModelActivator.Deactivate(false); - Assert.Equal(1, deactivated.Count); - } + Assert.Equal(1, deactivated.Count); + }); /// /// Tests the disposing after activation deactivates view model. /// + /// A representing the asynchronous operation. [Fact] - public void TestDisposingAfterActivationDeactivatesViewModel() - { - var viewModelActivator = new ViewModelActivator(); - viewModelActivator.Activated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); - - using (viewModelActivator.Activate()) + public async Task TestDisposingAfterActivationDeactivatesViewModel() => + await RunAppBuilderTestAsync(() => { - Assert.Equal(1, activated.Count); - Assert.Equal(0, deactivated.Count); - } + var viewModelActivator = new ViewModelActivator(); + viewModelActivator.Activated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); - Assert.Equal(1, activated.Count); - Assert.Equal(1, deactivated.Count); - } + using (viewModelActivator.Activate()) + { + Assert.Equal(1, activated.Count); + Assert.Equal(0, deactivated.Count); + } + + Assert.Equal(1, activated.Count); + Assert.Equal(1, deactivated.Count); + }); } diff --git a/src/ReactiveUI.Tests/AutoPersist/AutoPersistCollectionTests.cs b/src/ReactiveUI.Tests/AutoPersist/AutoPersistCollectionTests.cs index bed7a9fef7..5a51fc09d1 100644 --- a/src/ReactiveUI.Tests/AutoPersist/AutoPersistCollectionTests.cs +++ b/src/ReactiveUI.Tests/AutoPersist/AutoPersistCollectionTests.cs @@ -7,14 +7,12 @@ using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; - namespace ReactiveUI.Tests; /// /// Tests to make sure that the auto persist collection works. /// -public class AutoPersistCollectionTests +public class AutoPersistCollectionTests : AppBuilderTestBase { /// /// Test the automatic persist collection smoke test. diff --git a/src/ReactiveUI.Tests/AutoPersist/AutoPersistHelperTest.cs b/src/ReactiveUI.Tests/AutoPersist/AutoPersistHelperTest.cs index 79575428fa..4d8a56b599 100644 --- a/src/ReactiveUI.Tests/AutoPersist/AutoPersistHelperTest.cs +++ b/src/ReactiveUI.Tests/AutoPersist/AutoPersistHelperTest.cs @@ -5,14 +5,12 @@ using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; - namespace ReactiveUI.Tests; /// /// Tests the AutoPersistHelper. /// -public class AutoPersistHelperTest +public class AutoPersistHelperTest : AppBuilderTestBase { /// /// Test the automatic persist doesnt work on non data contract classes. diff --git a/src/ReactiveUI.Tests/AwaiterTest.cs b/src/ReactiveUI.Tests/AwaiterTest.cs index 28720b3bd0..678d39499e 100644 --- a/src/ReactiveUI.Tests/AwaiterTest.cs +++ b/src/ReactiveUI.Tests/AwaiterTest.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Tests the awaiters. /// -public class AwaiterTest +public class AwaiterTest : AppBuilderTestBase { /// /// A smoke test for Awaiters. diff --git a/src/ReactiveUI.Tests/BindingTypeConvertersTest.cs b/src/ReactiveUI.Tests/BindingTypeConvertersTest.cs index 354d6776ec..1ad501394d 100644 --- a/src/ReactiveUI.Tests/BindingTypeConvertersTest.cs +++ b/src/ReactiveUI.Tests/BindingTypeConvertersTest.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Tests for binding type converters. /// -public class BindingTypeConvertersTest +public class BindingTypeConvertersTest : AppBuilderTestBase { /// /// Tests that equality type converter do reference cast should convert null nullable values. diff --git a/src/ReactiveUI.Tests/Commands/CombinedReactiveCommandTest.cs b/src/ReactiveUI.Tests/Commands/CombinedReactiveCommandTest.cs index e3b1f5466d..e5c32fc167 100644 --- a/src/ReactiveUI.Tests/Commands/CombinedReactiveCommandTest.cs +++ b/src/ReactiveUI.Tests/Commands/CombinedReactiveCommandTest.cs @@ -7,14 +7,12 @@ using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; - namespace ReactiveUI.Tests; /// /// Tests for the ReactiveCommand Combined functionality. /// -public class CombinedReactiveCommandTest +public class CombinedReactiveCommandTest : AppBuilderTestBase { /// /// Tests that determines whether this instance [can execute is false if any child cannot execute]. diff --git a/src/ReactiveUI.Tests/Commands/CreatesCommandBindingTests.cs b/src/ReactiveUI.Tests/Commands/CreatesCommandBindingTests.cs index 727dc1df5a..8bafbefb74 100644 --- a/src/ReactiveUI.Tests/Commands/CreatesCommandBindingTests.cs +++ b/src/ReactiveUI.Tests/Commands/CreatesCommandBindingTests.cs @@ -8,29 +8,31 @@ namespace ReactiveUI.Tests; /// /// Tests for the CreateCommand binding. /// -public class CreatesCommandBindingTests +public class CreatesCommandBindingTests : AppBuilderTestBase { /// /// Test that makes sure events binder binds to explicit event. /// + /// A representing the asynchronous operation. [Fact] - public void EventBinderBindsToExplicitEvent() - { - var input = new TestFixture(); - var fixture = new CreatesCommandBindingViaEvent(); - var wasCalled = false; - var cmd = ReactiveCommand.Create(_ => wasCalled = true); + public async Task EventBinderBindsToExplicitEvent() => + await RunAppBuilderTestAsync(() => + { + var input = new TestFixture(); + var fixture = new CreatesCommandBindingViaEvent(); + var wasCalled = false; + var cmd = ReactiveCommand.Create(_ => wasCalled = true); - Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); - Assert.False(fixture.GetAffinityForObject(input.GetType(), false) > 0); + Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); + Assert.False(fixture.GetAffinityForObject(input.GetType(), false) > 0); - var disposable = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5), "PropertyChanged"); - input.IsNotNullString = "Foo"; - Assert.True(wasCalled); + var disposable = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5), "PropertyChanged"); + input.IsNotNullString = "Foo"; + Assert.True(wasCalled); - wasCalled = false; - disposable?.Dispose(); - input.IsNotNullString = "Bar"; - Assert.False(wasCalled); - } + wasCalled = false; + disposable?.Dispose(); + input.IsNotNullString = "Bar"; + Assert.False(wasCalled); + }); } diff --git a/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs b/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs index 6b79b06259..6db8949b49 100644 --- a/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs +++ b/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs @@ -9,14 +9,12 @@ using FluentAssertions; using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; - namespace ReactiveUI.Tests; /// /// Tests for the ReactiveCommand class. /// -public class ReactiveCommandTest +public class ReactiveCommandTest : AppBuilderTestBase { public ReactiveCommandTest() { @@ -29,7 +27,6 @@ public ReactiveCommandTest() [Fact] public void CanExecuteChangedIsAvailableViaICommand() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); ICommand? fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); var canExecuteChanged = new List(); @@ -49,7 +46,6 @@ public void CanExecuteChangedIsAvailableViaICommand() [Fact] public void CanExecuteIsAvailableViaICommand() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); ICommand? fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); @@ -68,7 +64,6 @@ public void CanExecuteIsAvailableViaICommand() [Fact] public void CanExecuteIsBehavioral() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.Create(() => Observables.Unit, outputScheduler: ImmediateScheduler.Instance); fixture.CanExecute.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var canExecute).Subscribe(); @@ -106,7 +101,6 @@ public void CanExecuteIsFalseIfAlreadyExecuting() => [Fact] public void CanExecuteIsFalseIfCallerDictatesAsSuch() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); var fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); fixture.CanExecute.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var canExecute).Subscribe(); @@ -126,7 +120,6 @@ public void CanExecuteIsFalseIfCallerDictatesAsSuch() [Fact] public void CanExecuteIsUnsubscribedAfterCommandDisposal() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); var fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); @@ -143,7 +136,6 @@ public void CanExecuteIsUnsubscribedAfterCommandDisposal() [Fact] public void CanExecuteOnlyTicksDistinctValues() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); var fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); fixture.CanExecute.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var canExecute).Subscribe(); @@ -166,7 +158,6 @@ public void CanExecuteOnlyTicksDistinctValues() [Fact] public void CanExecuteTicksFailuresThroughThrownExceptions() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var canExecuteSubject = new Subject(); var fixture = ReactiveCommand.Create(() => Observables.Unit, canExecuteSubject, ImmediateScheduler.Instance); fixture.ThrownExceptions.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var thrownExceptions).Subscribe(); @@ -183,7 +174,6 @@ public void CanExecuteTicksFailuresThroughThrownExceptions() [Fact] public void CreateTaskFacilitatesTPLIntegration() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromTask(() => Task.FromResult(13), outputScheduler: ImmediateScheduler.Instance); fixture.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var results).Subscribe(); @@ -199,7 +189,6 @@ public void CreateTaskFacilitatesTPLIntegration() [Fact] public void CreateTaskFacilitatesTPLIntegrationWithParameter() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromTask(param => Task.FromResult(param + 1), outputScheduler: ImmediateScheduler.Instance); fixture.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var results).Subscribe(); @@ -217,7 +206,6 @@ public void CreateTaskFacilitatesTPLIntegrationWithParameter() [Fact] public void CreateThrowsIfExecutionParameterIsNull() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. #pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. Assert.Throws(() => ReactiveCommand.Create(null)); @@ -238,7 +226,6 @@ public void CreateThrowsIfExecutionParameterIsNull() [Fact] public void CreateRunInBackgroundThrowsIfExecutionParameterIsNull() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. #pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. Assert.Throws(() => ReactiveCommand.CreateRunInBackground(null)); @@ -302,7 +289,6 @@ public void ExecuteCanBeCancelled() => [Fact] public void ExecuteCanTickThroughMultipleResults() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => new[] { 1, 2, 3 }.ToObservable(), outputScheduler: ImmediateScheduler.Instance); fixture.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var results).Subscribe(); @@ -357,7 +343,6 @@ public void ExecuteFacilitatesAnyNumberOfInFlightExecutions() => [Fact] public void ExecuteIsAvailableViaICommand() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; ICommand? fixture = ReactiveCommand.Create( () => @@ -377,7 +362,6 @@ public void ExecuteIsAvailableViaICommand() [Fact] public void ExecutePassesThroughParameter() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var parameters = new List(); var fixture = ReactiveCommand.CreateFromObservable( param => @@ -403,7 +387,6 @@ public void ExecutePassesThroughParameter() [Fact] public void ExecuteReenablesExecutionEvenAfterFailure() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => Observable.Throw(new InvalidOperationException("oops")), outputScheduler: ImmediateScheduler.Instance); fixture.CanExecute.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var canExecute).Subscribe(); fixture.ThrownExceptions.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var thrownExceptions).Subscribe(); @@ -444,7 +427,6 @@ public void ExecuteResultIsDeliveredOnSpecifiedScheduler() => [Fact] public void ExecuteTicksAnyException() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => Observable.Throw(new InvalidOperationException()), outputScheduler: ImmediateScheduler.Instance); fixture.ThrownExceptions.Subscribe(); Exception? exception = null; @@ -459,7 +441,6 @@ public void ExecuteTicksAnyException() [Fact] public void ExecuteTicksAnyLambdaException() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => throw new InvalidOperationException(), outputScheduler: ImmediateScheduler.Instance); fixture.ThrownExceptions.Subscribe(); Exception? exception = null; @@ -474,7 +455,6 @@ public void ExecuteTicksAnyLambdaException() [Fact] public void ExecuteTicksErrorsThroughThrownExceptions() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => Observable.Throw(new InvalidOperationException("oops")), outputScheduler: ImmediateScheduler.Instance); fixture.ThrownExceptions.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var thrownExceptions).Subscribe(); @@ -490,7 +470,6 @@ public void ExecuteTicksErrorsThroughThrownExceptions() [Fact] public void ExecuteTicksLambdaErrorsThroughThrownExceptions() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.CreateFromObservable(() => throw new InvalidOperationException("oops"), outputScheduler: ImmediateScheduler.Instance); fixture.ThrownExceptions.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var thrownExceptions).Subscribe(); @@ -507,7 +486,6 @@ public void ExecuteTicksLambdaErrorsThroughThrownExceptions() [Fact] public void ExecuteTicksThroughTheResult() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var num = 0; var fixture = ReactiveCommand.CreateFromObservable(() => Observable.Return(num), outputScheduler: ImmediateScheduler.Instance); fixture.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var results).Subscribe(); @@ -531,7 +509,6 @@ public void ExecuteTicksThroughTheResult() [Fact] public void ExecuteViaICommandThrowsIfParameterTypeIsIncorrect() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); ICommand? fixture = ReactiveCommand.Create(_ => { }, outputScheduler: ImmediateScheduler.Instance); var ex = Assert.Throws(() => fixture.Execute("foo")); Assert.Equal("Command requires parameters of type System.Int32, but received parameter of type System.String.", ex.Message); @@ -547,7 +524,6 @@ public void ExecuteViaICommandThrowsIfParameterTypeIsIncorrect() [Fact] public void ExecuteViaICommandWorksWithNullableTypes() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); int? value = null; ICommand? fixture = ReactiveCommand.Create(param => value = param, outputScheduler: ImmediateScheduler.Instance); @@ -564,7 +540,6 @@ public void ExecuteViaICommandWorksWithNullableTypes() [Fact] public void InvokeCommandAgainstICommandInTargetInvokesTheCommand() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; var fixture = new ICommandHolder(); var source = new Subject(); @@ -584,7 +559,6 @@ public void InvokeCommandAgainstICommandInTargetInvokesTheCommand() [Fact] public void InvokeCommandAgainstICommandInTargetPassesTheSpecifiedValueToCanExecuteAndExecute() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = new ICommandHolder(); var source = new Subject(); source.InvokeCommand(fixture, x => x!.TheCommand!); @@ -602,7 +576,6 @@ public void InvokeCommandAgainstICommandInTargetPassesTheSpecifiedValueToCanExec [Fact] public void InvokeCommandAgainstICommandInNullableTargetPassesTheSpecifiedValueToCanExecuteAndExecute() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = new ICommandHolder(); var source = new Subject(); source.InvokeCommand(fixture, x => x.TheCommand); @@ -620,7 +593,6 @@ public void InvokeCommandAgainstICommandInNullableTargetPassesTheSpecifiedValueT [Fact] public void InvokeCommandAgainstICommandInTargetRespectsCanExecute() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = new ICommandHolder(); @@ -642,7 +614,6 @@ public void InvokeCommandAgainstICommandInTargetRespectsCanExecute() [Fact] public void InvokeCommandAgainstICommandInNullableTargetRespectsCanExecute() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = new ICommandHolder(); @@ -664,7 +635,6 @@ public void InvokeCommandAgainstICommandInNullableTargetRespectsCanExecute() [Fact] public void InvokeCommandAgainstICommandInTargetRespectsCanExecuteWindow() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = new ICommandHolder(); @@ -687,7 +657,6 @@ public void InvokeCommandAgainstICommandInTargetRespectsCanExecuteWindow() [Fact] public void InvokeCommandAgainstICommandInTargetSwallowsExceptions() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var count = 0; var fixture = new ICommandHolder(); var command = ReactiveCommand.Create( @@ -714,7 +683,6 @@ public void InvokeCommandAgainstICommandInTargetSwallowsExceptions() [Fact] public void InvokeCommandAgainstICommandInvokesTheCommand() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; ICommand fixture = ReactiveCommand.Create(() => ++executionCount, outputScheduler: ImmediateScheduler.Instance); var source = new Subject(); @@ -733,7 +701,6 @@ public void InvokeCommandAgainstICommandInvokesTheCommand() [Fact] public void InvokeCommandAgainstNullableICommandInvokesTheCommand() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; ICommand? fixture = ReactiveCommand.Create(() => ++executionCount, outputScheduler: ImmediateScheduler.Instance); var source = new Subject(); @@ -752,7 +719,6 @@ public void InvokeCommandAgainstNullableICommandInvokesTheCommand() [Fact] public void InvokeCommandAgainstICommandPassesTheSpecifiedValueToCanExecuteAndExecute() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = new FakeCommand(); var source = new Subject(); source.InvokeCommand(fixture); @@ -768,7 +734,6 @@ public void InvokeCommandAgainstICommandPassesTheSpecifiedValueToCanExecuteAndEx [Fact] public void InvokeCommandAgainstICommandRespectsCanExecute() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); ICommand fixture = ReactiveCommand.Create(() => executed = true, canExecute, ImmediateScheduler.Instance); @@ -789,7 +754,6 @@ public void InvokeCommandAgainstICommandRespectsCanExecute() [Fact] public void InvokeCommandAgainstICommandRespectsCanExecuteWindow() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); ICommand fixture = ReactiveCommand.Create(() => executed = true, canExecute, ImmediateScheduler.Instance); @@ -811,7 +775,6 @@ public void InvokeCommandAgainstICommandRespectsCanExecuteWindow() [Fact] public void InvokeCommandAgainstICommandSwallowsExceptions() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var count = 0; var fixture = ReactiveCommand.Create( () => @@ -836,7 +799,6 @@ public void InvokeCommandAgainstICommandSwallowsExceptions() [Fact] public void InvokeCommandAgainstReactiveCommandInTargetInvokesTheCommand() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; var fixture = new ReactiveCommandHolder(); var source = new Subject(); @@ -856,7 +818,6 @@ public void InvokeCommandAgainstReactiveCommandInTargetInvokesTheCommand() [Fact] public void InvokeCommandAgainstReactiveCommandInTargetPassesTheSpecifiedValueToExecute() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executeReceived = 0; var fixture = new ReactiveCommandHolder(); var source = new Subject(); @@ -873,7 +834,6 @@ public void InvokeCommandAgainstReactiveCommandInTargetPassesTheSpecifiedValueTo [Fact] public void InvokeCommandAgainstReactiveCommandInTargetRespectsCanExecute() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = new ReactiveCommandHolder(); @@ -895,7 +855,6 @@ public void InvokeCommandAgainstReactiveCommandInTargetRespectsCanExecute() [Fact] public void InvokeCommandAgainstReactiveCommandInTargetRespectsCanExecuteWindow() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = new ReactiveCommandHolder(); @@ -918,7 +877,6 @@ public void InvokeCommandAgainstReactiveCommandInTargetRespectsCanExecuteWindow( [Fact] public void InvokeCommandAgainstReactiveCommandInTargetSwallowsExceptions() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var count = 0; var fixture = new ReactiveCommandHolder() { @@ -946,7 +904,6 @@ public void InvokeCommandAgainstReactiveCommandInTargetSwallowsExceptions() [Fact] public void InvokeCommandAgainstReactiveCommandInvokesTheCommand() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; var fixture = ReactiveCommand.Create(() => ++executionCount, outputScheduler: ImmediateScheduler.Instance); var source = new Subject(); @@ -965,7 +922,6 @@ public void InvokeCommandAgainstReactiveCommandInvokesTheCommand() [Fact] public void InvokeCommandAgainstReactiveCommandPassesTheSpecifiedValueToExecute() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executeReceived = 0; var fixture = ReactiveCommand.Create(x => executeReceived = x, outputScheduler: ImmediateScheduler.Instance); var source = new Subject(); @@ -981,7 +937,6 @@ public void InvokeCommandAgainstReactiveCommandPassesTheSpecifiedValueToExecute( [Fact] public void InvokeCommandAgainstReactiveCommandRespectsCanExecute() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = ReactiveCommand.Create(() => executed = true, canExecute, ImmediateScheduler.Instance); @@ -1002,7 +957,6 @@ public void InvokeCommandAgainstReactiveCommandRespectsCanExecute() [Fact] public void InvokeCommandAgainstReactiveCommandRespectsCanExecuteWindow() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executed = false; var canExecute = new BehaviorSubject(false); var fixture = ReactiveCommand.Create(() => executed = true, canExecute, outputScheduler: ImmediateScheduler.Instance); @@ -1024,7 +978,6 @@ public void InvokeCommandAgainstReactiveCommandRespectsCanExecuteWindow() [Fact] public void InvokeCommandAgainstReactiveCommandSwallowsExceptions() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var count = 0; var fixture = ReactiveCommand.Create( () => @@ -1049,7 +1002,6 @@ public void InvokeCommandAgainstReactiveCommandSwallowsExceptions() [Fact] public void InvokeCommandWorksEvenIfTheSourceIsCold() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; var fixture = ReactiveCommand.Create(() => ++executionCount, outputScheduler: ImmediateScheduler.Instance); var source = Observable.Return(Unit.Default); @@ -1064,7 +1016,6 @@ public void InvokeCommandWorksEvenIfTheSourceIsCold() [Fact] public void IsExecutingIsBehavioral() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture = ReactiveCommand.Create(() => Observables.Unit, outputScheduler: ImmediateScheduler.Instance); fixture.IsExecuting.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var isExecuting).Subscribe(); @@ -1078,7 +1029,6 @@ public void IsExecutingIsBehavioral() [Fact] public void IsExecutingRemainsTrueAsLongAsExecutionPipelineHasNotCompleted() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var execute = new Subject(); var fixture = ReactiveCommand.CreateFromObservable(() => execute, outputScheduler: ImmediateScheduler.Instance); @@ -1146,7 +1096,6 @@ public void ResultIsTickedThroughSpecifiedScheduler() => [Fact] public void SynchronousCommandExecuteLazily() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var executionCount = 0; #pragma warning disable IDE0053 // Use expression body for lambda expressions #pragma warning disable RCS1021 // Convert lambda expression body to expression-body. @@ -1194,7 +1143,6 @@ public void SynchronousCommandExecuteLazily() [Fact] public void SynchronousCommandsFailCorrectly() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); var fixture1 = ReactiveCommand.Create(() => throw new InvalidOperationException(), outputScheduler: ImmediateScheduler.Instance); var fixture2 = ReactiveCommand.Create(_ => throw new InvalidOperationException(), outputScheduler: ImmediateScheduler.Instance); var fixture3 = ReactiveCommand.Create(() => throw new InvalidOperationException(), outputScheduler: ImmediateScheduler.Instance); @@ -1219,7 +1167,6 @@ public void SynchronousCommandsFailCorrectly() [Fact] public async Task ReactiveCommandCreateFromTaskHandlesTaskExceptionAsync() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var subj = new Subject(); var isExecuting = false; @@ -1265,7 +1212,6 @@ public async Task ReactiveCommandCreateFromTaskHandlesTaskExceptionAsync() [Fact] public async Task ReactiveCommandCreateFromTaskThenCancelSetsIsExecutingFalseOnlyAfterCancellationCompleteAsync() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var statusTrail = new List<(int Position, string Status)>(); var position = 0; @@ -1333,7 +1279,6 @@ public async Task ReactiveCommandCreateFromTaskThenCancelSetsIsExecutingFalseOnl [Fact] public async Task ReactiveCommandExecutesFromInvokeCommand() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var command = ReactiveCommand.Create(async () => await testSequencer.AdvancePhaseAsync("Phase 1")); @@ -1378,7 +1323,6 @@ public void ShouldCallAsyncMethodOnSettingReactiveSetpoint() => [Fact] public async Task ReactiveCommandCreateFromTaskHandlesExecuteCancellation() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var statusTrail = new List<(int Position, string Status)>(); var position = 0; @@ -1483,7 +1427,6 @@ public void ReactiveCommandCreateFromTaskHandlesTaskException() => [Fact] public async Task ReactiveCommandCreateFromTaskHandlesCancellation() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var statusTrail = new List<(int Position, string Status)>(); var position = 0; @@ -1552,7 +1495,6 @@ public async Task ReactiveCommandCreateFromTaskHandlesCancellation() [Fact] public async Task ReactiveCommandCreateFromTaskHandlesCompletion() { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); using var testSequencer = new TestSequencer(); var statusTrail = new List<(int Position, string Status)>(); var position = 0; diff --git a/src/ReactiveUI.Tests/Comparers/OrderedComparerTests.cs b/src/ReactiveUI.Tests/Comparers/OrderedComparerTests.cs index f5849edc0e..408c15234c 100644 --- a/src/ReactiveUI.Tests/Comparers/OrderedComparerTests.cs +++ b/src/ReactiveUI.Tests/Comparers/OrderedComparerTests.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.Tests; /// /// Tests for the ordered comparer. /// -public class OrderedComparerTests +public class OrderedComparerTests : AppBuilderTestBase { /// /// A general smoke test. diff --git a/src/ReactiveUI.Tests/GlobalUsings.cs b/src/ReactiveUI.Tests/GlobalUsings.cs index a2fcae5614..0c3154674f 100644 --- a/src/ReactiveUI.Tests/GlobalUsings.cs +++ b/src/ReactiveUI.Tests/GlobalUsings.cs @@ -3,6 +3,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +global using global::ReactiveUI; +global using global::ReactiveUI.Testing; +global using global::ReactiveUI.Tests.Activation.Mocks; global using global::Splat; global using global::System; global using global::System.Collections.Generic; diff --git a/src/ReactiveUI.Tests/InteractionBinding/InteractionBinderImplementationTests.cs b/src/ReactiveUI.Tests/InteractionBinding/InteractionBinderImplementationTests.cs index 873846b99e..888e9ed99b 100644 --- a/src/ReactiveUI.Tests/InteractionBinding/InteractionBinderImplementationTests.cs +++ b/src/ReactiveUI.Tests/InteractionBinding/InteractionBinderImplementationTests.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.Tests; /// /// Tests for the Interaction bindings. /// -public class InteractionBinderImplementationTests +public class InteractionBinderImplementationTests : AppBuilderTestBase { /// /// Tests that make sure that the we receive output from task handler. diff --git a/src/ReactiveUI.Tests/InteractionsTest.cs b/src/ReactiveUI.Tests/InteractionsTest.cs index 110c11a8c1..cdc18035bc 100644 --- a/src/ReactiveUI.Tests/InteractionsTest.cs +++ b/src/ReactiveUI.Tests/InteractionsTest.cs @@ -7,14 +7,12 @@ using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; - namespace ReactiveUI.Tests; /// /// Tests interactions. /// -public class InteractionsTest +public class InteractionsTest : AppBuilderTestBase { /// /// Tests that registers null handler should cause exception. diff --git a/src/ReactiveUI.Tests/Locator/DefaultViewLocatorTests.cs b/src/ReactiveUI.Tests/Locator/DefaultViewLocatorTests.cs index ea2c6590aa..c9a9956749 100644 --- a/src/ReactiveUI.Tests/Locator/DefaultViewLocatorTests.cs +++ b/src/ReactiveUI.Tests/Locator/DefaultViewLocatorTests.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Tests for the default view locators. /// -public class DefaultViewLocatorTests +public class DefaultViewLocatorTests : AppBuilderTestBase { /// /// Tests that the default name of the view model is replaced with view when determining the service. diff --git a/src/ReactiveUI.Tests/MessageBusTest.cs b/src/ReactiveUI.Tests/MessageBusTest.cs index 8badadb0c8..7891f56cdb 100644 --- a/src/ReactiveUI.Tests/MessageBusTest.cs +++ b/src/ReactiveUI.Tests/MessageBusTest.cs @@ -7,237 +7,255 @@ using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; - namespace ReactiveUI.Tests; /// /// Tests the MessageBus class. /// -public class MessageBusTest +public class MessageBusTest : AppBuilderTestBase { /// /// Smoke tests the MessageBus. /// + /// A representing the asynchronous operation. [Fact] - public void MessageBusSmokeTest() - { - var input = new[] { 1, 2, 3, 4 }; - - var result = new TestScheduler().With(scheduler => + public async Task MessageBusSmokeTest() => + await RunAppBuilderTestAsync(() => { - var source = new Subject(); - var fixture = new MessageBus(); + var input = new[] { 1, 2, 3, 4 }; - fixture.RegisterMessageSource(source, "Test"); - Assert.False(fixture.IsRegistered(typeof(int))); - Assert.False(fixture.IsRegistered(typeof(int), "Foo")); + var result = new TestScheduler().With(scheduler => + { + var source = new Subject(); + var fixture = new MessageBus(); - fixture.Listen("Test").ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var output).Subscribe(); + fixture.RegisterMessageSource(source, "Test"); + Assert.False(fixture.IsRegistered(typeof(int))); + Assert.False(fixture.IsRegistered(typeof(int), "Foo")); - input.Run(source.OnNext); + fixture.Listen("Test").ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var output).Subscribe(); - scheduler.Start(); - return output; - }); + input.Run(source.OnNext); - input.AssertAreEqual(result); - } + scheduler.Start(); + return output; + }); + + input.AssertAreEqual(result); + }); /// /// Tests that explicits send message should work even after registering source. /// + /// A representing the asynchronous operation. [Fact] - public void ExplicitSendMessageShouldWorkEvenAfterRegisteringSource() - { - var fixture = new MessageBus(); - fixture.RegisterMessageSource(Observable.Never); + public async Task ExplicitSendMessageShouldWorkEvenAfterRegisteringSource() => + await RunAppBuilderTestAsync(() => + { + var fixture = new MessageBus(); + fixture.RegisterMessageSource(Observable.Never); - var messageReceived = false; - fixture.Listen().Subscribe(_ => messageReceived = true); + var messageReceived = false; + fixture.Listen().Subscribe(_ => messageReceived = true); - fixture.SendMessage(42); - Assert.True(messageReceived); - } + fixture.SendMessage(42); + Assert.True(messageReceived); + }); /// /// Tests that listening before registering a source should work. /// + /// A representing the asynchronous operation. [Fact] - public void ListeningBeforeRegisteringASourceShouldWork() - { - var fixture = new MessageBus(); - var result = -1; + public async Task ListeningBeforeRegisteringASourceShouldWork() => + await RunAppBuilderTestAsync(() => + { + var fixture = new MessageBus(); + var result = -1; - fixture.Listen().Subscribe(x => result = x); + fixture.Listen().Subscribe(x => result = x); - Assert.Equal(-1, result); + Assert.Equal(-1, result); - fixture.SendMessage(42); + fixture.SendMessage(42); - Assert.Equal(42, result); - } + Assert.Equal(42, result); + }); /// /// Tests that the Garbage Collector should not kill message service. /// + /// A representing the asynchronous operation. [Fact] - public void GcShouldNotKillMessageService() - { - var bus = new MessageBus(); + public async Task GcShouldNotKillMessageService() => + await RunAppBuilderTestAsync(() => + { + var bus = new MessageBus(); - var receivedMessage = false; - var dispose = bus.Listen().Subscribe(_ => receivedMessage = true); - bus.SendMessage(1); - Assert.True(receivedMessage); + var receivedMessage = false; + var dispose = bus.Listen().Subscribe(_ => receivedMessage = true); + bus.SendMessage(1); + Assert.True(receivedMessage); - GC.Collect(); - GC.WaitForPendingFinalizers(); + GC.Collect(); + GC.WaitForPendingFinalizers(); - receivedMessage = false; - bus.SendMessage(2); - Assert.True(receivedMessage); - } + receivedMessage = false; + bus.SendMessage(2); + Assert.True(receivedMessage); + }); /// /// Tests that Registering the second message source should merge both sources. /// + /// A representing the asynchronous operation. [Fact] - public void RegisteringSecondMessageSourceShouldMergeBothSources() - { - var bus = new MessageBus(); - var source1 = new Subject(); - var source2 = new Subject(); - var receivedMessage1 = false; - var receivedMessage2 = false; + public async Task RegisteringSecondMessageSourceShouldMergeBothSources() => + await RunAppBuilderTestAsync(() => + { + var bus = new MessageBus(); + var source1 = new Subject(); + var source2 = new Subject(); + var receivedMessage1 = false; + var receivedMessage2 = false; - bus.RegisterMessageSource(source1); - bus.Listen().Subscribe(_ => receivedMessage1 = true); + bus.RegisterMessageSource(source1); + bus.Listen().Subscribe(_ => receivedMessage1 = true); - bus.RegisterMessageSource(source2); - bus.Listen().Subscribe(_ => receivedMessage2 = true); + bus.RegisterMessageSource(source2); + bus.Listen().Subscribe(_ => receivedMessage2 = true); - source1.OnNext(1); - Assert.True(receivedMessage1); - Assert.True(receivedMessage2); + source1.OnNext(1); + Assert.True(receivedMessage1); + Assert.True(receivedMessage2); - receivedMessage1 = false; - receivedMessage2 = false; + receivedMessage1 = false; + receivedMessage2 = false; - source2.OnNext(2); - Assert.True(receivedMessage1); - Assert.True(receivedMessage2); - } + source2.OnNext(2); + Assert.True(receivedMessage1); + Assert.True(receivedMessage2); + }); /// /// Tests the MessageBus threading. /// + /// A representing the asynchronous operation. [Fact] - public void MessageBusThreadingTest() - { - var mb = new MessageBus(); - int? listenedThreadId = null; - int? otherThreadId = null; - var thisThreadId = Environment.CurrentManagedThreadId; - - var otherThread = new Thread(new ThreadStart(() => + public async Task MessageBusThreadingTest() => + await RunAppBuilderTestAsync(() => { - otherThreadId = Environment.CurrentManagedThreadId; - mb.Listen().Subscribe(_ => listenedThreadId = Environment.CurrentManagedThreadId); - mb.SendMessage(42); - })); - - otherThread.Start(); - otherThread.Join(); - - Assert.NotEqual(listenedThreadId!.Value, thisThreadId); - Assert.Equal(listenedThreadId.Value, otherThreadId!.Value); - } + var mb = new MessageBus(); + int? listenedThreadId = null; + int? otherThreadId = null; + var thisThreadId = Environment.CurrentManagedThreadId; + + var otherThread = new Thread(new ThreadStart(() => + { + otherThreadId = Environment.CurrentManagedThreadId; + mb.Listen().Subscribe(_ => listenedThreadId = Environment.CurrentManagedThreadId); + mb.SendMessage(42); + })); + + otherThread.Start(); + otherThread.Join(); + + Assert.NotEqual(listenedThreadId!.Value, thisThreadId); + Assert.Equal(listenedThreadId.Value, otherThreadId!.Value); + }); /// /// Tests MessageBus.RegisterScheduler method for complete coverage. /// + /// A representing the asynchronous operation. [Fact] - public void MessageBus_RegisterScheduler_ShouldWork() - { - // Arrange - var messageBus = new MessageBus(); - var receivedMessages = new List(); - - // Act - Register scheduler without contract first - messageBus.RegisterScheduler(CurrentThreadScheduler.Instance); - messageBus.Listen().Subscribe(x => receivedMessages.Add(x)); - messageBus.SendMessage(42); - - // Assert - Assert.Single(receivedMessages); - Assert.Equal(42, receivedMessages[0]); - } + public async Task MessageBus_RegisterScheduler_ShouldWork() => + await RunAppBuilderTestAsync(() => + { + // Arrange + var messageBus = new MessageBus(); + var receivedMessages = new List(); + + // Act - Register scheduler without contract first + messageBus.RegisterScheduler(CurrentThreadScheduler.Instance); + messageBus.Listen().Subscribe(x => receivedMessages.Add(x)); + messageBus.SendMessage(42); + + // Assert + Assert.Single(receivedMessages); + Assert.Equal(42, receivedMessages[0]); + }); /// /// Tests MessageBus.ListenIncludeLatest method for complete coverage. /// + /// A representing the asynchronous operation. [Fact] - public void MessageBus_ListenIncludeLatest_ShouldIncludeLastMessage() - { - // Arrange - var messageBus = new MessageBus(); - var receivedMessages = new List(); + public async Task MessageBus_ListenIncludeLatest_ShouldIncludeLastMessage() => + await RunAppBuilderTestAsync(() => + { + // Arrange + var messageBus = new MessageBus(); + var receivedMessages = new List(); - // Send a message first - messageBus.SendMessage(42); + // Send a message first + messageBus.SendMessage(42); - // Act - Listen including latest should get the previously sent message - messageBus.ListenIncludeLatest().Subscribe(x => receivedMessages.Add(x)); + // Act - Listen including latest should get the previously sent message + messageBus.ListenIncludeLatest().Subscribe(x => receivedMessages.Add(x)); - // Assert - Assert.Single(receivedMessages); - Assert.Equal(42, receivedMessages[0]); - } + // Assert + Assert.Single(receivedMessages); + Assert.Equal(42, receivedMessages[0]); + }); /// - /// Tests MessageBus.Current static property for complete coverage. + /// Tests MessageBus.Current static property for 100% coverage. /// + /// A representing the asynchronous operation. [Fact] - public void MessageBus_Current_ShouldBeAccessible() - { - // Act - var current = MessageBus.Current; + public async Task MessageBus_Current_ShouldBeAccessible() => + await RunAppBuilderTestAsync(() => + { + // Act + var current = MessageBus.Current; - // Assert - Assert.NotNull(current); - Assert.IsAssignableFrom(current); - } + // Assert + Assert.NotNull(current); + Assert.IsAssignableFrom(current); + }); /// /// Tests MessageBus with contracts to ensure message isolation. /// + /// A representing the asynchronous operation. [Fact] - public void MessageBus_WithContracts_ShouldIsolateMessages() - { - // Arrange - var messageBus = new MessageBus(); - var contract1Messages = new List(); - var contract2Messages = new List(); - var noContractMessages = new List(); - - // Act - messageBus.Listen("Contract1").Subscribe(x => contract1Messages.Add(x)); - messageBus.Listen("Contract2").Subscribe(x => contract2Messages.Add(x)); - messageBus.Listen().Subscribe(x => noContractMessages.Add(x)); - - messageBus.SendMessage(1, "Contract1"); - messageBus.SendMessage(2, "Contract2"); - messageBus.SendMessage(3); - - // Assert - Assert.Single(contract1Messages); - Assert.Equal(1, contract1Messages[0]); - - Assert.Single(contract2Messages); - Assert.Equal(2, contract2Messages[0]); - - Assert.Single(noContractMessages); - Assert.Equal(3, noContractMessages[0]); - } + public async Task MessageBus_WithContracts_ShouldIsolateMessages() => + await RunAppBuilderTestAsync(() => + { + // Arrange + var messageBus = new MessageBus(); + var contract1Messages = new List(); + var contract2Messages = new List(); + var noContractMessages = new List(); + + // Act + messageBus.Listen("Contract1").Subscribe(x => contract1Messages.Add(x)); + messageBus.Listen("Contract2").Subscribe(x => contract2Messages.Add(x)); + messageBus.Listen().Subscribe(x => noContractMessages.Add(x)); + + messageBus.SendMessage(1, "Contract1"); + messageBus.SendMessage(2, "Contract2"); + messageBus.SendMessage(3); + + // Assert + Assert.Single(contract1Messages); + Assert.Equal(1, contract1Messages[0]); + + Assert.Single(contract2Messages); + Assert.Equal(2, contract2Messages[0]); + + Assert.Single(noContractMessages); + Assert.Equal(3, noContractMessages[0]); + }); } diff --git a/src/ReactiveUI.Tests/ObservableAsPropertyHelper/ObservableAsPropertyHelperTest.cs b/src/ReactiveUI.Tests/ObservableAsPropertyHelper/ObservableAsPropertyHelperTest.cs index b356984adb..471bc8d9d1 100644 --- a/src/ReactiveUI.Tests/ObservableAsPropertyHelper/ObservableAsPropertyHelperTest.cs +++ b/src/ReactiveUI.Tests/ObservableAsPropertyHelper/ObservableAsPropertyHelperTest.cs @@ -7,14 +7,12 @@ using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; - namespace ReactiveUI.Tests; /// /// Tests for the observable as property helper. /// -public class ObservableAsPropertyHelperTest +public class ObservableAsPropertyHelperTest : AppBuilderTestBase { /// /// Tests that Observable As Property Helpers should fire change notifications. diff --git a/src/ReactiveUI.Tests/ObservedChanged/NewGameViewModelTests.cs b/src/ReactiveUI.Tests/ObservedChanged/NewGameViewModelTests.cs index b9a547064b..adf142eace 100644 --- a/src/ReactiveUI.Tests/ObservedChanged/NewGameViewModelTests.cs +++ b/src/ReactiveUI.Tests/ObservedChanged/NewGameViewModelTests.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Tests for a sample game. /// -public class NewGameViewModelTests +public class NewGameViewModelTests : AppBuilderTestBase { private readonly NewGameViewModel _viewmodel; diff --git a/src/ReactiveUI.Tests/ObservedChanged/ObservedChangedMixinTest.cs b/src/ReactiveUI.Tests/ObservedChanged/ObservedChangedMixinTest.cs index 8ffaad7b2d..ef24eb7d52 100644 --- a/src/ReactiveUI.Tests/ObservedChanged/ObservedChangedMixinTest.cs +++ b/src/ReactiveUI.Tests/ObservedChanged/ObservedChangedMixinTest.cs @@ -5,14 +5,12 @@ using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; - namespace ReactiveUI.Tests; /// /// Tests for the ObservedChangedMixin. /// -public class ObservedChangedMixinTest +public class ObservedChangedMixinTest : AppBuilderTestBase { /// /// Tests that getting the value should actually return the value. diff --git a/src/ReactiveUI.Tests/Platforms/windows-xaml/CommandBindingImplementationTests.cs b/src/ReactiveUI.Tests/Platforms/windows-xaml/CommandBindingImplementationTests.cs index d137b1d01d..85070672f0 100644 --- a/src/ReactiveUI.Tests/Platforms/windows-xaml/CommandBindingImplementationTests.cs +++ b/src/ReactiveUI.Tests/Platforms/windows-xaml/CommandBindingImplementationTests.cs @@ -15,216 +15,236 @@ namespace ReactiveUI.Tests.Xaml; /// /// Tests with the command binding implementation. /// -public class CommandBindingImplementationTests +public class CommandBindingImplementationTests : AppBuilderTestBase { /// /// Tests the command bind by name wireup. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindByNameWireup() - { - var view = new CommandBindView { ViewModel = new() }; + public async Task CommandBindByNameWireup() => + await RunAppBuilderTestAsync(() => + { + var view = new CommandBindView { ViewModel = new() }; - Assert.Null(view.Command1.Command); + Assert.Null(view.Command1.Command); - var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); - Assert.Equal(view.ViewModel.Command1, view.Command1.Command); + var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); + Assert.Equal(view.ViewModel.Command1, view.Command1.Command); - var newCmd = ReactiveCommand.Create(_ => { }); - view.ViewModel.Command1 = newCmd; - Assert.Equal(newCmd, view.Command1.Command); + var newCmd = ReactiveCommand.Create(_ => { }); + view.ViewModel.Command1 = newCmd; + Assert.Equal(newCmd, view.Command1.Command); - disp.Dispose(); - Assert.Null(view.Command1.Command); - } + disp.Dispose(); + Assert.Null(view.Command1.Command); + }); /// /// Tests the command bind nested command wireup. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindNestedCommandWireup() - { - var vm = new CommandBindViewModel + public async Task CommandBindNestedCommandWireup() => + await RunAppBuilderTestAsync(() => { - NestedViewModel = new() - }; + var vm = new CommandBindViewModel + { + NestedViewModel = new() + }; - var view = new CommandBindView { ViewModel = vm }; + var view = new CommandBindView { ViewModel = vm }; - view.BindCommand(view.ViewModel, m => m.NestedViewModel.NestedCommand, x => x.Command1); + view.BindCommand(view.ViewModel, m => m.NestedViewModel.NestedCommand, x => x.Command1); - Assert.Equal(view.ViewModel.NestedViewModel.NestedCommand, view.Command1.Command); - } + Assert.Equal(view.ViewModel.NestedViewModel.NestedCommand, view.Command1.Command); + }); /// /// Tests the command bind sets initial enabled state true. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindSetsInitialEnabledState_True() - { - var view = new CommandBindView { ViewModel = new() }; + public async Task CommandBindSetsInitialEnabledState_True() => + await RunAppBuilderTestAsync(() => + { + var view = new CommandBindView { ViewModel = new() }; - var canExecute1 = new BehaviorSubject(true); - view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); + var canExecute1 = new BehaviorSubject(true); + view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); - view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); + view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); - Assert.True(view.Command1.IsEnabled); - } + Assert.True(view.Command1.IsEnabled); + }); /// /// Tests the command bind sets disables command when can execute changed. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindSetsDisablesCommandWhenCanExecuteChanged() - { - var view = new CommandBindView { ViewModel = new() }; + public async Task CommandBindSetsDisablesCommandWhenCanExecuteChanged() => + await RunAppBuilderTestAsync(() => + { + var view = new CommandBindView { ViewModel = new() }; - var canExecute1 = new BehaviorSubject(true); - view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); + var canExecute1 = new BehaviorSubject(true); + view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); - view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); + view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); - Assert.True(view.Command1.IsEnabled); + Assert.True(view.Command1.IsEnabled); - canExecute1.OnNext(false); + canExecute1.OnNext(false); - Assert.False(view.Command1.IsEnabled); - } + Assert.False(view.Command1.IsEnabled); + }); /// /// Tests the command bind sets initial enabled state false. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindSetsInitialEnabledState_False() - { - var view = new CommandBindView { ViewModel = new() }; + public async Task CommandBindSetsInitialEnabledState_False() => + await RunAppBuilderTestAsync(() => + { + var view = new CommandBindView { ViewModel = new() }; - var canExecute1 = new BehaviorSubject(false); - view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); + var canExecute1 = new BehaviorSubject(false); + view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); - view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); + view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); - Assert.False(view.Command1.IsEnabled); - } + Assert.False(view.Command1.IsEnabled); + }); /// /// Tests the command bind raises can execute changed on bind. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindRaisesCanExecuteChangedOnBind() - { - var view = new CommandBindView { ViewModel = new() }; + public async Task CommandBindRaisesCanExecuteChangedOnBind() => + await RunAppBuilderTestAsync(() => + { + var view = new CommandBindView { ViewModel = new() }; - var canExecute1 = new BehaviorSubject(true); - view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); + var canExecute1 = new BehaviorSubject(true); + view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); - view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); + view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); - Assert.True(view.Command1.IsEnabled); + Assert.True(view.Command1.IsEnabled); - // Now change to a disabled cmd - var canExecute2 = new BehaviorSubject(false); - view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute2); + // Now change to a disabled cmd + var canExecute2 = new BehaviorSubject(false); + view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute2); - Assert.False(view.Command1.IsEnabled); - } + Assert.False(view.Command1.IsEnabled); + }); /// /// Tests the command bind with parameter expression. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindWithParameterExpression() - { - var view = new CommandBindView { ViewModel = new() }; + public async Task CommandBindWithParameterExpression() => + await RunAppBuilderTestAsync(() => + { + var view = new CommandBindView { ViewModel = new() }; - var received = 0; - view.ViewModel.Command1 = ReactiveCommand.Create(i => received = i); + var received = 0; + view.ViewModel.Command1 = ReactiveCommand.Create(i => received = i); - var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); + var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); - view.ViewModel.Value = 42; - view.Command1.RaiseCustomClick(); - Assert.Equal(42, received); + view.ViewModel.Value = 42; + view.Command1.RaiseCustomClick(); + Assert.Equal(42, received); - view.ViewModel.Value = 13; - view.Command1.RaiseCustomClick(); - Assert.Equal(13, received); - } + view.ViewModel.Value = 13; + view.Command1.RaiseCustomClick(); + Assert.Equal(13, received); + }); /// /// Tests the command bind with delay set vm parameter expression. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindWithDelaySetVMParameterExpression() - { - var view = new ReactiveObjectCommandBindView + public async Task CommandBindWithDelaySetVMParameterExpression() => + await RunAppBuilderTestAsync(() => { - ViewModel = new() - }; + var view = new ReactiveObjectCommandBindView + { + ViewModel = new() + }; - var received = 0; - view.ViewModel.Command1 = ReactiveCommand.Create(i => received = i); + var received = 0; + view.ViewModel.Command1 = ReactiveCommand.Create(i => received = i); - var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); + var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); - view.ViewModel.Value = 42; - view.Command1.RaiseCustomClick(); - Assert.Equal(42, received); + view.ViewModel.Value = 42; + view.Command1.RaiseCustomClick(); + Assert.Equal(42, received); - view.ViewModel.Value = 13; - view.Command1.RaiseCustomClick(); - Assert.Equal(13, received); - } + view.ViewModel.Value = 13; + view.Command1.RaiseCustomClick(); + Assert.Equal(13, received); + }); /// /// Tests the command bind with delay set vm parameter no inpc expression. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindWithDelaySetVMParameterNoINPCExpression() - { - var view = new CommandBindView { ViewModel = new() }; + public async Task CommandBindWithDelaySetVMParameterNoINPCExpression() => + await RunAppBuilderTestAsync(() => + { + var view = new CommandBindView { ViewModel = new() }; - var received = 0; - var cmd = ReactiveCommand.Create(i => received = i); - view.ViewModel.Command1 = cmd; - view.ViewModel.Value = 10; + var received = 0; + var cmd = ReactiveCommand.Create(i => received = i); + view.ViewModel.Command1 = cmd; + view.ViewModel.Value = 10; - view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); + view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); - view.Command1.RaiseCustomClick(); - Assert.Equal(10, received); + view.Command1.RaiseCustomClick(); + Assert.Equal(10, received); - view.ViewModel.Value = 42; - view.Command1.RaiseCustomClick(); - Assert.Equal(42, received); + view.ViewModel.Value = 42; + view.Command1.RaiseCustomClick(); + Assert.Equal(42, received); - view.ViewModel.Value = 13; - view.Command1.RaiseCustomClick(); - Assert.Equal(13, received); - } + view.ViewModel.Value = 13; + view.Command1.RaiseCustomClick(); + Assert.Equal(13, received); + }); /// /// Tests the command bind with parameter observable. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindWithParameterObservable() - { - var view = new CommandBindView { ViewModel = new() }; + public async Task CommandBindWithParameterObservable() => + await RunAppBuilderTestAsync(() => + { + var view = new CommandBindView { ViewModel = new() }; - var received = 0; - var cmd = ReactiveCommand.Create(i => received = i); - view.ViewModel.Command1 = cmd; - view.ViewModel.Value = 10; - var value = view.ViewModel.WhenAnyValue(v => v.Value); - var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, value, nameof(CustomClickButton.CustomClick)); + var received = 0; + var cmd = ReactiveCommand.Create(i => received = i); + view.ViewModel.Command1 = cmd; + view.ViewModel.Value = 10; + var value = view.ViewModel.WhenAnyValue(v => v.Value); + var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, value, nameof(CustomClickButton.CustomClick)); - view.Command1.RaiseCustomClick(); - Assert.Equal(10, received); + view.Command1.RaiseCustomClick(); + Assert.Equal(10, received); - view.ViewModel.Value = 42; - view.Command1.RaiseCustomClick(); + view.ViewModel.Value = 42; + view.Command1.RaiseCustomClick(); - Assert.Equal(42, received); - } + Assert.Equal(42, received); + }); } diff --git a/src/ReactiveUI.Tests/Platforms/windows-xaml/PropertyBindingTest.cs b/src/ReactiveUI.Tests/Platforms/windows-xaml/PropertyBindingTest.cs index 624b64e0c8..398c1d3fc3 100644 --- a/src/ReactiveUI.Tests/Platforms/windows-xaml/PropertyBindingTest.cs +++ b/src/ReactiveUI.Tests/Platforms/windows-xaml/PropertyBindingTest.cs @@ -20,130 +20,136 @@ namespace ReactiveUI.Tests.Xaml; /// /// Tests property bindings. /// -public class PropertyBindingTest +public class PropertyBindingTest : AppBuilderTestBase { /// /// Performs a smoke test with two way binding with func converter. /// + /// A representing the asynchronous operation. [Fact] [UseInvariantCulture] - public void TwoWayBindWithFuncConvertersSmokeTest() - { - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var fixture = new PropertyBinderImplementation(); + public async Task TwoWayBindWithFuncConvertersSmokeTest() => + await RunAppBuilderTestAsync(() => + { + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var fixture = new PropertyBinderImplementation(); - vm.JustADecimal = 123.45m; - Assert.NotEqual(vm.JustADecimal.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); + vm.JustADecimal = 123.45m; + Assert.NotEqual(vm.JustADecimal.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); - var disp = fixture.Bind(vm, view, x => x.JustADecimal, x => x.SomeTextBox.Text, (IObservable?)null, d => d.ToString(), t => decimal.TryParse(t, out var res) ? res : decimal.Zero); + var disp = fixture.Bind(vm, view, x => x.JustADecimal, x => x.SomeTextBox.Text, (IObservable?)null, d => d.ToString(), t => decimal.TryParse(t, out var res) ? res : decimal.Zero); - Assert.Equal(vm.JustADecimal.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); - Assert.Equal(123.45m, vm.JustADecimal); + Assert.Equal(vm.JustADecimal.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); + Assert.Equal(123.45m, vm.JustADecimal); - view.SomeTextBox.Text = "567.89"; - Assert.Equal(567.89m, vm.JustADecimal); + view.SomeTextBox.Text = "567.89"; + Assert.Equal(567.89m, vm.JustADecimal); - disp?.Dispose(); - vm.JustADecimal = 0; + disp?.Dispose(); + vm.JustADecimal = 0; - Assert.Equal(0, vm.JustADecimal); - Assert.Equal("567.89", view.SomeTextBox.Text); - } + Assert.Equal(0, vm.JustADecimal); + Assert.Equal("567.89", view.SomeTextBox.Text); + }); /// /// Performs a smoke test with two way binding. /// + /// A representing the asynchronous operation. [Fact] - public void TwoWayBindSmokeTest() - { - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var fixture = new PropertyBinderImplementation(); + public async Task TwoWayBindSmokeTest() => + await RunAppBuilderTestAsync(() => + { + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var fixture = new PropertyBinderImplementation(); - vm.Property1 = "Foo"; - Assert.NotEqual(vm.Property1, view.SomeTextBox.Text); + vm.Property1 = "Foo"; + Assert.NotEqual(vm.Property1, view.SomeTextBox.Text); - var disp = fixture.Bind(vm, view, x => x.Property1, x => x.SomeTextBox.Text, (IObservable?)null, null); + var disp = fixture.Bind(vm, view, x => x.Property1, x => x.SomeTextBox.Text, (IObservable?)null, null); - Assert.Equal(vm.Property1, view.SomeTextBox.Text); - Assert.Equal("Foo", vm.Property1); + Assert.Equal(vm.Property1, view.SomeTextBox.Text); + Assert.Equal("Foo", vm.Property1); - view.SomeTextBox.Text = "Bar"; - Assert.Equal(vm.Property1, "Bar"); + view.SomeTextBox.Text = "Bar"; + Assert.Equal(vm.Property1, "Bar"); - disp.Dispose(); - vm.Property1 = "Baz"; + disp.Dispose(); + vm.Property1 = "Baz"; - Assert.Equal("Baz", vm.Property1); - Assert.NotEqual(vm.Property1, view.SomeTextBox.Text); - } + Assert.Equal("Baz", vm.Property1); + Assert.NotEqual(vm.Property1, view.SomeTextBox.Text); + }); /// /// Performs a smoke test with two way binding with a type converter. /// + /// A representing the asynchronous operation. [Fact] - public void TypeConvertedTwoWayBindSmokeTest() - { - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var fixture = new PropertyBinderImplementation(); + public async Task TypeConvertedTwoWayBindSmokeTest() => + await RunAppBuilderTestAsync(() => + { + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var fixture = new PropertyBinderImplementation(); - vm.Property2 = 17; - Assert.NotEqual(vm.Property2.ToString(), view.SomeTextBox.Text); + vm.Property2 = 17; + Assert.NotEqual(vm.Property2.ToString(), view.SomeTextBox.Text); - var disp = fixture.Bind(vm, view, x => x.Property2, x => x.SomeTextBox.Text, (IObservable?)null, null); + var disp = fixture.Bind(vm, view, x => x.Property2, x => x.SomeTextBox.Text, (IObservable?)null, null); - Assert.Equal(vm.Property2.ToString(), view.SomeTextBox.Text); - Assert.Equal(17, vm.Property2); + Assert.Equal(vm.Property2.ToString(), view.SomeTextBox.Text); + Assert.Equal(17, vm.Property2); - view.SomeTextBox.Text = "42"; - Assert.Equal(42, vm.Property2); + view.SomeTextBox.Text = "42"; + Assert.Equal(42, vm.Property2); - // Bad formatting error - view.SomeTextBox.Text = "--"; - Assert.Equal(42, vm.Property2); + // Bad formatting error + view.SomeTextBox.Text = "--"; + Assert.Equal(42, vm.Property2); - disp.Dispose(); - vm.Property2 = 0; + disp.Dispose(); + vm.Property2 = 0; - Assert.Equal(0, vm.Property2); - Assert.NotEqual("0", view.SomeTextBox.Text); + Assert.Equal(0, vm.Property2); + Assert.NotEqual("0", view.SomeTextBox.Text); - vm.JustADecimal = 17.2m; - var disp1 = fixture.Bind(vm, view, x => x.JustADecimal, x => x.SomeTextBox.Text, (IObservable?)null, null); + vm.JustADecimal = 17.2m; + var disp1 = fixture.Bind(vm, view, x => x.JustADecimal, x => x.SomeTextBox.Text, (IObservable?)null, null); - Assert.Equal(vm.JustADecimal.ToString(CultureInfo.CurrentCulture), view.SomeTextBox.Text); - Assert.Equal(17.2m, vm.JustADecimal); + Assert.Equal(vm.JustADecimal.ToString(CultureInfo.CurrentCulture), view.SomeTextBox.Text); + Assert.Equal(17.2m, vm.JustADecimal); - view.SomeTextBox.Text = 42.3m.ToString(CultureInfo.CurrentCulture); - Assert.Equal(42.3m, vm.JustADecimal); + view.SomeTextBox.Text = 42.3m.ToString(CultureInfo.CurrentCulture); + Assert.Equal(42.3m, vm.JustADecimal); - // Bad formatting. - view.SomeTextBox.Text = "--"; - Assert.Equal(42.3m, vm.JustADecimal); + // Bad formatting. + view.SomeTextBox.Text = "--"; + Assert.Equal(42.3m, vm.JustADecimal); - disp1.Dispose(); + disp1.Dispose(); - vm.JustADecimal = 0; + vm.JustADecimal = 0; - Assert.Equal(0, vm.JustADecimal); - Assert.NotEqual("0", view.SomeTextBox.Text); + Assert.Equal(0, vm.JustADecimal); + Assert.NotEqual("0", view.SomeTextBox.Text); - // Empty test - vm.JustAInt32 = 12; - var disp2 = fixture.Bind(vm, view, x => x.JustAInt32, x => x.SomeTextBox.Text, (IObservable?)null, null); + // Empty test + vm.JustAInt32 = 12; + var disp2 = fixture.Bind(vm, view, x => x.JustAInt32, x => x.SomeTextBox.Text, (IObservable?)null, null); - view.SomeTextBox.Text = string.Empty; - Assert.Equal(12, vm.JustAInt32); + view.SomeTextBox.Text = string.Empty; + Assert.Equal(12, vm.JustAInt32); - view.SomeTextBox.Text = "1.2"; + view.SomeTextBox.Text = "1.2"; - Assert.Equal(12, vm.JustAInt32); + Assert.Equal(12, vm.JustAInt32); - view.SomeTextBox.Text = "13"; - Assert.Equal(13, vm.JustAInt32); - } + view.SomeTextBox.Text = "13"; + Assert.Equal(13, vm.JustAInt32); + }); /// /// Tests binding into model objects. @@ -784,52 +790,6 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithNullableDecimalCon Assert.True(dis.IsDisposed); } - [Fact] - public void BindWithFuncToTriggerUpdateTestViewToViewModel() - { - var dis = new CompositeDisposable(); - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var update = new Subject(); - - vm.JustADecimal = 123.45m; - Assert.NotEqual(vm.JustADecimal.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); - - view.Bind(vm, x => x.JustADecimal, x => x.SomeTextBox.Text, update.AsObservable(), d => d.ToString(CultureInfo.InvariantCulture), t => decimal.TryParse(t, out var res) ? res : decimal.Zero, TriggerUpdate.ViewToViewModel).DisposeWith(dis); - - view.SomeTextBox.Text = "1.0"; - - // value should have pre bind value - Assert.Equal(vm.JustADecimal, 123.45m); - - // trigger UI update - update.OnNext(true); - Assert.Equal(vm.JustADecimal, 1.0m); - - view.SomeTextBox.Text = "2.0"; - Assert.Equal(vm.JustADecimal, 1.0m); - - update.OnNext(true); - Assert.Equal(vm.JustADecimal, 2.0m); - - // test reverse bind no trigger required - vm.JustADecimal = 3.0m; - Assert.Equal(view.SomeTextBox.Text, "3.0"); - - vm.JustADecimal = 4.0m; - Assert.Equal(view.SomeTextBox.Text, "4.0"); - - // test forward bind to ensure trigger is still honoured. - view.SomeTextBox.Text = "2.0"; - Assert.Equal(vm.JustADecimal, 4.0m); - - update.OnNext(true); - Assert.Equal(vm.JustADecimal, 2.0m); - - dis.Dispose(); - Assert.True(dis.IsDisposed); - } - [Fact] public void BindWithFuncToTriggerUpdateTestViewModelToViewWithDoubleConverter() { @@ -1076,52 +1036,6 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithNullableSingleConv Assert.True(dis.IsDisposed); } - [Fact] - public void BindWithFuncToTriggerUpdateTestViewModelToViewWithSingleConverterNoRound() - { - var dis = new CompositeDisposable(); - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var update = new Subject(); - - vm.JustASingle = 123.45f; - Assert.NotEqual(vm.JustASingle.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); - - view.Bind(vm, x => x.JustASingle, x => x.SomeTextBox.Text, update.AsObservable(), null, triggerUpdate: TriggerUpdate.ViewModelToView).DisposeWith(dis); - - vm.JustASingle = 1.0f; - - // value should have pre bind value - Assert.Equal(view.SomeTextBox.Text, "123.45"); - - // trigger UI update - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "1"); - - vm.JustASingle = 2.0f; - Assert.Equal(view.SomeTextBox.Text, "1"); - - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "2"); - - // test reverse bind no trigger required - view.SomeTextBox.Text = "3"; - Assert.Equal(vm.JustASingle, 3.0f); - - view.SomeTextBox.Text = "4"; - Assert.Equal(vm.JustASingle, 4.0f); - - // test forward bind to ensure trigger is still honoured. - vm.JustASingle = 2.0f; - Assert.Equal(view.SomeTextBox.Text, "4"); - - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "2"); - - dis.Dispose(); - Assert.True(dis.IsDisposed); - } - [Fact] public void BindWithFuncToTriggerUpdateTestViewModelToViewWithByteConverter() { @@ -1222,52 +1136,6 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithNullableByteConver Assert.True(dis.IsDisposed); } - [Fact] - public void BindWithFuncToTriggerUpdateTestViewModelToViewWithByteConverterNoHint() - { - var dis = new CompositeDisposable(); - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var update = new Subject(); - - vm.JustAByte = 123; - Assert.NotEqual(vm.JustAByte.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); - - view.Bind(vm, x => x.JustAByte, x => x.SomeTextBox.Text, update.AsObservable(), null, triggerUpdate: TriggerUpdate.ViewModelToView).DisposeWith(dis); - - vm.JustAByte = 1; - - // value should have pre bind value - Assert.Equal(view.SomeTextBox.Text, "123"); - - // trigger UI update - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "1"); - - vm.JustAByte = 2; - Assert.Equal(view.SomeTextBox.Text, "1"); - - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "2"); - - // test reverse bind no trigger required - view.SomeTextBox.Text = "3"; - Assert.Equal(vm.JustAByte, 3); - - view.SomeTextBox.Text = "4"; - Assert.Equal(vm.JustAByte, 4); - - // test forward bind to ensure trigger is still honoured. - vm.JustAByte = 2; - Assert.Equal(view.SomeTextBox.Text, "4"); - - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "2"); - - dis.Dispose(); - Assert.True(dis.IsDisposed); - } - [Fact] public void BindWithFuncToTriggerUpdateTestViewModelToViewWithShortConverter() { @@ -1368,52 +1236,6 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithNullableShortConve Assert.True(dis.IsDisposed); } - [Fact] - public void BindWithFuncToTriggerUpdateTestViewModelToViewWithShortConverterNoHint() - { - var dis = new CompositeDisposable(); - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var update = new Subject(); - - vm.JustAInt16 = 123; - Assert.NotEqual(vm.JustAInt16.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); - - view.Bind(vm, x => x.JustAInt16, x => x.SomeTextBox.Text, update.AsObservable(), null, triggerUpdate: TriggerUpdate.ViewModelToView).DisposeWith(dis); - - vm.JustAInt16 = 1; - - // value should have pre bind value - Assert.Equal(view.SomeTextBox.Text, "123"); - - // trigger UI update - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "1"); - - vm.JustAInt16 = 2; - Assert.Equal(view.SomeTextBox.Text, "1"); - - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "2"); - - // test reverse bind no trigger required - view.SomeTextBox.Text = "3"; - Assert.Equal(vm.JustAInt16, 3); - - view.SomeTextBox.Text = "4"; - Assert.Equal(vm.JustAInt16, 4); - - // test forward bind to ensure trigger is still honoured. - vm.JustAInt16 = 2; - Assert.Equal(view.SomeTextBox.Text, "4"); - - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "2"); - - dis.Dispose(); - Assert.True(dis.IsDisposed); - } - [Fact] public void BindWithFuncToTriggerUpdateTestViewModelToViewWithIntegerConverter() { @@ -1514,52 +1336,6 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithNullableIntegerCon Assert.True(dis.IsDisposed); } - [Fact] - public void BindWithFuncToTriggerUpdateTestViewModelToViewWithIntegerConverterNoHint() - { - var dis = new CompositeDisposable(); - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var update = new Subject(); - - vm.JustAInt32 = 123; - Assert.NotEqual(vm.JustAInt32.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); - - view.Bind(vm, x => x.JustAInt32, x => x.SomeTextBox.Text, update.AsObservable(), null, triggerUpdate: TriggerUpdate.ViewModelToView).DisposeWith(dis); - - vm.JustAInt32 = 1; - - // value should have pre bind value - Assert.Equal(view.SomeTextBox.Text, "123"); - - // trigger UI update - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "1"); - - vm.JustAInt32 = 2; - Assert.Equal(view.SomeTextBox.Text, "1"); - - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "2"); - - // test reverse bind no trigger required - view.SomeTextBox.Text = "3"; - Assert.Equal(vm.JustAInt32, 3); - - view.SomeTextBox.Text = "4"; - Assert.Equal(vm.JustAInt32, 4); - - // test forward bind to ensure trigger is still honoured. - vm.JustAInt32 = 2; - Assert.Equal(view.SomeTextBox.Text, "4"); - - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "2"); - - dis.Dispose(); - Assert.True(dis.IsDisposed); - } - [Fact] public void BindWithFuncToTriggerUpdateTestViewModelToViewWithLongConverter() { @@ -1607,50 +1383,4 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithLongConverter() dis.Dispose(); Assert.True(dis.IsDisposed); } - - [Fact] - public void BindWithFuncToTriggerUpdateTestViewModelToViewWithLongConverterNoHint() - { - var dis = new CompositeDisposable(); - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var update = new Subject(); - - vm.JustAInt64 = 123; - Assert.NotEqual(vm.JustAInt64.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); - - view.Bind(vm, x => x.JustAInt64, x => x.SomeTextBox.Text, update.AsObservable(), null, triggerUpdate: TriggerUpdate.ViewModelToView).DisposeWith(dis); - - vm.JustAInt64 = 1; - - // value should have pre bind value - Assert.Equal(view.SomeTextBox.Text, "123"); - - // trigger UI update - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "1"); - - vm.JustAInt64 = 2; - Assert.Equal(view.SomeTextBox.Text, "1"); - - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "2"); - - // test reverse bind no trigger required - view.SomeTextBox.Text = "3"; - Assert.Equal(vm.JustAInt64, 3); - - view.SomeTextBox.Text = "4"; - Assert.Equal(vm.JustAInt64, 4); - - // test forward bind to ensure trigger is still honoured. - vm.JustAInt64 = 2; - Assert.Equal(view.SomeTextBox.Text, "4"); - - update.OnNext(true); - Assert.Equal(view.SomeTextBox.Text, "2"); - - dis.Dispose(); - Assert.True(dis.IsDisposed); - } } diff --git a/src/ReactiveUI.Tests/Platforms/windows-xaml/RxAppDependencyObjectTests.cs b/src/ReactiveUI.Tests/Platforms/windows-xaml/RxAppDependencyObjectTests.cs index 320223bb46..63c68db716 100644 --- a/src/ReactiveUI.Tests/Platforms/windows-xaml/RxAppDependencyObjectTests.cs +++ b/src/ReactiveUI.Tests/Platforms/windows-xaml/RxAppDependencyObjectTests.cs @@ -8,17 +8,19 @@ namespace ReactiveUI.Tests.Xaml; /// /// Checks RxApp dependency objects. /// -public class RxAppDependencyObjectTests +public class RxAppDependencyObjectTests : AppBuilderTestBase { /// /// Tests that Dependency Property notifiers should be found. /// + /// A representing the asynchronous operation. [Fact] - public void DepPropNotifierShouldBeFound() - { - RxApp.EnsureInitialized(); + public async Task DepPropNotifierShouldBeFound() => + await RunAppBuilderTestAsync(() => + { + RxApp.EnsureInitialized(); - Assert.True(Locator.Current.GetServices() - .Any(x => x is DependencyObjectObservableForProperty)); - } + Assert.True(Locator.Current.GetServices() + .Any(x => x is DependencyObjectObservableForProperty)); + }); } diff --git a/src/ReactiveUI.Tests/Platforms/windows-xaml/WhenAnyThroughDependencyObjectTests.cs b/src/ReactiveUI.Tests/Platforms/windows-xaml/WhenAnyThroughDependencyObjectTests.cs index 3172cd7532..3273b3482e 100644 --- a/src/ReactiveUI.Tests/Platforms/windows-xaml/WhenAnyThroughDependencyObjectTests.cs +++ b/src/ReactiveUI.Tests/Platforms/windows-xaml/WhenAnyThroughDependencyObjectTests.cs @@ -15,38 +15,40 @@ namespace ReactiveUI.Tests.Xaml; /// /// Tests that WhenAny dependency objects. /// -public class WhenAnyThroughDependencyObjectTests +public class WhenAnyThroughDependencyObjectTests : AppBuilderTestBase { /// /// Tests that WhenAny through a view shouldn't give null values. /// + /// A representing the asynchronous operation. [Fact] - public void WhenAnyThroughAViewShouldntGiveNullValues() - { - var vm = new HostTestFixture() + public async Task WhenAnyThroughAViewShouldntGiveNullValues() => + await RunAppBuilderTestAsync(() => { - Child = new TestFixture + var vm = new HostTestFixture() { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }, - }; + Child = new TestFixture + { + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }, + }; - var fixture = new HostTestView(); + var fixture = new HostTestView(); - var output = new List(); + var output = new List(); - Assert.Equal(0, output.Count); - Assert.Null(fixture.ViewModel); + Assert.Equal(0, output.Count); + Assert.Null(fixture.ViewModel); - fixture.WhenAnyValue(x => x.ViewModel!.Child!.IsNotNullString).Subscribe(output.Add); + fixture.WhenAnyValue(x => x.ViewModel!.Child!.IsNotNullString).Subscribe(output.Add); - fixture.ViewModel = vm; - Assert.Equal(1, output.Count); + fixture.ViewModel = vm; + Assert.Equal(1, output.Count); - fixture.ViewModel.Child.IsNotNullString = "Bar"; - Assert.Equal(2, output.Count); - new[] { "Foo", "Bar" }.AssertAreEqual(output); - } + fixture.ViewModel.Child.IsNotNullString = "Bar"; + Assert.Equal(2, output.Count); + new[] { "Foo", "Bar" }.AssertAreEqual(output); + }); } diff --git a/src/ReactiveUI.Tests/Platforms/windows-xaml/XamlViewDependencyResolverTests.cs b/src/ReactiveUI.Tests/Platforms/windows-xaml/XamlViewDependencyResolverTests.cs index 6c86ea803f..8b39d7d2ae 100644 --- a/src/ReactiveUI.Tests/Platforms/windows-xaml/XamlViewDependencyResolverTests.cs +++ b/src/ReactiveUI.Tests/Platforms/windows-xaml/XamlViewDependencyResolverTests.cs @@ -16,7 +16,7 @@ namespace ReactiveUI.Tests.Xaml; /// /// Tests associated with UI and the . /// -public sealed class XamlViewDependencyResolverTests : IDisposable +public sealed class XamlViewDependencyResolverTests : AppBuilderTestBase, IDisposable { private readonly IDependencyResolver _resolver; @@ -34,29 +34,33 @@ public XamlViewDependencyResolverTests() /// /// Test that register views for view model should register all views. /// + /// A representing the asynchronous operation. [Fact] - public void RegisterViewsForViewModelShouldRegisterAllViews() - { - using (_resolver.WithResolver()) + public async Task RegisterViewsForViewModelShouldRegisterAllViews() => + await RunAppBuilderTestAsync(() => { - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - } - } + using (_resolver.WithResolver()) + { + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + } + }); /// /// Test that register views for view model should include contracts. /// + /// A representing the asynchronous operation. [Fact] - public void RegisterViewsForViewModelShouldIncludeContracts() - { - using (_resolver.WithResolver()) + public async Task RegisterViewsForViewModelShouldIncludeContracts() => + await RunAppBuilderTestAsync(() => { - Assert.Single(_resolver.GetServices(typeof(IViewFor), "contract")); - } - } + using (_resolver.WithResolver()) + { + Assert.Single(_resolver.GetServices(typeof(IViewFor), "contract")); + } + }); /// public void Dispose() => _resolver?.Dispose(); diff --git a/src/ReactiveUI.Tests/Platforms/winforms/ActivationTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/ActivationTests.cs index bc68cfa0ce..01b9161f49 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/ActivationTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/ActivationTests.cs @@ -10,130 +10,140 @@ namespace ReactiveUI.Tests.Winforms; /// /// Tests to make sure the activation works correctly. /// -public class ActivationTests +public class ActivationTests : AppBuilderTestBase { /// /// Tests activations for view fetcher supports default winforms components. /// + /// A representing the asynchronous operation. [Fact] - public void ActivationForViewFetcherSupportsDefaultWinformsComponents() - { - var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); - var supportedComponents = new[] { typeof(Control), typeof(UserControl), typeof(Form) }; - - foreach (var c in supportedComponents) + public async Task ActivationForViewFetcherSupportsDefaultWinformsComponents() => + await RunAppBuilderTestAsync(() => { - Assert.Equal(10, target.GetAffinityForView(c)); - } - } + var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); + var supportedComponents = new[] { typeof(Control), typeof(UserControl), typeof(Form) }; + + foreach (var c in supportedComponents) + { + Assert.Equal(10, target.GetAffinityForView(c)); + } + }); /// /// Tests that determines whether this instance [can fetch activator for form]. /// + /// A representing the asynchronous operation. [Fact] - public void CanFetchActivatorForForm() - { - var form = new TestForm(); - var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); - var formActivator = target.GetActivationForView(form); + public async Task CanFetchActivatorForForm() => + await RunAppBuilderTestAsync(() => + { + var form = new TestForm(); + var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); + var formActivator = target.GetActivationForView(form); - Assert.NotNull(formActivator); - } + Assert.NotNull(formActivator); + }); /// /// Tests that determines whether this instance [can fetch activator for control]. /// + /// A representing the asynchronous operation. [Fact] - public void CanFetchActivatorForControl() - { - var control = new TestControl(); - var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); - var activator = target.GetActivationForView(control); + public async Task CanFetchActivatorForControl() => + await RunAppBuilderTestAsync(() => + { + var control = new TestControl(); + var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); + var activator = target.GetActivationForView(control); - Assert.NotNull(activator); - } + Assert.NotNull(activator); + }); /// /// Smokes the test windows form. /// + /// A representing the asynchronous operation. [Fact] - public void SmokeTestWindowsForm() - { - var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); - using (var form = new TestForm()) + public async Task SmokeTestWindowsForm() => + await RunAppBuilderTestAsync(() => { - var formActivator = target.GetActivationForView(form); - - int formActivateCount = 0, formDeActivateCount = 0; - formActivator.Subscribe(activated => + var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); + using (var form = new TestForm()) { - if (activated) - { - formActivateCount++; - } - else - { - formDeActivateCount++; - } - }); - - Assert.Equal(0, formActivateCount); - Assert.Equal(0, formDeActivateCount); - - form.Visible = true; - Assert.Equal(1, formActivateCount); - - form.Visible = false; - Assert.Equal(1, formActivateCount); - Assert.Equal(1, formDeActivateCount); - - form.Visible = true; - Assert.Equal(2, formActivateCount); + var formActivator = target.GetActivationForView(form); - form.Close(); - Assert.Equal(2, formDeActivateCount); - } - } + int formActivateCount = 0, formDeActivateCount = 0; + formActivator.Subscribe(activated => + { + if (activated) + { + formActivateCount++; + } + else + { + formDeActivateCount++; + } + }); + + Assert.Equal(0, formActivateCount); + Assert.Equal(0, formDeActivateCount); + + form.Visible = true; + Assert.Equal(1, formActivateCount); + + form.Visible = false; + Assert.Equal(1, formActivateCount); + Assert.Equal(1, formDeActivateCount); + + form.Visible = true; + Assert.Equal(2, formActivateCount); + + form.Close(); + Assert.Equal(2, formDeActivateCount); + } + }); /// /// Smokes the test user control. /// + /// A representing the asynchronous operation. [Fact] - public void SmokeTestUserControl() - { - var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); - using (var userControl = new TestControl()) - using (var parent = new TestForm()) + public async Task SmokeTestUserControl() => + await RunAppBuilderTestAsync(() => { - var userControlActivator = target.GetActivationForView(userControl); - - int userControlActivateCount = 0, userControlDeActivateCount = 0; - userControlActivator.Subscribe(activated => + var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); + using (var userControl = new TestControl()) + using (var parent = new TestForm()) { - if (activated) - { - userControlActivateCount++; - } - else + var userControlActivator = target.GetActivationForView(userControl); + + int userControlActivateCount = 0, userControlDeActivateCount = 0; + userControlActivator.Subscribe(activated => { - userControlDeActivateCount++; - } - }); - - parent.Visible = true; - parent.Controls.Add(userControl); - - userControl.Visible = true; - Assert.Equal(1, userControlActivateCount); - userControl.Visible = false; - Assert.Equal(1, userControlDeActivateCount); - - userControl.Visible = true; - Assert.Equal(2, userControlActivateCount); - - // closing the form deactivated the usercontrol - parent.Close(); - Assert.Equal(2, userControlDeActivateCount); - } - } + if (activated) + { + userControlActivateCount++; + } + else + { + userControlDeActivateCount++; + } + }); + + parent.Visible = true; + parent.Controls.Add(userControl); + + userControl.Visible = true; + Assert.Equal(1, userControlActivateCount); + userControl.Visible = false; + Assert.Equal(1, userControlDeActivateCount); + + userControl.Visible = true; + Assert.Equal(2, userControlActivateCount); + + // closing the form deactivated the usercontrol + parent.Close(); + Assert.Equal(2, userControlDeActivateCount); + } + }); } diff --git a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs index 5177943c04..88f170b7d2 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs @@ -4,42 +4,43 @@ // See the LICENSE file in the project root for full license information. using System.Windows.Forms; -using ReactiveUI.Testing; namespace ReactiveUI.Tests.Winforms; /// /// Checks the command bindings. /// -public class CommandBindingImplementationTests +public class CommandBindingImplementationTests : AppBuilderTestBase { /// /// Tests the command bind by name wireup. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBindByNameWireup() - { - var vm = new WinformCommandBindViewModel(); - var view = new WinformCommandBindView { ViewModel = vm }; - var fixture = new CommandBinderImplementation(); + public async Task CommandBindByNameWireup() => + await RunAppBuilderTestAsync(() => + { + var vm = new WinformCommandBindViewModel(); + var view = new WinformCommandBindView { ViewModel = vm }; + var fixture = new CommandBinderImplementation(); - var invokeCount = 0; - vm.Command1.Subscribe(_ => ++invokeCount); + var invokeCount = 0; + vm.Command1.Subscribe(_ => ++invokeCount); - var disp = fixture.BindCommand(vm, view, x => x.Command1, x => x.Command1); + var disp = fixture.BindCommand(vm, view, x => x.Command1, x => x.Command1); - view.Command1.PerformClick(); + view.Command1.PerformClick(); - Assert.Equal(1, invokeCount); + Assert.Equal(1, invokeCount); - var newCmd = ReactiveCommand.Create(() => { }); - vm.Command1 = newCmd; + var newCmd = ReactiveCommand.Create(() => { }); + vm.Command1 = newCmd; - view.Command1.PerformClick(); - Assert.Equal(1, invokeCount); + view.Command1.PerformClick(); + Assert.Equal(1, invokeCount); - disp.Dispose(); - } + disp.Dispose(); + }); /// /// Tests the command bind explicit event wire up. @@ -73,63 +74,65 @@ public async Task CommandBindToExplicitEventWireupAsync() } [Fact] - public void CommandBindByNameWireupWithParameter() - { - var vm = new WinformCommandBindViewModel(); - var view = new WinformCommandBindView { ViewModel = vm }; - ICommandBinderImplementation fixture = new CommandBinderImplementation(); + public async Task CommandBindByNameWireupWithParameter() => + await RunAppBuilderTestAsync(() => + { + var vm = new WinformCommandBindViewModel(); + var view = new WinformCommandBindView { ViewModel = vm }; + ICommandBinderImplementation fixture = new CommandBinderImplementation(); - var invokeCount = 0; - vm.Command3.Subscribe(_ => ++invokeCount); + var invokeCount = 0; + vm.Command3.Subscribe(_ => ++invokeCount); - var disp = CommandBinderImplementationMixins.BindCommand(fixture, vm, view, vm => vm.Command3, v => v.Command1, vm => vm.Parameter); + var disp = CommandBinderImplementationMixins.BindCommand(fixture, vm, view, vm => vm.Command3, v => v.Command1, vm => vm.Parameter); - view.Command1.PerformClick(); - Assert.Equal(1, invokeCount); - Assert.Equal(10, vm.ParameterResult); + view.Command1.PerformClick(); + Assert.Equal(1, invokeCount); + Assert.Equal(10, vm.ParameterResult); - // update the parameter to ensure its updated when the command is executed - vm.Parameter = 2; - view.Command1.PerformClick(); - Assert.Equal(2, invokeCount); - Assert.Equal(20, vm.ParameterResult); + // update the parameter to ensure its updated when the command is executed + vm.Parameter = 2; + view.Command1.PerformClick(); + Assert.Equal(2, invokeCount); + Assert.Equal(20, vm.ParameterResult); - // break the Command3 subscription - var newCmd = ReactiveCommand.Create(i => vm.ParameterResult = i * 2); - vm.Command3 = newCmd; + // break the Command3 subscription + var newCmd = ReactiveCommand.Create(i => vm.ParameterResult = i * 2); + vm.Command3 = newCmd; - // ensure that the invoke count does not update and that the Command3 is now using the new math - view.Command1.PerformClick(); - Assert.Equal(2, invokeCount); - Assert.Equal(4, vm.ParameterResult); + // ensure that the invoke count does not update and that the Command3 is now using the new math + view.Command1.PerformClick(); + Assert.Equal(2, invokeCount); + Assert.Equal(4, vm.ParameterResult); - disp.Dispose(); - } + disp.Dispose(); + }); [Fact] - public void CommandBindToExplicitEventWireupWithParameter() - { - var vm = new WinformCommandBindViewModel(); - var view = new WinformCommandBindView { ViewModel = vm }; - var fixture = new CommandBinderImplementation(); + public async Task CommandBindToExplicitEventWireupWithParameter() => + await RunAppBuilderTestAsync(() => + { + var vm = new WinformCommandBindViewModel(); + var view = new WinformCommandBindView { ViewModel = vm }; + var fixture = new CommandBinderImplementation(); - var invokeCount = 0; - vm.Command3.Subscribe(_ => ++invokeCount); + var invokeCount = 0; + vm.Command3.Subscribe(_ => ++invokeCount); - var disp = CommandBinderImplementationMixins.BindCommand(fixture, vm, view, x => x.Command3, x => x.Command2, vm => vm.Parameter, "MouseUp"); + var disp = CommandBinderImplementationMixins.BindCommand(fixture, vm, view, x => x.Command3, x => x.Command2, vm => vm.Parameter, "MouseUp"); - view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - Assert.Equal(10, vm.ParameterResult); - Assert.Equal(1, invokeCount); + view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); + Assert.Equal(10, vm.ParameterResult); + Assert.Equal(1, invokeCount); - vm.Parameter = 2; - view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - Assert.Equal(20, vm.ParameterResult); - Assert.Equal(2, invokeCount); + vm.Parameter = 2; + view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); + Assert.Equal(20, vm.ParameterResult); + Assert.Equal(2, invokeCount); - disp.Dispose(); + disp.Dispose(); - view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - Assert.Equal(2, invokeCount); - } + view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); + Assert.Equal(2, invokeCount); + }); } diff --git a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs index 87dd7f4f21..2f4acc4870 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs @@ -4,7 +4,6 @@ // See the LICENSE file in the project root for full license information. using System.Windows.Forms; -using ReactiveUI.Testing; using ReactiveUI.Winforms; using Splat.Builder; @@ -13,146 +12,150 @@ namespace ReactiveUI.Tests.Winforms; /// /// Command binding tests. /// -public class CommandBindingTests +public class CommandBindingTests : AppBuilderTestBase { /// /// Tests that the command binder binds to button. /// /// A representing the asynchronous unit test. [Fact] - public async Task CommandBinderBindsToButtonAsync() - { - AppBuilder.ResetBuilderStateForTests(); - using var testSequencer = new TestSequencer(); - var fixture = new CreatesWinformsCommandBinding(); - var cmd = ReactiveCommand.CreateRunInBackground(_ => { }); - var input = new Button(); - - Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); - Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); - var commandExecuted = false; - object? ea = null; - cmd.Subscribe(async o => + public async Task CommandBinderBindsToButtonAsync() => + await RunAppBuilderTestAsync(async () => { - ea = o; - commandExecuted = true; - await testSequencer.AdvancePhaseAsync("Phase 1"); + using var testSequencer = new TestSequencer(); + var fixture = new CreatesWinformsCommandBinding(); + var cmd = ReactiveCommand.CreateRunInBackground(_ => { }); + var input = new Button(); + + Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); + Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); + var commandExecuted = false; + object? ea = null; + cmd.Subscribe(async o => + { + ea = o; + commandExecuted = true; + await testSequencer.AdvancePhaseAsync("Phase 1"); + }); + + using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + { + input.PerformClick(); + await testSequencer.AdvancePhaseAsync("Phase 1"); + Assert.True(commandExecuted); + Assert.NotNull(ea); + } }); - using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) - { - input.PerformClick(); - await testSequencer.AdvancePhaseAsync("Phase 1"); - Assert.True(commandExecuted); - Assert.NotNull(ea); - } - } - /// /// Tests that the command binder binds to custom control. /// + /// A representing the asynchronous unit test. [Fact] - public void CommandBinderBindsToCustomControl() - { - AppBuilder.ResetBuilderStateForTests(); - var fixture = new CreatesWinformsCommandBinding(); - var cmd = ReactiveCommand.Create(_ => { }); - var input = new CustomClickableControl(); - - Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); - Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); - var commandExecuted = false; - object? ea = null; - cmd.Subscribe(o => + public async Task CommandBinderBindsToCustomControl() => + await RunAppBuilderTestAsync(() => { - ea = o; - commandExecuted = true; + var fixture = new CreatesWinformsCommandBinding(); + var cmd = ReactiveCommand.Create(_ => { }); + var input = new CustomClickableControl(); + + Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); + Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); + var commandExecuted = false; + object? ea = null; + cmd.Subscribe(o => + { + ea = o; + commandExecuted = true; + }); + + using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + { + input.PerformClick(); + + Assert.True(commandExecuted); + Assert.NotNull(ea); + } }); - using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) - { - input.PerformClick(); - - Assert.True(commandExecuted); - Assert.NotNull(ea); - } - } - /// /// Tests that the command binder binds to custom component. /// + /// A representing the asynchronous unit test. [Fact] - public void CommandBinderBindsToCustomComponent() - { - AppBuilder.ResetBuilderStateForTests(); - var fixture = new CreatesWinformsCommandBinding(); - var cmd = ReactiveCommand.Create(_ => { }); - var input = new CustomClickableComponent(); - - Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); - Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); - var commandExecuted = false; - object? ea = null; - cmd.Subscribe(o => + public async Task CommandBinderBindsToCustomComponent() => + await RunAppBuilderTestAsync(() => { - ea = o; - commandExecuted = true; + var fixture = new CreatesWinformsCommandBinding(); + var cmd = ReactiveCommand.Create(_ => { }); + var input = new CustomClickableComponent(); + + Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); + Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); + var commandExecuted = false; + object? ea = null; + cmd.Subscribe(o => + { + ea = o; + commandExecuted = true; + }); + + using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + { + input.PerformClick(); + + Assert.True(commandExecuted); + Assert.NotNull(ea); + } }); - using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) - { - input.PerformClick(); - - Assert.True(commandExecuted); - Assert.NotNull(ea); - } - } - /// /// Tests that the command binder affects enabled. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBinderAffectsEnabledState() - { - AppBuilder.ResetBuilderStateForTests(); - var fixture = new CreatesWinformsCommandBinding(); - var canExecute = new Subject(); - canExecute.OnNext(true); - - var cmd = ReactiveCommand.Create(() => { }, canExecute); - var input = new Button(); - - using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + public async Task CommandBinderAffectsEnabledState() => + await RunAppBuilderTestAsync(() => { + var fixture = new CreatesWinformsCommandBinding(); + var canExecute = new Subject(); canExecute.OnNext(true); - Assert.True(input.Enabled); - canExecute.OnNext(false); - Assert.False(input.Enabled); - } - } + var cmd = ReactiveCommand.Create(() => { }, canExecute); + var input = new Button(); + + using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + { + canExecute.OnNext(true); + Assert.True(input.Enabled); + + canExecute.OnNext(false); + Assert.False(input.Enabled); + } + }); /// /// Tests that the command binder affects enabled state for components. /// + /// A representing the asynchronous operation. [Fact] - public void CommandBinderAffectsEnabledStateForComponents() - { - AppBuilder.ResetBuilderStateForTests(); - var fixture = new CreatesWinformsCommandBinding(); - var canExecute = new Subject(); - canExecute.OnNext(true); - - var cmd = ReactiveCommand.Create(() => { }, canExecute); - var input = new ToolStripButton(); // ToolStripButton is a Component, not a Control - - using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + public async Task CommandBinderAffectsEnabledStateForComponents() => + await RunAppBuilderTestAsync(() => { + var fixture = new CreatesWinformsCommandBinding(); + var canExecute = new Subject(); canExecute.OnNext(true); - Assert.True(input.Enabled); - canExecute.OnNext(false); - Assert.False(input.Enabled); - } - } + var cmd = ReactiveCommand.Create(() => { }, canExecute); + var input = new ToolStripButton(); // ToolStripButton is a Component, not a Control + + using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + { + canExecute.OnNext(true); + Assert.True(input.Enabled); + + canExecute.OnNext(false); + Assert.False(input.Enabled); + } + }); } diff --git a/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs index ee3382a83f..c60a54749b 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs @@ -4,7 +4,6 @@ // See the LICENSE file in the project root for full license information. using ReactiveUI.Builder; -using ReactiveUI.Winforms; using Splat.Builder; namespace ReactiveUI.Tests.Platforms.Winforms; @@ -12,53 +11,53 @@ namespace ReactiveUI.Tests.Platforms.Winforms; /// /// Tests for WinForms-specific ReactiveUIBuilder functionality. /// -public class ReactiveUIBuilderWinFormsTests +public class ReactiveUIBuilderWinFormsTests : AppBuilderTestBase { /// /// Test that WinForms services can be registered using the builder. /// + /// A representing the asynchronous operation. [Fact] - public void WithWinForms_Should_Register_WinForms_Services() - { - AppBuilder.ResetBuilderStateForTests(); + public async Task WithWinForms_Should_Register_WinForms_Services() => + await RunAppBuilderTestAsync(() => + { + // Arrange + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - // Arrange - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + // Act + builder.WithWinForms().Build(); - // Act - builder.WithWinForms().Build(); + // Assert + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); - // Assert - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - - var activationFetcher = locator.GetService(); - Assert.NotNull(activationFetcher); - } + var activationFetcher = locator.GetService(); + Assert.NotNull(activationFetcher); + }); /// /// Test that the builder can chain WinForms registration with core services. /// + /// A representing the asynchronous operation. [Fact] - public void WithCoreServices_AndWinForms_Should_Register_All_Services() - { - AppBuilder.ResetBuilderStateForTests(); - - // Arrange - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - - // Act - builder.WithWinForms().Build(); - - // Assert - // Core services - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); - - // WinForms-specific services - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - } + public async Task WithCoreServices_AndWinForms_Should_Register_All_Services() => + await RunAppBuilderTestAsync(() => + { + // Arrange + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + + // Act + builder.WithWinForms().Build(); + + // Assert + // Core services + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); + + // WinForms-specific services + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); + }); } diff --git a/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs index 5aeec4f94f..2b7570504a 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs @@ -14,8 +14,6 @@ public sealed class WinFormsViewDependencyResolverTests : IDisposable public WinFormsViewDependencyResolverTests() { - AppBuilder.ResetBuilderStateForTests(); - // Reset static counters to avoid cross-test interference when running entire suite SingleInstanceExampleView.ResetInstances(); SingleInstanceWithContractExampleView.ResetInstances(); diff --git a/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs b/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs index 4409b87946..907f35601a 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.Tests.Platforms.Wpf; /// /// Tests for WPF-specific ReactiveUIBuilder functionality. /// -public class ReactiveUIBuilderWpfTests +public class ReactiveUIBuilderWpfTests : AppBuilderTestBase { /// /// Initializes a new instance of the class. @@ -23,48 +23,48 @@ public ReactiveUIBuilderWpfTests() /// /// Test that WPF services can be registered using the builder. /// + /// A representing the asynchronous operation. [Fact] - public void WithWpf_Should_Register_Wpf_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - - // Arrange - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task WithWpf_Should_Register_Wpf_Services() => + await RunAppBuilderTestAsync(() => + { + // Arrange + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - // Act - builder.WithWpf().Build(); + // Act + builder.WithWpf().Build(); - // Assert - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); + // Assert + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); - var activationFetcher = locator.GetService(); - Assert.NotNull(activationFetcher); - } + var activationFetcher = locator.GetService(); + Assert.NotNull(activationFetcher); + }); /// /// Test that the builder can chain WPF registration with core services. /// + /// A representing the asynchronous operation. [Fact] - public void WithCoreServices_AndWpf_Should_Register_All_Services() - { - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - - // Arrange - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public async Task WithCoreServices_AndWpf_Should_Register_All_Services() => + await RunAppBuilderTestAsync(() => + { + // Arrange + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - // Act - builder.WithWpf().Build(); + // Act + builder.WithWpf().Build(); - // Assert - // Core services - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); + // Assert + // Core services + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - // WPF-specific services - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - } + // WPF-specific services + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); + }); } diff --git a/src/ReactiveUI.Tests/Platforms/wpf/WpfActivationForViewFetcherTest.cs b/src/ReactiveUI.Tests/Platforms/wpf/WpfActivationForViewFetcherTest.cs index 2721e3380e..d581524b36 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/WpfActivationForViewFetcherTest.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/WpfActivationForViewFetcherTest.cs @@ -11,132 +11,152 @@ namespace ReactiveUI.Tests.Wpf; -public class WpfActivationForViewFetcherTest +public class WpfActivationForViewFetcherTest : AppBuilderTestBase { + /// + /// Ensures FrameworkElement is activated and then deactivated. + /// + /// A representing the asynchronous operation. [Fact] - public void FrameworkElementIsActivatedAndDeactivated() - { - var uc = new WpfTestUserControl(); - var activation = new ActivationForViewFetcher(); + public async Task FrameworkElementIsActivatedAndDeactivated() => + await RunAppBuilderTestAsync(() => + { + var uc = new WpfTestUserControl(); + var activation = new ActivationForViewFetcher(); - var obs = activation.GetActivationForView(uc); - obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + var obs = activation.GetActivationForView(uc); + obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; - uc.RaiseEvent(loaded); + uc.RaiseEvent(loaded); - new[] { true }.AssertAreEqual(activated); + new[] { true }.AssertAreEqual(activated); - var unloaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.UnloadedEvent - }; + var unloaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.UnloadedEvent + }; - uc.RaiseEvent(unloaded); + uc.RaiseEvent(unloaded); - new[] { true, false }.AssertAreEqual(activated); - } + new[] { true, false }.AssertAreEqual(activated); + }); + /// + /// Ensures IsHitTestVisible activates FrameworkElement correctly. + /// + /// A representing the asynchronous operation. [Fact] - public void IsHitTestVisibleActivatesFrameworkElement() - { - var uc = new WpfTestUserControl + public async Task IsHitTestVisibleActivatesFrameworkElement() => + await RunAppBuilderTestAsync(() => { - IsHitTestVisible = false - }; - var activation = new ActivationForViewFetcher(); + var uc = new WpfTestUserControl + { + IsHitTestVisible = false + }; + var activation = new ActivationForViewFetcher(); - var obs = activation.GetActivationForView(uc); - obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + var obs = activation.GetActivationForView(uc); + obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; - uc.RaiseEvent(loaded); + uc.RaiseEvent(loaded); - // Loaded has happened. - new[] { true }.AssertAreEqual(activated); + // Loaded has happened. + new[] { true }.AssertAreEqual(activated); - uc.IsHitTestVisible = true; + uc.IsHitTestVisible = true; - // IsHitTestVisible true, we don't want the event to repeat unnecessarily. - new[] { true }.AssertAreEqual(activated); + // IsHitTestVisible true, we don't want the event to repeat unnecessarily. + new[] { true }.AssertAreEqual(activated); - var unloaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.UnloadedEvent - }; + var unloaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.UnloadedEvent + }; - uc.RaiseEvent(unloaded); + uc.RaiseEvent(unloaded); - // We had both a loaded/hit test visible change/unloaded happen. - new[] { true, false }.AssertAreEqual(activated); - } + // We had both a loaded/hit test visible change/unloaded happen. + new[] { true, false }.AssertAreEqual(activated); + }); + /// + /// Ensures IsHitTestVisible deactivates FrameworkElement correctly. + /// + /// A representing the asynchronous operation. [Fact] - public void IsHitTestVisibleDeactivatesFrameworkElement() - { - var uc = new WpfTestUserControl(); - var activation = new ActivationForViewFetcher(); + public async Task IsHitTestVisibleDeactivatesFrameworkElement() => + await RunAppBuilderTestAsync(() => + { + var uc = new WpfTestUserControl(); + var activation = new ActivationForViewFetcher(); - var obs = activation.GetActivationForView(uc); - obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + var obs = activation.GetActivationForView(uc); + obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; - uc.RaiseEvent(loaded); + uc.RaiseEvent(loaded); - new[] { true }.AssertAreEqual(activated); + new[] { true }.AssertAreEqual(activated); - uc.IsHitTestVisible = false; + uc.IsHitTestVisible = false; - new[] { true, false }.AssertAreEqual(activated); - } + new[] { true, false }.AssertAreEqual(activated); + }); + /// + /// Ensures FrameworkElement activation and deactivation with hit test visibility changes. + /// + /// A representing the asynchronous operation. [Fact] - public void FrameworkElementIsActivatedAndDeactivatedWithHitTest() - { - var uc = new WpfTestUserControl(); - var activation = new ActivationForViewFetcher(); + public async Task FrameworkElementIsActivatedAndDeactivatedWithHitTest() => + await RunAppBuilderTestAsync(() => + { + var uc = new WpfTestUserControl(); + var activation = new ActivationForViewFetcher(); - var obs = activation.GetActivationForView(uc); - obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + var obs = activation.GetActivationForView(uc); + obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; - uc.RaiseEvent(loaded); + uc.RaiseEvent(loaded); - new[] { true }.AssertAreEqual(activated); + new[] { true }.AssertAreEqual(activated); - // this should deactivate it - uc.IsHitTestVisible = false; + // this should deactivate it + uc.IsHitTestVisible = false; - new[] { true, false }.AssertAreEqual(activated); + new[] { true, false }.AssertAreEqual(activated); - // this should activate it - uc.IsHitTestVisible = true; + // this should activate it + uc.IsHitTestVisible = true; - new[] { true, false, true }.AssertAreEqual(activated); + new[] { true, false, true }.AssertAreEqual(activated); - var unloaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.UnloadedEvent - }; + var unloaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.UnloadedEvent + }; - uc.RaiseEvent(unloaded); + uc.RaiseEvent(unloaded); - new[] { true, false, true, false }.AssertAreEqual(activated); - } + new[] { true, false, true, false }.AssertAreEqual(activated); + }); } diff --git a/src/ReactiveUI.Tests/Platforms/wpf/WpfActiveContentTests.cs b/src/ReactiveUI.Tests/Platforms/wpf/WpfActiveContentTests.cs index aa6261c9d1..ed9f632232 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/WpfActiveContentTests.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/WpfActiveContentTests.cs @@ -5,7 +5,6 @@ using System.Windows; using DynamicData; -using ReactiveUI.Testing; namespace ReactiveUI.Tests.Wpf; @@ -18,7 +17,7 @@ namespace ReactiveUI.Tests.Wpf; /// Initializes a new instance of the class. /// /// The fixture. -public class WpfActiveContentTests(WpfActiveContentFixture fixture) : IClassFixture +public class WpfActiveContentTests(WpfActiveContentFixture fixture) : AppBuilderTestBase, IClassFixture { /// /// Gets the fixture. @@ -31,313 +30,331 @@ public class WpfActiveContentTests(WpfActiveContentFixture fixture) : IClassFixt [StaFact] public void BindListFunctionalTest() { - var window = Fixture?.App?.WpfTestWindowFactory(); - var view = new MockBindListView(); - window!.RootGrid.Children.Add(view); - - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; - - window.RaiseEvent(loaded); - view.RaiseEvent(loaded); - var test1 = new MockBindListItemViewModel("Test1"); - view.ViewModel?.ActiveListItem.Add(test1); - Assert.Equal(1, view.ItemList.Items.Count); - Assert.Equal(test1, view.ViewModel!.ActiveItem); - - var test2 = new MockBindListItemViewModel("Test2"); - view.ViewModel?.ActiveListItem.Add(test2); - Assert.Equal(2, view.ItemList.Items.Count); - Assert.Equal(test2, view.ViewModel!.ActiveItem); - - var test3 = new MockBindListItemViewModel("Test3"); - view.ViewModel?.ActiveListItem.Add(test3); - Assert.Equal(3, view.ItemList.Items.Count); - Assert.Equal(test3, view.ViewModel!.ActiveItem); - - view.ItemList.SelectedItem = view.ItemList.Items.GetItemAt(0); - Assert.Equal(1, view.ItemList.Items.Count); - Assert.Equal(test1, view.ViewModel!.ActiveItem); - - window.Close(); - } - - [StaFact] - public void ViewModelHostViewTestFallback() - { - var oldLocator = Locator.GetLocator(); - - var resolver = new ModernDependencyResolver(); - resolver.InitializeSplat(); - resolver.InitializeReactiveUI(); - - // test the resolving behavior - using (resolver.WithResolver()) - { - ResolveViewBIfViewBIsRegistered(resolver); - ResolveView0WithFallbck(resolver); - ResolveNoneWithFallbckByPass(resolver); - } - - void ResolveViewBIfViewBIsRegistered(ModernDependencyResolver resolver) + RunAppBuilderTestAsync(() => { - resolver.Register(() => new FakeViewWithContract.View0(), typeof(IViewFor)); - resolver.Register(() => new FakeViewWithContract.ViewA(), typeof(IViewFor), FakeViewWithContract.ContractA); - resolver.Register(() => new FakeViewWithContract.ViewB(), typeof(IViewFor), FakeViewWithContract.ContractB); - var window = Fixture?.App?.WpfTestWindowFactory(); - - var viewmodel = new FakeViewWithContract.MyViewModel(); - var vmvhost = new ViewModelViewHost() - { - ViewModel = viewmodel, - ViewContract = FakeViewWithContract.ContractB, - }; - window!.RootGrid.Children.Clear(); - window!.RootGrid.Children.Add(vmvhost); + var view = new MockBindListView(); + window!.RootGrid.Children.Add(view); var loaded = new RoutedEventArgs { RoutedEvent = FrameworkElement.LoadedEvent }; + window.RaiseEvent(loaded); - vmvhost.RaiseEvent(loaded); + view.RaiseEvent(loaded); + var test1 = new MockBindListItemViewModel("Test1"); + view.ViewModel?.ActiveListItem.Add(test1); + Assert.Equal(1, view.ItemList.Items.Count); + Assert.Equal(test1, view.ViewModel!.ActiveItem); + + var test2 = new MockBindListItemViewModel("Test2"); + view.ViewModel?.ActiveListItem.Add(test2); + Assert.Equal(2, view.ItemList.Items.Count); + Assert.Equal(test2, view.ViewModel!.ActiveItem); + + var test3 = new MockBindListItemViewModel("Test3"); + view.ViewModel?.ActiveListItem.Add(test3); + Assert.Equal(3, view.ItemList.Items.Count); + Assert.Equal(test3, view.ViewModel!.ActiveItem); + + view.ItemList.SelectedItem = view.ItemList.Items.GetItemAt(0); + Assert.Equal(1, view.ItemList.Items.Count); + Assert.Equal(test1, view.ViewModel!.ActiveItem); - Assert.NotNull(vmvhost.Content); - Assert.IsType(typeof(FakeViewWithContract.ViewB), vmvhost.Content); window.Close(); - } + }).GetAwaiter().GetResult(); + } - void ResolveView0WithFallbck(ModernDependencyResolver resolver) + [StaFact] + public void ViewModelHostViewTestFallback() + { + RunAppBuilderTestAsync(() => { - resolver.UnregisterCurrent(typeof(IViewFor), FakeViewWithContract.ContractB); + var oldLocator = Locator.GetLocator(); - var window = Fixture?.App?.WpfTestWindowFactory(); + var resolver = new ModernDependencyResolver(); + resolver.InitializeSplat(); + resolver.InitializeReactiveUI(); - var viewmodel = new FakeViewWithContract.MyViewModel(); - var vmvhost = new ViewModelViewHost() + // test the resolving behavior + using (resolver.WithResolver()) { - ViewModel = viewmodel, - ViewContract = FakeViewWithContract.ContractB, - ContractFallbackByPass = false, - }; - window!.RootGrid.Children.Clear(); - window!.RootGrid.Children.Add(vmvhost); + ResolveViewBIfViewBIsRegistered(resolver); + ResolveView0WithFallbck(resolver); + ResolveNoneWithFallbckByPass(resolver); + } - var loaded = new RoutedEventArgs + void ResolveViewBIfViewBIsRegistered(ModernDependencyResolver resolver) { - RoutedEvent = FrameworkElement.LoadedEvent - }; - window.RaiseEvent(loaded); - vmvhost.RaiseEvent(loaded); + resolver.Register(() => new FakeViewWithContract.View0(), typeof(IViewFor)); + resolver.Register(() => new FakeViewWithContract.ViewA(), typeof(IViewFor), FakeViewWithContract.ContractA); + resolver.Register(() => new FakeViewWithContract.ViewB(), typeof(IViewFor), FakeViewWithContract.ContractB); - Assert.NotNull(vmvhost.Content); - Assert.IsType(typeof(FakeViewWithContract.View0), vmvhost.Content); - window.Close(); - } + var window = Fixture?.App?.WpfTestWindowFactory(); - void ResolveNoneWithFallbckByPass(ModernDependencyResolver resolver) - { - resolver.UnregisterCurrent(typeof(IViewFor), FakeViewWithContract.ContractB); + var viewmodel = new FakeViewWithContract.MyViewModel(); + var vmvhost = new ViewModelViewHost() + { + ViewModel = viewmodel, + ViewContract = FakeViewWithContract.ContractB, + }; + window!.RootGrid.Children.Clear(); + window!.RootGrid.Children.Add(vmvhost); - var window = Fixture?.App?.WpfTestWindowFactory(); + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; + window.RaiseEvent(loaded); + vmvhost.RaiseEvent(loaded); + + Assert.NotNull(vmvhost.Content); + Assert.IsType(typeof(FakeViewWithContract.ViewB), vmvhost.Content); + window.Close(); + } - var viewmodel = new FakeViewWithContract.MyViewModel(); - var vmvhost = new ViewModelViewHost() + void ResolveView0WithFallbck(ModernDependencyResolver resolver) { - ViewModel = viewmodel, - ViewContract = FakeViewWithContract.ContractB, - ContractFallbackByPass = true, - }; - window!.RootGrid.Children.Clear(); - window!.RootGrid.Children.Add(vmvhost); + resolver.UnregisterCurrent(typeof(IViewFor), FakeViewWithContract.ContractB); - var loaded = new RoutedEventArgs + var window = Fixture?.App?.WpfTestWindowFactory(); + + var viewmodel = new FakeViewWithContract.MyViewModel(); + var vmvhost = new ViewModelViewHost() + { + ViewModel = viewmodel, + ViewContract = FakeViewWithContract.ContractB, + ContractFallbackByPass = false, + }; + window!.RootGrid.Children.Clear(); + window!.RootGrid.Children.Add(vmvhost); + + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; + window.RaiseEvent(loaded); + vmvhost.RaiseEvent(loaded); + + Assert.NotNull(vmvhost.Content); + Assert.IsType(typeof(FakeViewWithContract.View0), vmvhost.Content); + window.Close(); + } + + void ResolveNoneWithFallbckByPass(ModernDependencyResolver resolver) { - RoutedEvent = FrameworkElement.LoadedEvent - }; - window.RaiseEvent(loaded); - vmvhost.RaiseEvent(loaded); + resolver.UnregisterCurrent(typeof(IViewFor), FakeViewWithContract.ContractB); - Assert.Null(vmvhost.Content); - window.Close(); - } + var window = Fixture?.App?.WpfTestWindowFactory(); + + var viewmodel = new FakeViewWithContract.MyViewModel(); + var vmvhost = new ViewModelViewHost() + { + ViewModel = viewmodel, + ViewContract = FakeViewWithContract.ContractB, + ContractFallbackByPass = true, + }; + window!.RootGrid.Children.Clear(); + window!.RootGrid.Children.Add(vmvhost); + + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; + window.RaiseEvent(loaded); + vmvhost.RaiseEvent(loaded); + + Assert.Null(vmvhost.Content); + window.Close(); + } + }).GetAwaiter().GetResult(); } [StaFact] public void TransitioningContentControlTest() { - var window = Fixture?.App?.MockWindowFactory(); - window!.WhenActivated(async _ => + RunAppBuilderTestAsync(() => { - window!.TransitioningContent.Duration = TimeSpan.FromMilliseconds(200); - var transitioning = false; - window.TransitioningContent.TransitionStarted += (s, e) => transitioning = true; - - window.TransitioningContent.TransitionCompleted += (s, e) => transitioning = false; - - await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); - - async Task TestTransiton() + var window = Fixture?.App?.MockWindowFactory(); + window!.WhenActivated(async _ => { - var view = new View1(); - window.TransitioningContent.Content = view; - Assert.True(transitioning); - while (transitioning) + window!.TransitioningContent.Duration = TimeSpan.FromMilliseconds(200); + var transitioning = false; + window.TransitioningContent.TransitionStarted += (s, e) => transitioning = true; + + window.TransitioningContent.TransitionCompleted += (s, e) => transitioning = false; + + await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); + + async Task TestTransiton() { - await Task.Delay(5).ConfigureAwait(true); - } + var view = new View1(); + window.TransitioningContent.Content = view; + Assert.True(transitioning); + while (transitioning) + { + await Task.Delay(5).ConfigureAwait(true); + } - Assert.Equal(window.TransitioningContent.Content, view); - Assert.False(transitioning); + Assert.Equal(window.TransitioningContent.Content, view); + Assert.False(transitioning); - var view2 = new View2(); - window.TransitioningContent.Content = view2; - Assert.True(transitioning); - while (transitioning) - { - await Task.Delay(5).ConfigureAwait(true); - } + var view2 = new View2(); + window.TransitioningContent.Content = view2; + Assert.True(transitioning); + while (transitioning) + { + await Task.Delay(5).ConfigureAwait(true); + } - Assert.Equal(window.TransitioningContent.Content, view2); - Assert.False(transitioning); - } + Assert.Equal(window.TransitioningContent.Content, view2); + Assert.False(transitioning); + } - async Task TestCyle(TransitioningContentControl.TransitionDirection direction, TransitioningContentControl.TransitionType transition) - { - window.TransitioningContent.Direction = direction; - window.TransitioningContent.Transition = transition; - Assert.Equal(window.TransitioningContent.Direction, direction); - Assert.Equal(window.TransitioningContent.Transition, transition); - await TestTransiton().ConfigureAwait(true); - await TestTransiton().ConfigureAwait(true); - } + async Task TestCyle(TransitioningContentControl.TransitionDirection direction, TransitioningContentControl.TransitionType transition) + { + window.TransitioningContent.Direction = direction; + window.TransitioningContent.Transition = transition; + Assert.Equal(window.TransitioningContent.Direction, direction); + Assert.Equal(window.TransitioningContent.Transition, transition); + await TestTransiton().ConfigureAwait(true); + await TestTransiton().ConfigureAwait(true); + } - window.Close(); - }); - window!.ShowDialog(); + window.Close(); + }); + window!.ShowDialog(); + }).GetAwaiter().GetResult(); } [Fact] public void DummySuspensionDriverTest() { - var dsd = new DummySuspensionDriver(); - dsd.LoadState().Select(_ => 1).Subscribe(_ => Assert.Equal(1, _)); - dsd.SaveState("Save Me").Select(_ => 2).Subscribe(_ => Assert.Equal(2, _)); - dsd.InvalidateState().Select(_ => 3).Subscribe(_ => Assert.Equal(3, _)); + RunAppBuilderTestAsync(() => + { + var dsd = new DummySuspensionDriver(); + dsd.LoadState().Select(_ => 1).Subscribe(_ => Assert.Equal(1, _)); + dsd.SaveState("Save Me").Select(_ => 2).Subscribe(_ => Assert.Equal(2, _)); + dsd.InvalidateState().Select(_ => 3).Subscribe(_ => Assert.Equal(3, _)); + }).GetAwaiter().GetResult(); } [StaFact] public void TransitioninContentControlDpiTest() { - var window = Fixture?.App?.TCMockWindowFactory(); - const int delay = 2000; - - window!.WhenActivated(async _ => + RunAppBuilderTestAsync(() => { - TransitioningContentControl.OverrideDpi = true; - window!.TransitioningContent.Height = 500; - window.TransitioningContent.Width = 500; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Height = 300; - window.TransitioningContent.Width = 300; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - window.TransitioningContent.Height = 0.25; - window.TransitioningContent.Width = 0.25; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - window.TransitioningContent.Height = 500; - window.TransitioningContent.Width = 500; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Height = 300; - window.TransitioningContent.Width = 300; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - window.TransitioningContent.Height = 0.25; - window.TransitioningContent.Width = 0.25; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - window.Close(); - }); - window!.ShowDialog(); + var window = Fixture?.App?.TCMockWindowFactory(); + const int delay = 2000; + + window!.WhenActivated(async _ => + { + TransitioningContentControl.OverrideDpi = true; + window!.TransitioningContent.Height = 500; + window.TransitioningContent.Width = 500; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Height = 300; + window.TransitioningContent.Width = 300; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + window.TransitioningContent.Height = 0.25; + window.TransitioningContent.Width = 0.25; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + window.TransitioningContent.Height = 500; + window.TransitioningContent.Width = 500; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Height = 300; + window.TransitioningContent.Width = 300; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + window.TransitioningContent.Height = 0.25; + window.TransitioningContent.Width = 0.25; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + window.Close(); + }); + window!.ShowDialog(); + }).GetAwaiter().GetResult(); } [StaFact] public void ReactiveCommandRunningOnTaskThreadAllowsCanExecuteAndExecutingToFire() { - LiveModeDetector.UseRuntimeThreads(); - var window = Fixture?.App?.MockWindowFactory(); - window!.WhenActivated(async d => + RunAppBuilderTestAsync(() => { - try + LiveModeDetector.UseRuntimeThreads(); + var window = Fixture?.App?.MockWindowFactory(); + window!.WhenActivated(async d => { - using var testSequencer = new TestSequencer(); - window!.TransitioningContent.VerticalContentAlignment = VerticalAlignment.Stretch; - window!.TransitioningContent.HorizontalContentAlignment = HorizontalAlignment.Stretch; - var view = new CanExecuteExecutingView(); - window!.TransitioningContent.Content = view; - await Task.Delay(2000).ConfigureAwait(true); - - var isExecutingExecuted = false; - view!.ViewModel!.Command3.IsExecuting - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(value => + try { - if (value) + using var testSequencer = new TestSequencer(); + window!.TransitioningContent.VerticalContentAlignment = VerticalAlignment.Stretch; + window!.TransitioningContent.HorizontalContentAlignment = HorizontalAlignment.Stretch; + var view = new CanExecuteExecutingView(); + window!.TransitioningContent.Content = view; + await Task.Delay(2000).ConfigureAwait(true); + + var isExecutingExecuted = false; + view!.ViewModel!.Command3.IsExecuting + .ObserveOn(RxApp.MainThreadScheduler) + .Subscribe(value => { - isExecutingExecuted = true; - } - }).DisposeWith(d); - - int? result = null; - view!.ViewModel!.Command3.Subscribe(async r => - { - result = r; + if (value) + { + isExecutingExecuted = true; + } + }).DisposeWith(d); + + int? result = null; + view!.ViewModel!.Command3.Subscribe(async r => + { + result = r; + await testSequencer.AdvancePhaseAsync(); + }); + await view!.ViewModel!.Command3.Execute(); await testSequencer.AdvancePhaseAsync(); - }); - await view!.ViewModel!.Command3.Execute(); - await testSequencer.AdvancePhaseAsync(); - Assert.Equal(100, result); - Assert.True(isExecutingExecuted); - } - finally - { - window?.Close(); - LiveModeDetector.UseDefaultModeDetector(); - } - }); - window!.ShowDialog(); + Assert.Equal(100, result); + Assert.True(isExecutingExecuted); + } + finally + { + window?.Close(); + LiveModeDetector.UseDefaultModeDetector(); + } + }); + window!.ShowDialog(); + }).GetAwaiter().GetResult(); } } diff --git a/src/ReactiveUI.Tests/TestConfiguration.cs b/src/ReactiveUI.Tests/Properties/TestConfiguration.cs similarity index 100% rename from src/ReactiveUI.Tests/TestConfiguration.cs rename to src/ReactiveUI.Tests/Properties/TestConfiguration.cs diff --git a/src/ReactiveUI.Tests/ReactiveObject/ReactiveObjectTests.cs b/src/ReactiveUI.Tests/ReactiveObject/ReactiveObjectTests.cs index 825295fad8..0dc733ce61 100644 --- a/src/ReactiveUI.Tests/ReactiveObject/ReactiveObjectTests.cs +++ b/src/ReactiveUI.Tests/ReactiveObject/ReactiveObjectTests.cs @@ -12,7 +12,7 @@ namespace ReactiveUI.Tests; /// /// Tests for the reactive object. /// -public class ReactiveObjectTests +public class ReactiveObjectTests : AppBuilderTestBase { /// /// Test that changing values should always arrive before changed. diff --git a/src/ReactiveUI.Tests/ReactiveProperty/ReactivePropertyTest.cs b/src/ReactiveUI.Tests/ReactiveProperty/ReactivePropertyTest.cs index 7fb92d8cad..13006bab93 100644 --- a/src/ReactiveUI.Tests/ReactiveProperty/ReactivePropertyTest.cs +++ b/src/ReactiveUI.Tests/ReactiveProperty/ReactivePropertyTest.cs @@ -6,12 +6,11 @@ using System.Collections; using FluentAssertions; using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; using ReactiveUI.Tests.ReactiveProperty.Mocks; namespace ReactiveUI.Tests.ReactiveProperty; -public class ReactivePropertyTest : ReactiveTest +public class ReactivePropertyTest : AppBuilderTestBase { [Fact] public void DefaultValueIsRaisedOnSubscribe() diff --git a/src/ReactiveUI.Tests/Resolvers/DependencyResolverTests.cs b/src/ReactiveUI.Tests/Resolvers/DependencyResolverTests.cs index dd80df12a8..f472aa82e7 100644 --- a/src/ReactiveUI.Tests/Resolvers/DependencyResolverTests.cs +++ b/src/ReactiveUI.Tests/Resolvers/DependencyResolverTests.cs @@ -7,7 +7,7 @@ namespace ReactiveUI.Tests; -public sealed class DependencyResolverTests +public sealed class DependencyResolverTests : AppBuilderTestBase { /// /// Gets RegistrationNamespaces. diff --git a/src/ReactiveUI.Tests/Resolvers/INPCObservableForPropertyTests.cs b/src/ReactiveUI.Tests/Resolvers/INPCObservableForPropertyTests.cs index dd7664f87f..d363a1098b 100644 --- a/src/ReactiveUI.Tests/Resolvers/INPCObservableForPropertyTests.cs +++ b/src/ReactiveUI.Tests/Resolvers/INPCObservableForPropertyTests.cs @@ -7,7 +7,7 @@ namespace ReactiveUI.Tests; -public class INPCObservableForPropertyTests +public class INPCObservableForPropertyTests : AppBuilderTestBase { [Fact] public void CheckGetAffinityForObjectValues() diff --git a/src/ReactiveUI.Tests/Resolvers/PocoObservableForPropertyTests.cs b/src/ReactiveUI.Tests/Resolvers/PocoObservableForPropertyTests.cs index 282df06d1c..7a2c1f5aae 100644 --- a/src/ReactiveUI.Tests/Resolvers/PocoObservableForPropertyTests.cs +++ b/src/ReactiveUI.Tests/Resolvers/PocoObservableForPropertyTests.cs @@ -5,7 +5,7 @@ namespace ReactiveUI.Tests; -public class PocoObservableForPropertyTests +public class PocoObservableForPropertyTests : AppBuilderTestBase { #pragma warning disable CA1812 // Class is not instantiated diff --git a/src/ReactiveUI.Tests/Routing/RoutableViewModelMixinTests.cs b/src/ReactiveUI.Tests/Routing/RoutableViewModelMixinTests.cs index 4abe7940fa..8208619300 100644 --- a/src/ReactiveUI.Tests/Routing/RoutableViewModelMixinTests.cs +++ b/src/ReactiveUI.Tests/Routing/RoutableViewModelMixinTests.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Routable ViewModel MixinTests. /// -public class RoutableViewModelMixinTests +public class RoutableViewModelMixinTests : AppBuilderTestBase { /// /// Whens the navigated to calls on navigated to when view model is first added. diff --git a/src/ReactiveUI.Tests/Routing/RoutedViewHostTests.cs b/src/ReactiveUI.Tests/Routing/RoutedViewHostTests.cs index c5e611aa6e..012fd2a97e 100644 --- a/src/ReactiveUI.Tests/Routing/RoutedViewHostTests.cs +++ b/src/ReactiveUI.Tests/Routing/RoutedViewHostTests.cs @@ -11,7 +11,7 @@ namespace ReactiveUI.Tests; -public class RoutedViewHostTests +public class RoutedViewHostTests : AppBuilderTestBase { [StaFact] public void RoutedViewHostDefaultContentNotNull() diff --git a/src/ReactiveUI.Tests/Routing/RoutingStateTests.cs b/src/ReactiveUI.Tests/Routing/RoutingStateTests.cs index 0e4187cb01..0b22d52d4d 100644 --- a/src/ReactiveUI.Tests/Routing/RoutingStateTests.cs +++ b/src/ReactiveUI.Tests/Routing/RoutingStateTests.cs @@ -7,11 +7,9 @@ using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; - namespace ReactiveUI.Tests; -public class RoutingStateTests +public class RoutingStateTests : AppBuilderTestBase { /// /// Navigations the push pop test. diff --git a/src/ReactiveUI.Tests/Routing/ViewModelViewHostTests.cs b/src/ReactiveUI.Tests/Routing/ViewModelViewHostTests.cs index c988918ff9..fc02bc8857 100644 --- a/src/ReactiveUI.Tests/Routing/ViewModelViewHostTests.cs +++ b/src/ReactiveUI.Tests/Routing/ViewModelViewHostTests.cs @@ -11,7 +11,7 @@ namespace ReactiveUI.Tests; -public class ViewModelViewHostTests +public class ViewModelViewHostTests : AppBuilderTestBase { [StaFact] public void ViewModelViewHostDefaultContentNotNull() diff --git a/src/ReactiveUI.Tests/RxAppTest.cs b/src/ReactiveUI.Tests/RxAppTest.cs index 40a9f030be..f13a5e47b1 100644 --- a/src/ReactiveUI.Tests/RxAppTest.cs +++ b/src/ReactiveUI.Tests/RxAppTest.cs @@ -10,17 +10,18 @@ namespace ReactiveUI.Tests; /// /// Tests the RxApp class. /// -public class RxAppTest +public class RxAppTest : AppBuilderTestBase { /// /// Tests that schedulers should be current thread in test runner. /// + /// A representing the asynchronous operation. [Fact] - public void SchedulerShouldBeCurrentThreadInTestRunner() - { - RxApp.MainThreadScheduler = CurrentThreadScheduler.Instance; - Splat.Builder.AppBuilder.ResetBuilderStateForTests(); - Debug.WriteLine(RxApp.MainThreadScheduler.GetType().FullName); - Assert.Equal(CurrentThreadScheduler.Instance, RxApp.MainThreadScheduler); - } + public async Task SchedulerShouldBeCurrentThreadInTestRunner() => + await RunAppBuilderTestAsync(() => + { + RxApp.MainThreadScheduler = CurrentThreadScheduler.Instance; + Debug.WriteLine(RxApp.MainThreadScheduler.GetType().FullName); + Assert.Equal(CurrentThreadScheduler.Instance, RxApp.MainThreadScheduler); + }); } diff --git a/src/ReactiveUI.Tests/Suspension/SuspensionHostExtensionsTests.cs b/src/ReactiveUI.Tests/Suspension/SuspensionHostExtensionsTests.cs index e8a4e1f732..dc1135dae6 100644 --- a/src/ReactiveUI.Tests/Suspension/SuspensionHostExtensionsTests.cs +++ b/src/ReactiveUI.Tests/Suspension/SuspensionHostExtensionsTests.cs @@ -7,7 +7,7 @@ namespace ReactiveUI.Tests.Suspension; -public class SuspensionHostExtensionsTests +public class SuspensionHostExtensionsTests : AppBuilderTestBase { [Fact] public void GetAppStateReturns() diff --git a/src/ReactiveUI.Tests/WaitForDispatcherSchedulerTests.cs b/src/ReactiveUI.Tests/WaitForDispatcherSchedulerTests.cs index d6b0431416..a3d5be3656 100644 --- a/src/ReactiveUI.Tests/WaitForDispatcherSchedulerTests.cs +++ b/src/ReactiveUI.Tests/WaitForDispatcherSchedulerTests.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Tests the WaitForDispatcherSchedulerClass. /// -public class WaitForDispatcherSchedulerTests +public class WaitForDispatcherSchedulerTests : AppBuilderTestBase { /// /// Tests call scheduler factory on creation. diff --git a/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs b/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs index 3ee51f54a2..9d650f19d9 100644 --- a/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs +++ b/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs @@ -7,14 +7,12 @@ using Microsoft.Reactive.Testing; -using ReactiveUI.Testing; - namespace ReactiveUI.Tests; /// /// Tests the reactive notify property changed. /// -public class ReactiveNotifyPropertyChangedMixinTest +public class ReactiveNotifyPropertyChangedMixinTest : AppBuilderTestBase { /// /// Gets or sets the dummy. diff --git a/src/ReactiveUI.Tests/WhenAny/WhenAnyObservableTests.cs b/src/ReactiveUI.Tests/WhenAny/WhenAnyObservableTests.cs index 7cc84b06e5..3533efec0d 100644 --- a/src/ReactiveUI.Tests/WhenAny/WhenAnyObservableTests.cs +++ b/src/ReactiveUI.Tests/WhenAny/WhenAnyObservableTests.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.Tests; /// /// Tests WhenAnyObservable. /// -public class WhenAnyObservableTests +public class WhenAnyObservableTests : AppBuilderTestBase { /// /// Tests that null observables do not cause exceptions. From b644315621ceee8f583f28d390a2930e8d625176 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Thu, 28 Aug 2025 00:31:36 +0100 Subject: [PATCH 08/11] Update tests --- .../Properties/TestConfiguration.cs | 2 - .../StringBasedObservationTests.cs | 2 - .../ViewLocatorAOTMappingTests.cs | 2 - .../TestConfiguration.cs | 2 - .../TestConfiguration.cs | 2 - src/ReactiveUI.Testing/RxTest.cs | 24 +- ...provalTests.Testing.DotNet8_0.verified.txt | 2 +- ...provalTests.Testing.DotNet9_0.verified.txt | 2 +- ...iApprovalTests.Testing.Net4_7.verified.txt | 2 +- .../Activation/ActivatingViewTests.cs | 2 - .../CommandBindingImplementationTests.cs | 39 +- .../Platforms/winforms/CommandBindingTests.cs | 1 - .../ReactiveUIBuilderWinFormsTests.cs | 1 - .../WinFormsViewDependencyResolverTests.cs | 123 +- .../WpfCommandBindingImplementationTests.cs | 398 +-- .../wpf/WpfViewDependencyResolverTests.cs | 17 +- .../ReactiveNotifyPropertyChangedMixinTest.cs | 2224 ++++++++--------- src/ReactiveUI/Builder/ReactiveUIBuilder.cs | 1 - .../Mixins/DependencyResolverMixins.cs | 1 - .../MutableDependencyResolverExtensions.cs | 2 - src/ReactiveUI/View/DefaultViewLocator.AOT.cs | 1 - src/ReactiveUI/View/DefaultViewLocator.cs | 1 - 22 files changed, 1423 insertions(+), 1428 deletions(-) diff --git a/src/ReactiveUI.AOTTests/Properties/TestConfiguration.cs b/src/ReactiveUI.AOTTests/Properties/TestConfiguration.cs index 3d24fd781a..7ff7f58d81 100644 --- a/src/ReactiveUI.AOTTests/Properties/TestConfiguration.cs +++ b/src/ReactiveUI.AOTTests/Properties/TestConfiguration.cs @@ -3,6 +3,4 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using Xunit; - [assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.AOTTests/StringBasedObservationTests.cs b/src/ReactiveUI.AOTTests/StringBasedObservationTests.cs index 00787e8119..7e0aefa922 100644 --- a/src/ReactiveUI.AOTTests/StringBasedObservationTests.cs +++ b/src/ReactiveUI.AOTTests/StringBasedObservationTests.cs @@ -3,8 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; -using System.Reactive.Concurrency; using System.Reactive.Linq; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs b/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs index 031f49f5f8..b44cd9fe05 100644 --- a/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs +++ b/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs @@ -3,8 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Reactive.Linq; - namespace ReactiveUI.AOTTests; /// diff --git a/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs b/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs index 3d24fd781a..7ff7f58d81 100644 --- a/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs +++ b/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs @@ -3,6 +3,4 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using Xunit; - [assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Builder.Tests/TestConfiguration.cs b/src/ReactiveUI.Builder.Tests/TestConfiguration.cs index 3d24fd781a..7ff7f58d81 100644 --- a/src/ReactiveUI.Builder.Tests/TestConfiguration.cs +++ b/src/ReactiveUI.Builder.Tests/TestConfiguration.cs @@ -3,6 +3,4 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using Xunit; - [assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Testing/RxTest.cs b/src/ReactiveUI.Testing/RxTest.cs index 7e9a653bc4..d472cce782 100644 --- a/src/ReactiveUI.Testing/RxTest.cs +++ b/src/ReactiveUI.Testing/RxTest.cs @@ -18,17 +18,22 @@ public static class RxTest /// Applications the builder test asynchronous. /// /// The test body. - /// The maximum wait ms. + /// The maximum wait in milliseconds for both acquiring the test gate and running the test body. /// testBody. /// A representing the asynchronous operation. - public static async Task AppBuilderTestAsync(Func testBody, int maxWaitMs = 5000) + public static async Task AppBuilderTestAsync(Func testBody, int maxWaitMs = 60000) { if (testBody is null) { throw new ArgumentNullException(nameof(testBody)); } - await TestGate.WaitAsync().ConfigureAwait(false); + // Try to acquire the global test gate with timeout to avoid deadlocks in CI. + if (!await TestGate.WaitAsync(maxWaitMs).ConfigureAwait(false)) + { + throw new TimeoutException($"Timed out waiting for AppBuilder test gate after {maxWaitMs}ms."); + } + try { // Force-reset any previous builder state to avoid waiting deadlocks. @@ -36,8 +41,17 @@ public static async Task AppBuilderTestAsync(Func testBody, int maxWaitMs try { - // Execute actual test - await testBody().ConfigureAwait(false); + // Execute actual test with timeout so it doesn't hang forever on CI. + var testTask = testBody(); + var timeoutTask = Task.Delay(maxWaitMs); + var completed = await Task.WhenAny(testTask, timeoutTask).ConfigureAwait(false); + if (completed == timeoutTask) + { + throw new TimeoutException($"Test execution exceeded {maxWaitMs}ms."); + } + + // Propagate exceptions from the test body. + await testTask.ConfigureAwait(false); } finally { diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt index 57ed4e8ce2..c503136929 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt @@ -33,7 +33,7 @@ namespace ReactiveUI.Testing } public static class RxTest { - public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 5000) { } + public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 30000) { } } public static class SchedulerExtensions { diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt index 312c10e8d9..bc32960280 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt @@ -33,7 +33,7 @@ namespace ReactiveUI.Testing } public static class RxTest { - public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 5000) { } + public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 30000) { } } public static class SchedulerExtensions { diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt index 3f835a248f..254d2da388 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt @@ -33,7 +33,7 @@ namespace ReactiveUI.Testing } public static class RxTest { - public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 5000) { } + public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 30000) { } } public static class SchedulerExtensions { diff --git a/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs b/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs index 8561c6d1a9..d6fed2589a 100644 --- a/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs +++ b/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs @@ -3,8 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using Splat.Builder; - namespace ReactiveUI.Tests; /// diff --git a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs index 88f170b7d2..e576b83f9e 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs @@ -47,31 +47,32 @@ await RunAppBuilderTestAsync(() => /// /// A representing the asynchronous unit test. [Fact] - public async Task CommandBindToExplicitEventWireupAsync() - { - using var testSequencer = new TestSequencer(); - var vm = new WinformCommandBindViewModel(); - var view = new WinformCommandBindView { ViewModel = vm }; - var fixture = new CommandBinderImplementation(); - - var invokeCount = 0; - vm.Command2.Subscribe(async _ => + public async Task CommandBindToExplicitEventWireupAsync() => + await RunAppBuilderTestAsync(async () => { - ++invokeCount; - await testSequencer.AdvancePhaseAsync(); - }); + using var testSequencer = new TestSequencer(); + var vm = new WinformCommandBindViewModel(); + var view = new WinformCommandBindView { ViewModel = vm }; + var fixture = new CommandBinderImplementation(); - var disp = fixture.BindCommand(vm, view, x => x.Command2, x => x.Command2, "MouseUp"); + var invokeCount = 0; + vm.Command2.Subscribe(async _ => + { + ++invokeCount; + await testSequencer.AdvancePhaseAsync(); + }); - view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); + var disp = fixture.BindCommand(vm, view, x => x.Command2, x => x.Command2, "MouseUp"); - disp.Dispose(); + view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); + disp.Dispose(); + + view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - await testSequencer.AdvancePhaseAsync(); - Assert.Equal(1, invokeCount); - } + await testSequencer.AdvancePhaseAsync(); + Assert.Equal(1, invokeCount); + }); [Fact] public async Task CommandBindByNameWireupWithParameter() => diff --git a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs index 2f4acc4870..faf50f8bf4 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs @@ -5,7 +5,6 @@ using System.Windows.Forms; using ReactiveUI.Winforms; -using Splat.Builder; namespace ReactiveUI.Tests.Winforms; diff --git a/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs index c60a54749b..dffaf0cbfa 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs @@ -4,7 +4,6 @@ // See the LICENSE file in the project root for full license information. using ReactiveUI.Builder; -using Splat.Builder; namespace ReactiveUI.Tests.Platforms.Winforms; diff --git a/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs index 2b7570504a..e8c7268e86 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs @@ -3,12 +3,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using Splat.Builder; using FactAttribute = Xunit.WpfFactAttribute; namespace ReactiveUI.Tests.Winforms; -public sealed class WinFormsViewDependencyResolverTests : IDisposable +public sealed class WinFormsViewDependencyResolverTests : AppBuilderTestBase, IDisposable { private readonly IDependencyResolver _resolver; @@ -25,79 +24,85 @@ public WinFormsViewDependencyResolverTests() _resolver.RegisterViewsForViewModels(GetType().Assembly); } - [Fact] - public void RegisterViewsForViewModelShouldRegisterAllViews() - { - using (_resolver.WithResolver()) + [FactAttribute] + public async Task RegisterViewsForViewModelShouldRegisterAllViews() => + await RunAppBuilderTestAsync(() => { - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - } - } - - [Fact] - public void NonContractRegistrationsShouldResolveCorrectly() - { - using (_resolver.WithResolver()) + using (_resolver.WithResolver()) + { + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + } + }); + + [FactAttribute] + public async Task NonContractRegistrationsShouldResolveCorrectly() => + await RunAppBuilderTestAsync(() => { - Assert.IsType(_resolver.GetService>()); - } - } + using (_resolver.WithResolver()) + { + Assert.IsType(_resolver.GetService>()); + } + }); /// public void Dispose() => _resolver?.Dispose(); - [Fact] - public void ContractRegistrationsShouldResolveCorrectly() - { - using (_resolver.WithResolver()) + [FactAttribute] + public async Task ContractRegistrationsShouldResolveCorrectly() => + await RunAppBuilderTestAsync(() => { - Assert.IsType(_resolver.GetService(typeof(IViewFor), "contract")); - } - } - - [Fact] - public void SingleInstanceViewsShouldOnlyBeInstantiatedOnce() - { - using (_resolver.WithResolver()) + using (_resolver.WithResolver()) + { + Assert.IsType(_resolver.GetService(typeof(IViewFor), "contract")); + } + }); + + [FactAttribute] + public async Task SingleInstanceViewsShouldOnlyBeInstantiatedOnce() => + await RunAppBuilderTestAsync(() => { - Assert.Equal(0, SingleInstanceExampleView.Instances); + using (_resolver.WithResolver()) + { + Assert.Equal(0, SingleInstanceExampleView.Instances); - var instance = _resolver.GetService(typeof(IViewFor)); - Assert.Equal(1, SingleInstanceExampleView.Instances); + var instance = _resolver.GetService(typeof(IViewFor)); + Assert.Equal(1, SingleInstanceExampleView.Instances); - var instance2 = _resolver.GetService(typeof(IViewFor)); - Assert.Equal(1, SingleInstanceExampleView.Instances); + var instance2 = _resolver.GetService(typeof(IViewFor)); + Assert.Equal(1, SingleInstanceExampleView.Instances); - Assert.Same(instance, instance2); - } - } + Assert.Same(instance, instance2); + } + }); - [Fact] - public void SingleInstanceViewsWithContractShouldResolveCorrectly() - { - using (_resolver.WithResolver()) + [FactAttribute] + public async Task SingleInstanceViewsWithContractShouldResolveCorrectly() => + await RunAppBuilderTestAsync(() => { - Assert.Equal(0, SingleInstanceWithContractExampleView.Instances); + using (_resolver.WithResolver()) + { + Assert.Equal(0, SingleInstanceWithContractExampleView.Instances); - var instance = _resolver.GetService(typeof(IViewFor), "contract"); - Assert.Equal(1, SingleInstanceWithContractExampleView.Instances); + var instance = _resolver.GetService(typeof(IViewFor), "contract"); + Assert.Equal(1, SingleInstanceWithContractExampleView.Instances); - var instance2 = _resolver.GetService(typeof(IViewFor), "contract"); - Assert.Equal(1, SingleInstanceWithContractExampleView.Instances); + var instance2 = _resolver.GetService(typeof(IViewFor), "contract"); + Assert.Equal(1, SingleInstanceWithContractExampleView.Instances); - Assert.Same(instance, instance2); - } - } + Assert.Same(instance, instance2); + } + }); - [Fact] - public void SingleInstanceViewsShouldOnlyBeInstantiatedWhenRequested() - { - using (_resolver.WithResolver()) + [FactAttribute] + public async Task SingleInstanceViewsShouldOnlyBeInstantiatedWhenRequested() => + await RunAppBuilderTestAsync(() => { - Assert.Equal(0, NeverUsedView.Instances); - } - } + using (_resolver.WithResolver()) + { + Assert.Equal(0, NeverUsedView.Instances); + } + }); } diff --git a/src/ReactiveUI.Tests/Platforms/wpf/WpfCommandBindingImplementationTests.cs b/src/ReactiveUI.Tests/Platforms/wpf/WpfCommandBindingImplementationTests.cs index 98167d02f9..49639725d6 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/WpfCommandBindingImplementationTests.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/WpfCommandBindingImplementationTests.cs @@ -14,270 +14,280 @@ namespace ReactiveUI.Tests.Wpf; -public class WpfCommandBindingImplementationTests +public class WpfCommandBindingImplementationTests : AppBuilderTestBase { /// /// Commands the bind to explicit event wireup. /// - [Fact] - public void CommandBindToExplicitEventWireup() - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; + [FactAttribute] + public async Task CommandBindToExplicitEventWireup() => + await RunAppBuilderTestAsync(() => + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); - var disp = view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); + var disp = view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - disp.Dispose(); + disp.Dispose(); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(1, invokeCount); - } + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(1, invokeCount); + }); /// /// Binds the command to object target is null. /// - [Fact] - public void BindCommandToObjectWithEventTargetIsNull() - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; + [FactAttribute] + public async Task BindCommandToObjectWithEventTargetIsNull() => + await RunAppBuilderTestAsync(() => + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); - var sub = new Subject(); - Assert.Throws(() => - { - var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, true, sub, "MouseUp"); + var sub = new Subject(); + Assert.Throws(() => + { + var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, true, sub, "MouseUp"); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - disp.Dispose(); + disp.Dispose(); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - }); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + }); - Assert.Equal(0, invokeCount); - } + Assert.Equal(0, invokeCount); + }); /// /// Binds the command to object target is null. /// - [Fact] - public void BindCommandToObjectTargetIsNull() - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; + [FactAttribute] + public async Task BindCommandToObjectTargetIsNull() => + await RunAppBuilderTestAsync(() => + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); - var sub = new Subject(); - Assert.Throws(() => - { - var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, true, sub); + var sub = new Subject(); + Assert.Throws(() => + { + var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, true, sub); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - disp.Dispose(); + disp.Dispose(); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - }); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + }); - Assert.Equal(0, invokeCount); - } + Assert.Equal(0, invokeCount); + }); /// /// Binds the command to object target is null. /// - [Fact] - public void BindCommandToObjectEventIsNull() - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; + [FactAttribute] + public async Task BindCommandToObjectEventIsNull() => + await RunAppBuilderTestAsync(() => + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); - var sub = new Subject(); - Assert.Throws(() => - { - var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, vm, sub, "HappyMouseEvent"); + var sub = new Subject(); + Assert.Throws(() => + { + var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, vm, sub, "HappyMouseEvent"); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - disp.Dispose(); + disp.Dispose(); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - }); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + }); - Assert.Equal(0, invokeCount); - } + Assert.Equal(0, invokeCount); + }); /// /// Binds the command to object command is null. /// - [Fact] - public void BindCommandToObjectWithEventCommandIsArgumentNull() - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; - - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); - var btn = new Button(); - var cmd = (btn as ICommand)!; - var sub = new Subject(); - Assert.Throws(() => + [FactAttribute] + public async Task BindCommandToObjectWithEventCommandIsArgumentNull() => + await RunAppBuilderTestAsync(() => { - var disp = CreatesCommandBinding.BindCommandToObject(cmd, view, sub, "PropertyChanged"); + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); + var btn = new Button(); + var cmd = (btn as ICommand)!; + var sub = new Subject(); + Assert.Throws(() => + { + var disp = CreatesCommandBinding.BindCommandToObject(cmd, view, sub, "PropertyChanged"); - disp.Dispose(); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - }); + disp.Dispose(); - Assert.Equal(0, invokeCount); - } + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + }); + + Assert.Equal(0, invokeCount); + }); /// /// Binds the command to object command is null. /// - [Fact] - public void BindCommandToObjectCommandIsArgumentNull() - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; - - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); - var btn = new Button(); - var cmd = (btn as ICommand)!; - var sub = new Subject(); - Assert.Throws(() => + [FactAttribute] + public async Task BindCommandToObjectCommandIsArgumentNull() => + await RunAppBuilderTestAsync(() => { - var disp = CreatesCommandBinding.BindCommandToObject(cmd, view, sub); + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); + var btn = new Button(); + var cmd = (btn as ICommand)!; + var sub = new Subject(); + Assert.Throws(() => + { + var disp = CreatesCommandBinding.BindCommandToObject(cmd, view, sub); - disp.Dispose(); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - }); + disp.Dispose(); - Assert.Equal(0, invokeCount); - } + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + }); + + Assert.Equal(0, invokeCount); + }); /// /// Commands the bind view model to view with observable. /// - [Fact] - public void CommandBindViewModelToViewWithObservable() - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; - - // Create a paramenter feed - vm.Command2.Subscribe(_ => vm.Value++); - view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); - - // Bind the command and the IObservable parameter. - var fixture = new CommandBinderImplementation().BindCommand(vm, view, vm => vm.Command1, v => v.Command3, vm.WhenAnyValue(vm => vm.Value), "MouseUp"); - Assert.Equal(0, vm.Value); - - // Confirm that the values update as expected. - var parameter = 0; - vm.Command1.Subscribe(i => parameter = i); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(1, vm.Value); - Assert.Equal(0, parameter); - - view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(1, parameter); - - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(2, vm.Value); - Assert.Equal(1, parameter); - - view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(2, parameter); - Assert.Equal(2, vm.Value); - } + [FactAttribute] + public async Task CommandBindViewModelToViewWithObservable() => + await RunAppBuilderTestAsync(() => + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; + + // Create a paramenter feed + vm.Command2.Subscribe(_ => vm.Value++); + view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); + + // Bind the command and the IObservable parameter. + var fixture = new CommandBinderImplementation().BindCommand(vm, view, vm => vm.Command1, v => v.Command3, vm.WhenAnyValue(vm => vm.Value), "MouseUp"); + Assert.Equal(0, vm.Value); + + // Confirm that the values update as expected. + var parameter = 0; + vm.Command1.Subscribe(i => parameter = i); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(1, vm.Value); + Assert.Equal(0, parameter); + + view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(1, parameter); + + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(2, vm.Value); + Assert.Equal(1, parameter); + + view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(2, parameter); + Assert.Equal(2, vm.Value); + }); /// /// Commands the bind view model to view with function. /// - [Fact] - public void CommandBindViewModelToViewWithFunc() - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; - - // Create a paramenter feed - vm.Command2.Subscribe(_ => vm.Value++); - view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); - - // Bind the command and the Func parameter. - var fixture = new CommandBinderImplementation().BindCommand(vm, view, vm => vm.Command1, v => v.Command3, vm => vm.Value, "MouseUp"); - Assert.Equal(0, vm.Value); - - // Confirm that the values update as expected. - var parameter = 0; - vm.Command1.Subscribe(i => parameter = i); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(1, vm.Value); - Assert.Equal(0, parameter); - - view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(1, parameter); - - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(2, vm.Value); - Assert.Equal(1, parameter); - - view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(2, parameter); - Assert.Equal(2, vm.Value); - } - - [Fact] - public void BindCommandShouldNotWarnWhenBindingToFieldDeclaredInXaml() - { - var testLogger = new TestLogger(); - Locator.CurrentMutable.RegisterConstant(testLogger); - - var vm = new CommandBindingViewModel(); - var view = new FakeXamlCommandBindingView { ViewModel = vm }; - - testLogger.Messages.Should().NotContain(t => t.message.Contains(nameof(POCOObservableForProperty)) && t.message.Contains(view.NameOfButtonDeclaredInXaml) && t.logLevel == LogLevel.Warn); - } - - [Fact] - public void ViewModelShouldBeGarbageCollectedWhenOverwritten() - { - static (IDisposable, WeakReference) GetWeakReference() + [FactAttribute] + public async Task CommandBindViewModelToViewWithFunc() => + await RunAppBuilderTestAsync(() => { var vm = new CommandBindingViewModel(); var view = new CommandBindingView { ViewModel = vm }; - var weakRef = new WeakReference(vm); - var disp = view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); - view.ViewModel = new CommandBindingViewModel(); - return (disp, weakRef); - } + // Create a paramenter feed + vm.Command2.Subscribe(_ => vm.Value++); + view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); + + // Bind the command and the Func parameter. + var fixture = new CommandBinderImplementation().BindCommand(vm, view, vm => vm.Command1, v => v.Command3, vm => vm.Value, "MouseUp"); + Assert.Equal(0, vm.Value); + + // Confirm that the values update as expected. + var parameter = 0; + vm.Command1.Subscribe(i => parameter = i); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(1, vm.Value); + Assert.Equal(0, parameter); + + view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(1, parameter); + + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(2, vm.Value); + Assert.Equal(1, parameter); + + view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(2, parameter); + Assert.Equal(2, vm.Value); + }); + + [FactAttribute] + public async Task BindCommandShouldNotWarnWhenBindingToFieldDeclaredInXaml() => + await RunAppBuilderTestAsync(() => + { + var testLogger = new TestLogger(); + Locator.CurrentMutable.RegisterConstant(testLogger); + + var vm = new CommandBindingViewModel(); + var view = new FakeXamlCommandBindingView { ViewModel = vm }; + + testLogger.Messages.Should().NotContain(t => t.message.Contains(nameof(POCOObservableForProperty)) && t.message.Contains(view.NameOfButtonDeclaredInXaml) && t.logLevel == LogLevel.Warn); + }); + + [FactAttribute] + public async Task ViewModelShouldBeGarbageCollectedWhenOverwritten() => + await RunAppBuilderTestAsync(() => + { + static (IDisposable, WeakReference) GetWeakReference() + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; + var weakRef = new WeakReference(vm); + var disp = view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); + view.ViewModel = new CommandBindingViewModel(); - var (disp, weakRef) = GetWeakReference(); + return (disp, weakRef); + } - GC.Collect(); - GC.WaitForPendingFinalizers(); + var (disp, weakRef) = GetWeakReference(); - Assert.False(weakRef.IsAlive); - } + GC.Collect(); + GC.WaitForPendingFinalizers(); + + Assert.False(weakRef.IsAlive); + }); } diff --git a/src/ReactiveUI.Tests/Platforms/wpf/WpfViewDependencyResolverTests.cs b/src/ReactiveUI.Tests/Platforms/wpf/WpfViewDependencyResolverTests.cs index 29718d98ed..d9e5c3fa58 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/WpfViewDependencyResolverTests.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/WpfViewDependencyResolverTests.cs @@ -11,7 +11,7 @@ namespace ReactiveUI.Tests.Wpf; /// Tests for the WPF View Resolver. /// /// -public sealed class WpfViewDependencyResolverTests : IDisposable +public sealed class WpfViewDependencyResolverTests : AppBuilderTestBase, IDisposable { private readonly IDependencyResolver _resolver; @@ -29,14 +29,15 @@ public WpfViewDependencyResolverTests() /// /// Tests that Register views for view model should register all views. /// - [Fact] - public void RegisterViewsForViewModelShouldRegisterAllViews() - { - using (_resolver.WithResolver()) + [FactAttribute] + public async Task RegisterViewsForViewModelShouldRegisterAllViews() => + await RunAppBuilderTestAsync(() => { - Assert.Single(_resolver.GetServices>()); - } - } + using (_resolver.WithResolver()) + { + Assert.Single(_resolver.GetServices>()); + } + }); /// public void Dispose() => _resolver?.Dispose(); diff --git a/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs b/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs index 9d650f19d9..f039855762 100644 --- a/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs +++ b/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs @@ -4,7 +4,6 @@ // See the LICENSE file in the project root for full license information. using DynamicData; - using Microsoft.Reactive.Testing; namespace ReactiveUI.Tests; @@ -20,40 +19,42 @@ public class ReactiveNotifyPropertyChangedMixinTest : AppBuilderTestBase public string? Dummy { get; set; } [Fact] - public void AnyChangeInExpressionListTriggersUpdate() - { - var obj = new ObjChain1(); - bool obsUpdated; + public async Task AnyChangeInExpressionListTriggersUpdate() => + await RunAppBuilderTestAsync(() => + { + var obj = new ObjChain1(); + bool obsUpdated; - obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(_ => obsUpdated = true); + obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(_ => obsUpdated = true); - obsUpdated = false; - obj.Model.Model.Model.SomeOtherParam = 42; - Assert.True(obsUpdated); + obsUpdated = false; + obj.Model.Model.Model.SomeOtherParam = 42; + Assert.True(obsUpdated); - obsUpdated = false; - obj.Model.Model.Model = new HostTestFixture(); - Assert.True(obsUpdated); + obsUpdated = false; + obj.Model.Model.Model = new HostTestFixture(); + Assert.True(obsUpdated); - obsUpdated = false; - obj.Model.Model = new ObjChain3 - { - Model = new HostTestFixture + obsUpdated = false; + obj.Model.Model = new ObjChain3 { - SomeOtherParam = 10 - } - }; - Assert.True(obsUpdated); + Model = new HostTestFixture + { + SomeOtherParam = 10 + } + }; + Assert.True(obsUpdated); - obsUpdated = false; - obj.Model = new ObjChain2(); - Assert.True(obsUpdated); - } + obsUpdated = false; + obj.Model = new ObjChain2(); + Assert.True(obsUpdated); + }); [Fact] - public void MultiPropertyExpressionsShouldBeProperlyResolved() - { - var data = new Dictionary>, string[]> + public async Task MultiPropertyExpressionsShouldBeProperlyResolved() => + await RunAppBuilderTestAsync(() => + { + var data = new Dictionary>, string[]> { { x => x!.Child!.IsOnlyOneWord!.Length, new[] { "Child", "IsOnlyOneWord", "Length" } }, { x => x.SomeOtherParam, new[] { "SomeOtherParam" } }, @@ -61,7 +62,7 @@ public void MultiPropertyExpressionsShouldBeProperlyResolved() { x => x.Child!.Changed, new[] { "Child", "Changed" } }, }; - var dataTypes = new Dictionary>, Type[]> + var dataTypes = new Dictionary>, Type[]> { { x => x.Child!.IsOnlyOneWord!.Length, new[] { typeof(TestFixture), typeof(string), typeof(int) } }, { x => x.SomeOtherParam, new[] { typeof(int) } }, @@ -69,1279 +70,1262 @@ public void MultiPropertyExpressionsShouldBeProperlyResolved() { x => x.Child!.Changed, new[] { typeof(TestFixture), typeof(IObservable>) } }, }; - var results = data.Keys.Select( + var results = data.Keys.Select( x => new { input = x, output = Reflection.Rewrite(x.Body).GetExpressionChain() }).ToArray(); - var resultTypes = dataTypes.Keys.Select( + var resultTypes = dataTypes.Keys.Select( x => new { input = x, output = Reflection.Rewrite(x.Body).GetExpressionChain() }).ToArray(); - foreach (var x in results) - { - data[x.input].AssertAreEqual(x.output.Select(y => + foreach (var x in results) + { + data[x.input].AssertAreEqual(x.output.Select(y => { var propertyName = y.GetMemberInfo()?.Name; return propertyName ?? throw new InvalidOperationException("propertyName should not be null."); })); - } + } - foreach (var x in resultTypes) - { - dataTypes[x.input].AssertAreEqual(x.output.Select(y => y.Type)); - } - } + foreach (var x in resultTypes) + { + dataTypes[x.input].AssertAreEqual(x.output.Select(y => y.Type)); + } + }); [Fact] - public void OFPChangingTheHostPropertyShouldFireAChildChangeNotificationOnlyIfThePreviousChildIsDifferent() => - new TestScheduler().With(scheduler => - { - var fixture = new HostTestFixture() + public async Task OFPChangingTheHostPropertyShouldFireAChildChangeNotificationOnlyIfThePreviousChildIsDifferent() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With(scheduler => { - Child = new TestFixture() - }; - fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); + var fixture = new HostTestFixture() + { + Child = new TestFixture() + }; + fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); - fixture.Child.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); + fixture.Child.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); - fixture.Child.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); + fixture.Child.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); - fixture.Child = new TestFixture - { - IsOnlyOneWord = "Bar" - }; - scheduler.Start(); - Assert.Equal(2, changes.Count); - }); + fixture.Child = new TestFixture + { + IsOnlyOneWord = "Bar" + }; + scheduler.Start(); + Assert.Equal(2, changes.Count); + })); [Fact] - public void OFPNamedPropertyTest() => - new TestScheduler().With(scheduler => - { - var fixture = new TestFixture(); - fixture.ObservableForProperty(x => x.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - fixture.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); - }); + public async Task OFPNamedPropertyTest() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With(scheduler => + { + var fixture = new TestFixture(); + fixture.ObservableForProperty(x => x.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + fixture.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); + })); [Fact] - public void OFPNamedPropertyTestBeforeChange() => - new TestScheduler().With(scheduler => - { - var fixture = new TestFixture() + public async Task OFPNamedPropertyTestBeforeChange() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With(scheduler => { - IsOnlyOneWord = "Pre" - }; - fixture.ObservableForProperty(x => x.IsOnlyOneWord, beforeChange: true) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); + var fixture = new TestFixture() + { + IsOnlyOneWord = "Pre" + }; + fixture.ObservableForProperty(x => x.IsOnlyOneWord, beforeChange: true) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); - scheduler.Start(); - Assert.Equal(0, changes.Count); + scheduler.Start(); + Assert.Equal(0, changes.Count); - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); - fixture.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); + fixture.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Pre", "Foo" }); - }); + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Pre", "Foo" }); + })); [Fact] - public void OFPNamedPropertyTestNoSkipInitial() => - new TestScheduler().With(scheduler => - { - var fixture = new TestFixture() + public async Task OFPNamedPropertyTestNoSkipInitial() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With(scheduler => { - IsOnlyOneWord = "Pre" - }; - fixture.ObservableForProperty(x => x.IsOnlyOneWord, false, false) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); + var fixture = new TestFixture() + { + IsOnlyOneWord = "Pre" + }; + fixture.ObservableForProperty(x => x.IsOnlyOneWord, false, false) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); - scheduler.Start(); - Assert.Equal(1, changes.Count); + scheduler.Start(); + Assert.Equal(1, changes.Count); - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(2, changes.Count); + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(2, changes.Count); - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Pre", "Foo" }); - }); + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Pre", "Foo" }); + })); [Fact] - public void OFPNamedPropertyTestRepeats() => - new TestScheduler().With(scheduler => - { - var fixture = new TestFixture(); - fixture.ObservableForProperty(x => x.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Foo" }); - }); + public async Task OFPNamedPropertyTestRepeats() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With(scheduler => + { + var fixture = new TestFixture(); + fixture.ObservableForProperty(x => x.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Foo" }); + })); [Fact] - public void OFPReplacingTheHostShouldResubscribeTheObservable() => - new TestScheduler().With(scheduler => - { - var fixture = new HostTestFixture() + public async Task OFPReplacingTheHostShouldResubscribeTheObservable() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With(scheduler => { - Child = new TestFixture() - }; - fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.Child.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.Child.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - // Tricky! This is a change too, because from the perspective - // of the binding, we've went from "Bar" to null - fixture.Child = new TestFixture(); - scheduler.Start(); - Assert.Equal(3, changes.Count); - - // Here we've set the value but it shouldn't change - fixture.Child.IsOnlyOneWord = null!; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - fixture.Child.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(4, changes.Count); - - fixture.Child.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(4, changes.Count); - - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", null, "Baz" }); - }); + var fixture = new HostTestFixture() + { + Child = new TestFixture() + }; + fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixture.Child.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.Child.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + // Tricky! This is a change too, because from the perspective + // of the binding, we've went from "Bar" to null + fixture.Child = new TestFixture(); + scheduler.Start(); + Assert.Equal(3, changes.Count); + + // Here we've set the value but it shouldn't change + fixture.Child.IsOnlyOneWord = null!; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + fixture.Child.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(4, changes.Count); + + fixture.Child.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(4, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", null, "Baz" }); + })); [Fact] - public void OFPReplacingTheHostWithNullThenSettingItBackShouldResubscribeTheObservable() => - new TestScheduler().With(scheduler => - { - var fixture = new HostTestFixture() + public async Task OFPReplacingTheHostWithNullThenSettingItBackShouldResubscribeTheObservable() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With(scheduler => { - Child = new TestFixture() - }; - var fixtureProp = fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord); - fixtureProp - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixtureProp.Subscribe(x => Console.WriteLine(x.Value)); - - fixture.Child.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.Child.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - // Oops, now the child is Null, we may now blow up - fixture.Child = null!; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - // Tricky! This is a change too, because from the perspective - // of the binding, we've went from "Bar" to null - fixture.Child = new TestFixture(); - scheduler.Start(); - Assert.Equal(3, changes.Count); - - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", null }); - }); + var fixture = new HostTestFixture() + { + Child = new TestFixture() + }; + var fixtureProp = fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord); + fixtureProp + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixtureProp.Subscribe(x => Console.WriteLine(x.Value)); + + fixture.Child.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.Child.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + // Oops, now the child is Null, we may now blow up + fixture.Child = null!; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + // Tricky! This is a change too, because from the perspective + // of the binding, we've went from "Bar" to null + fixture.Child = new TestFixture(); + scheduler.Start(); + Assert.Equal(3, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", null }); + })); [Fact] - public void OFPShouldWorkWithINPCObjectsToo() => - new TestScheduler().With(scheduler => - { - var fixture = new NonReactiveINPCObject() + public async Task OFPShouldWorkWithINPCObjectsToo() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With(scheduler => { - InpcProperty = null! - }; - fixture.ObservableForProperty(x => x.InpcProperty.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.InpcProperty = new TestFixture(); - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.InpcProperty.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.InpcProperty.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - }); + var fixture = new NonReactiveINPCObject() + { + InpcProperty = null! + }; + fixture.ObservableForProperty(x => x.InpcProperty.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixture.InpcProperty = new TestFixture(); + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.InpcProperty.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.InpcProperty.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + })); [Fact] - public void OFPSimpleChildPropertyTest() => - new TestScheduler().With(scheduler => - { - var fixture = new HostTestFixture() + public async Task OFPSimpleChildPropertyTest() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With(scheduler => { - Child = new TestFixture() - }; - fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.Child.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.Child.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.Child.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - fixture.Child.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); - }); + var fixture = new HostTestFixture() + { + Child = new TestFixture() + }; + fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); - [Fact] - public void OFPSimplePropertyTest() => - new TestScheduler().With(scheduler => - { - var fixture = new TestFixture(); - fixture.ObservableForProperty(x => x.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - fixture.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); - }); + fixture.Child.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.Child.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.Child.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + fixture.Child.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); + })); [Fact] - public void SubscriptionToWhenAnyShouldReturnCurrentValue() - { - var obj = new HostTestFixture(); - var observedValue = 1; - obj.WhenAnyValue(x => x.SomeOtherParam).Subscribe(x => observedValue = x); + public async Task OFPSimplePropertyTest() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With(scheduler => + { + var fixture = new TestFixture(); + fixture.ObservableForProperty(x => x.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); - obj.SomeOtherParam = 42; + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); - Assert.True(observedValue == obj.SomeOtherParam); - } + fixture.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + fixture.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); + })); [Fact] - public void WhenAnyShouldRunInContext() - { - var tid = Environment.CurrentManagedThreadId; + public async Task SubscriptionToWhenAnyShouldReturnCurrentValue() => + await RunAppBuilderTestAsync(() => + { + var obj = new HostTestFixture(); + var observedValue = 1; + obj.WhenAnyValue(x => x.SomeOtherParam).Subscribe(x => observedValue = x); - TaskPoolScheduler.Default.With( - _ => - { - var whenAnyTid = 0; - var fixture = new TestFixture - { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }; + obj.SomeOtherParam = 42; - fixture.WhenAnyValue(x => x.IsNotNullString).Subscribe(__ => whenAnyTid = Environment.CurrentManagedThreadId); + Assert.True(observedValue == obj.SomeOtherParam); + }); - var timeout = 10; - fixture.IsNotNullString = "Bar"; - while (--timeout > 0 && whenAnyTid == 0) - { - Thread.Sleep(250); - } + [Fact] + public async Task WhenAnyShouldRunInContext() => + await RunAppBuilderTestAsync(() => + { + var tid = Environment.CurrentManagedThreadId; - Assert.Equal(tid, whenAnyTid); - }); - } + TaskPoolScheduler.Default.With( + _ => + { + var whenAnyTid = 0; + var fixture = new TestFixture + { + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }; + + fixture.WhenAnyValue(x => x.IsNotNullString).Subscribe(__ => whenAnyTid = Environment.CurrentManagedThreadId); + + var timeout = 10; + fixture.IsNotNullString = "Bar"; + while (--timeout > 0 && whenAnyTid == 0) + { + Thread.Sleep(250); + } + + Assert.Equal(tid, whenAnyTid); + }); + }); [Fact] - public void WhenAnyShouldWorkEvenWithNormalProperties() - { - var fixture = new TestFixture + public async Task WhenAnyShouldWorkEvenWithNormalProperties() => + await RunAppBuilderTestAsync(() => { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }; + var fixture = new TestFixture + { + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }; - var output = new List?>(); - fixture.WhenAny(x => x.PocoProperty, x => x).Subscribe(output.Add); - var output2 = new List(); - fixture.WhenAnyValue(x => x.PocoProperty).Subscribe(output2.Add); - var output3 = new List?>(); - fixture.WhenAny(x => x.NullableInt, x => x).Subscribe(output3.Add); + var output = new List?>(); + fixture.WhenAny(x => x.PocoProperty, x => x).Subscribe(output.Add); + var output2 = new List(); + fixture.WhenAnyValue(x => x.PocoProperty).Subscribe(output2.Add); + var output3 = new List?>(); + fixture.WhenAny(x => x.NullableInt, x => x).Subscribe(output3.Add); - var output4 = new List(); - fixture.WhenAnyValue(x => x.NullableInt).Subscribe(output4.Add); + var output4 = new List(); + fixture.WhenAnyValue(x => x.NullableInt).Subscribe(output4.Add); - Assert.Equal(1, output.Count); - Assert.Equal(fixture, output[0]!.Sender); - Assert.Equal("PocoProperty", output[0]!.GetPropertyName()); - Assert.Equal("Bamf", output[0]!.Value); + Assert.Equal(1, output.Count); + Assert.Equal(fixture, output[0]!.Sender); + Assert.Equal("PocoProperty", output[0]!.GetPropertyName()); + Assert.Equal("Bamf", output[0]!.Value); - Assert.Equal(1, output2.Count); - Assert.Equal("Bamf", output2[0]); + Assert.Equal(1, output2.Count); + Assert.Equal("Bamf", output2[0]); - Assert.Equal(1, output3.Count); - Assert.Equal(fixture, output3[0]!.Sender); - Assert.Equal("NullableInt", output3[0]!.GetPropertyName()); - Assert.Equal(null, output3[0]!.Value); + Assert.Equal(1, output3.Count); + Assert.Equal(fixture, output3[0]!.Sender); + Assert.Equal("NullableInt", output3[0]!.GetPropertyName()); + Assert.Equal(null, output3[0]!.Value); - Assert.Equal(1, output4.Count); - Assert.Equal(null, output4[0]); - } + Assert.Equal(1, output4.Count); + Assert.Equal(null, output4[0]); + }); [Fact] - public void ChangedShouldHaveValidData() - { - var fixture = new TestFixture + public async Task ChangedShouldHaveValidData() => + await RunAppBuilderTestAsync(() => { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }; - - object sender = null!; - string? propertyName = null; - fixture.Changed.ObserveOn(ImmediateScheduler.Instance).Subscribe( - x => + var fixture = new TestFixture { - sender = x.Sender; - propertyName = x.PropertyName; - }); + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }; - fixture.UsesExprRaiseSet = "abc"; + object sender = null!; + string? propertyName = null; + fixture.Changed.ObserveOn(ImmediateScheduler.Instance).Subscribe( + x => + { + sender = x.Sender; + propertyName = x.PropertyName; + }); - Assert.Equal(fixture, sender); - Assert.Equal(nameof(fixture.UsesExprRaiseSet), propertyName); + fixture.UsesExprRaiseSet = "abc"; - sender = null!; - propertyName = null; - fixture.PocoProperty = "abc"; + Assert.Equal(fixture, sender); + Assert.Equal(nameof(fixture.UsesExprRaiseSet), propertyName); - Assert.Equal(null!, sender); - Assert.Equal(null, propertyName); - } + sender = null!; + propertyName = null; + fixture.PocoProperty = "abc"; + + Assert.Equal(null!, sender); + Assert.Equal(null, propertyName); + }); [Fact] - public void ChangingShouldHaveValidData() - { - var fixture = new TestFixture + public async Task ChangingShouldHaveValidData() => + await RunAppBuilderTestAsync(() => { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }; - - object sender = null!; - string? propertyName = null; - fixture.Changing.ObserveOn(ImmediateScheduler.Instance).Subscribe( - x => + var fixture = new TestFixture { - sender = x.Sender; - propertyName = x.PropertyName; - }); + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }; - fixture.UsesExprRaiseSet = "abc"; + object sender = null!; + string? propertyName = null; + fixture.Changing.ObserveOn(ImmediateScheduler.Instance).Subscribe( + x => + { + sender = x.Sender; + propertyName = x.PropertyName; + }); - Assert.Equal(fixture, sender); - Assert.Equal(nameof(fixture.UsesExprRaiseSet), propertyName); + fixture.UsesExprRaiseSet = "abc"; - sender = null!; - propertyName = null; - fixture.PocoProperty = "abc"; + Assert.Equal(fixture, sender); + Assert.Equal(nameof(fixture.UsesExprRaiseSet), propertyName); - Assert.Equal(null!, sender); - Assert.Equal(null, propertyName); - } + sender = null!; + propertyName = null; + fixture.PocoProperty = "abc"; + + Assert.Equal(null!, sender); + Assert.Equal(null, propertyName); + }); [Fact] - public void WhenAnySmokeTest() => - new TestScheduler().With( - scheduler => - { - var fixture = new HostTestFixture + public async Task WhenAnySmokeTest() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With( + scheduler => { - Child = new TestFixture(), - SomeOtherParam = 5 - }; - fixture.Child.IsNotNullString = "Foo"; - - var output1 = new List>(); - var output2 = new List>(); - fixture.WhenAny( - x => x.SomeOtherParam, - x => x.Child!.IsNotNullString, - (sop, nns) => new - { - sop, - nns - }).Subscribe( - x => + var fixture = new HostTestFixture { - output1.Add(x!.sop); - output2.Add(x.nns!); - }); - - scheduler.Start(); - Assert.Equal(1, output1.Count); - Assert.Equal(1, output2.Count); - Assert.Equal(fixture, output1[0].Sender); - Assert.Equal(fixture, output2[0].Sender); - Assert.Equal(5, output1[0].Value); - Assert.Equal("Foo", output2[0].Value); - - fixture.SomeOtherParam = 10; - scheduler.Start(); - Assert.Equal(2, output1.Count); - Assert.Equal(2, output2.Count); - Assert.Equal(fixture, output1[1].Sender); - Assert.Equal(fixture, output2[1].Sender); - Assert.Equal(10, output1[1].Value); - Assert.Equal("Foo", output2[1].Value); - - fixture.Child.IsNotNullString = "Bar"; - scheduler.Start(); - Assert.Equal(3, output1.Count); - Assert.Equal(3, output2.Count); - Assert.Equal(fixture, output1[2].Sender); - Assert.Equal(fixture, output2[2].Sender); - Assert.Equal(10, output1[2].Value); - Assert.Equal("Bar", output2[2].Value); - }); + Child = new TestFixture(), + SomeOtherParam = 5 + }; + fixture.Child.IsNotNullString = "Foo"; + + var output1 = new List>(); + var output2 = new List>(); + fixture.WhenAny( + x => x.SomeOtherParam, + x => x.Child!.IsNotNullString, + (sop, nns) => new + { + sop, + nns + }).Subscribe( + x => + { + output1.Add(x!.sop); + output2.Add(x.nns!); + }); + + scheduler.Start(); + Assert.Equal(1, output1.Count); + Assert.Equal(1, output2.Count); + Assert.Equal(fixture, output1[0].Sender); + Assert.Equal(fixture, output2[0].Sender); + Assert.Equal(5, output1[0].Value); + Assert.Equal("Foo", output2[0].Value); + + fixture.SomeOtherParam = 10; + scheduler.Start(); + Assert.Equal(2, output1.Count); + Assert.Equal(2, output2.Count); + Assert.Equal(fixture, output1[1].Sender); + Assert.Equal(fixture, output2[1].Sender); + Assert.Equal(10, output1[1].Value); + Assert.Equal("Foo", output2[1].Value); + + fixture.Child.IsNotNullString = "Bar"; + scheduler.Start(); + Assert.Equal(3, output1.Count); + Assert.Equal(3, output2.Count); + Assert.Equal(fixture, output1[2].Sender); + Assert.Equal(fixture, output2[2].Sender); + Assert.Equal(10, output1[2].Value); + Assert.Equal("Bar", output2[2].Value); + })); [Fact] - public void WhenAnyValueShouldWorkEvenWithNormalProperties() - { - var fixture = new TestFixture + public async Task WhenAnyValueShouldWorkEvenWithNormalProperties() => + await RunAppBuilderTestAsync(() => { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }; + var fixture = new TestFixture + { + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }; - var output1 = new List(); - var output2 = new List(); - fixture.WhenAnyValue(x => x.PocoProperty).Subscribe(output1.Add); - fixture.WhenAnyValue(x => x.IsOnlyOneWord, x => x?.Length).Subscribe(output2.Add); + var output1 = new List(); + var output2 = new List(); + fixture.WhenAnyValue(x => x.PocoProperty).Subscribe(output1.Add); + fixture.WhenAnyValue(x => x.IsOnlyOneWord, x => x?.Length).Subscribe(output2.Add); - Assert.Equal(1, output1.Count); - Assert.Equal("Bamf", output1[0]); - Assert.Equal(1, output2.Count); - Assert.Equal(3, output2[0]); - } + Assert.Equal(1, output1.Count); + Assert.Equal("Bamf", output1[0]); + Assert.Equal(1, output2.Count); + Assert.Equal(3, output2[0]); + }); [Fact] - public void WhenAnyValueSmokeTest() => - new TestScheduler().With( - scheduler => - { - var fixture = new HostTestFixture + public async Task WhenAnyValueSmokeTest() => + await RunAppBuilderTestAsync(() => + new TestScheduler().With( + scheduler => { - Child = new TestFixture(), - SomeOtherParam = 5 - }; - fixture.Child.IsNotNullString = "Foo"; - - var output1 = new List(); - var output2 = new List(); - fixture.WhenAnyValue( - x => x.SomeOtherParam, - x => x.Child!.IsNotNullString, - (sop, nns) => new + var fixture = new HostTestFixture { - sop, - nns - }).Subscribe( - x => - { - output1.Add(x!.sop); - output2.Add(x.nns!); - }); - - scheduler.Start(); - Assert.Equal(1, output1.Count); - Assert.Equal(1, output2.Count); - Assert.Equal(5, output1[0]); - Assert.Equal("Foo", output2[0]); - - fixture.SomeOtherParam = 10; - scheduler.Start(); - Assert.Equal(2, output1.Count); - Assert.Equal(2, output2.Count); - Assert.Equal(10, output1[1]); - Assert.Equal("Foo", output2[1]); - - fixture.Child.IsNotNullString = "Bar"; - scheduler.Start(); - Assert.Equal(3, output1.Count); - Assert.Equal(3, output2.Count); - Assert.Equal(10, output1[2]); - Assert.Equal("Bar", output2[2]); - }); + Child = new TestFixture(), + SomeOtherParam = 5 + }; + fixture.Child.IsNotNullString = "Foo"; + + var output1 = new List(); + var output2 = new List(); + fixture.WhenAnyValue( + x => x.SomeOtherParam, + x => x.Child!.IsNotNullString, + (sop, nns) => new + { + sop, + nns + }).Subscribe( + x => + { + output1.Add(x!.sop); + output2.Add(x.nns!); + }); + + scheduler.Start(); + Assert.Equal(1, output1.Count); + Assert.Equal(1, output2.Count); + Assert.Equal(5, output1[0]); + Assert.Equal("Foo", output2[0]); + + fixture.SomeOtherParam = 10; + scheduler.Start(); + Assert.Equal(2, output1.Count); + Assert.Equal(2, output2.Count); + Assert.Equal(10, output1[1]); + Assert.Equal("Foo", output2[1]); + + fixture.Child.IsNotNullString = "Bar"; + scheduler.Start(); + Assert.Equal(3, output1.Count); + Assert.Equal(3, output2.Count); + Assert.Equal(10, output1[2]); + Assert.Equal("Bar", output2[2]); + })); [Fact] - public void ObjectShouldBeGarbageCollectedWhenPropertyValueChanges() - { - static (ObjChain1, WeakReference) GetWeakReference1() + public async Task ObjectShouldBeGarbageCollectedWhenPropertyValueChanges() => + await RunAppBuilderTestAsync(() => { - var obj = new ObjChain1(); - var weakRef = new WeakReference(obj.Model); - obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); - obj.Model = new ObjChain2(); + static (ObjChain1, WeakReference) GetWeakReference1() + { + var obj = new ObjChain1(); + var weakRef = new WeakReference(obj.Model); + obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); + obj.Model = new ObjChain2(); - return (obj, weakRef); - } + return (obj, weakRef); + } - static (ObjChain1, WeakReference) GetWeakReference2() - { - var obj = new ObjChain1(); - var weakRef = new WeakReference(obj.Model.Model); - obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); - obj.Model.Model = new ObjChain3(); + static (ObjChain1, WeakReference) GetWeakReference2() + { + var obj = new ObjChain1(); + var weakRef = new WeakReference(obj.Model.Model); + obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); + obj.Model.Model = new ObjChain3(); - return (obj, weakRef); - } + return (obj, weakRef); + } - static (ObjChain1, WeakReference) GetWeakReference3() - { - var obj = new ObjChain1(); - var weakRef = new WeakReference(obj.Model.Model.Model); - obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); - obj.Model.Model.Model = new HostTestFixture(); + static (ObjChain1, WeakReference) GetWeakReference3() + { + var obj = new ObjChain1(); + var weakRef = new WeakReference(obj.Model.Model.Model); + obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); + obj.Model.Model.Model = new HostTestFixture(); - return (obj, weakRef); - } + return (obj, weakRef); + } - var (obj1, weakRef1) = GetWeakReference1(); - var (obj2, weakRef2) = GetWeakReference2(); - var (obj3, weakRef3) = GetWeakReference3(); + var (obj1, weakRef1) = GetWeakReference1(); + var (obj2, weakRef2) = GetWeakReference2(); + var (obj3, weakRef3) = GetWeakReference3(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + GC.Collect(); + GC.WaitForPendingFinalizers(); - Assert.False(weakRef1.IsAlive); - Assert.False(weakRef2.IsAlive); - Assert.False(weakRef3.IsAlive); - } + Assert.False(weakRef1.IsAlive); + Assert.False(weakRef2.IsAlive); + Assert.False(weakRef3.IsAlive); + }); [Fact] - public void WhenAnyValueUnsupportedExpressionType_Equal() - { - var fixture = new TestFixture(); - var exception = Assert.Throws( - () => fixture.WhenAnyValue(x => x.IsNotNullString == x.IsOnlyOneWord).Subscribe()); + public async Task WhenAnyValueUnsupportedExpressionType_Equal() => + await RunAppBuilderTestAsync(() => + { + var fixture = new TestFixture(); + var exception = Assert.Throws( + () => fixture.WhenAnyValue(x => x.IsNotNullString == x.IsOnlyOneWord).Subscribe()); - Assert.Equal("Unsupported expression of type 'Equal' (x.IsNotNullString == x.IsOnlyOneWord). Did you meant to use expressions 'x.IsNotNullString' and 'x.IsOnlyOneWord'?", exception.Message); - } + Assert.Equal("Unsupported expression of type 'Equal' (x.IsNotNullString == x.IsOnlyOneWord). Did you meant to use expressions 'x.IsNotNullString' and 'x.IsOnlyOneWord'?", exception.Message); + }); [Fact] - public void WhenAnyValueUnsupportedExpressionType_Constant() - { - var fixture = new TestFixture(); - var exception = Assert.Throws( - () => fixture.WhenAnyValue(_ => Dummy).Subscribe()); + public async Task WhenAnyValueUnsupportedExpressionType_Constant() => + await RunAppBuilderTestAsync(() => + { + var fixture = new TestFixture(); + var exception = Assert.Throws( + () => fixture.WhenAnyValue(_ => Dummy).Subscribe()); - Assert.Equal("Unsupported expression of type 'Constant'. Did you miss the member access prefix in the expression?", exception.Message); - } + Assert.Equal("Unsupported expression of type 'Constant'. Did you miss the member access prefix in the expression?", exception.Message); + }); [Fact] - public void NullableTypesTestShouldntNeedDecorators() - { - var fixture = new WhenAnyTestFixture(); - IEnumerable? result = null; - fixture.WhenAnyValue(x => x.AccountService.AccountUsersNullable) - .Where(users => users.Count > 0) - .Select(users => users.Values.Where(x => !string.IsNullOrWhiteSpace(x?.LastName))) - .Subscribe(dict => result = dict); - - Assert.Equal(result!.Count(), 3); - } + public async Task NullableTypesTestShouldntNeedDecorators() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + IEnumerable? result = null; + fixture.WhenAnyValue(x => x.AccountService.AccountUsersNullable) + .Where(users => users.Count > 0) + .Select(users => users.Values.Where(x => !string.IsNullOrWhiteSpace(x?.LastName))) + .Subscribe(dict => result = dict); + + Assert.Equal(result!.Count(), 3); + }); - /// - /// Nullables the types test shouldnt need decorators2. - /// [Fact] - public void NullableTypesTestShouldntNeedDecorators2() - { - var fixture = new WhenAnyTestFixture(); - IEnumerable? result = null; - fixture.WhenAnyValue( - x => x.ProjectService.ProjectsNullable, - x => x.AccountService.AccountUsersNullable) - .Where(tuple => tuple.Item1?.Count > 0 && tuple.Item2?.Count > 0) - .Select(tuple => - { - var (projects, users) = tuple; - return users?.Values.Where(x => !string.IsNullOrWhiteSpace(x?.LastName)); - }) - .Subscribe(dict => result = dict); - - Assert.Equal(result!.Count(), 3); - } + public async Task NullableTypesTestShouldntNeedDecorators2() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + IEnumerable? result = null; + fixture.WhenAnyValue( + x => x.ProjectService.ProjectsNullable, + x => x.AccountService.AccountUsersNullable) + .Where(tuple => tuple.Item1?.Count > 0 && tuple.Item2?.Count > 0) + .Select(tuple => + { + var (projects, users) = tuple; + return users?.Values.Where(x => !string.IsNullOrWhiteSpace(x?.LastName)); + }) + .Subscribe(dict => result = dict); + + Assert.Equal(result!.Count(), 3); + }); - /// - /// Nons the nullable types test shouldnt need decorators. - /// [Fact] - public void NonNullableTypesTestShouldntNeedDecorators() - { - var fixture = new WhenAnyTestFixture(); - IEnumerable? result = null; - fixture.WhenAnyValue(x => x.AccountService.AccountUsers) - .Where(users => users.Count > 0) - .Select(users => users.Values.Where(x => !string.IsNullOrWhiteSpace(x.LastName))) - .Subscribe(dict => result = dict); - - Assert.Equal(result!.Count(), 3); - } + public async Task NonNullableTypesTestShouldntNeedDecorators() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + IEnumerable? result = null; + fixture.WhenAnyValue(x => x.AccountService.AccountUsers) + .Where(users => users.Count > 0) + .Select(users => users.Values.Where(x => !string.IsNullOrWhiteSpace(x.LastName))) + .Subscribe(dict => result = dict); + + Assert.Equal(result!.Count(), 3); + }); - /// - /// Nons the nullable types test shouldnt need decorators2. - /// [Fact] - public void NonNullableTypesTestShouldntNeedDecorators2() - { - var fixture = new WhenAnyTestFixture(); - IEnumerable? result = null; - fixture.WhenAnyValue( - x => x.ProjectService.Projects, - x => x.AccountService.AccountUsers) - .Where(tuple => tuple.Item1?.Count > 0 && tuple.Item2?.Count > 0) - .Select(tuple => - { - var (projects, users) = tuple; - return users!.Values.Where(x => !string.IsNullOrWhiteSpace(x.LastName)); - }) - .Subscribe(dict => result = dict); - - Assert.Equal(result!.Count(), 3); - } + public async Task NonNullableTypesTestShouldntNeedDecorators2() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + IEnumerable? result = null; + fixture.WhenAnyValue( + x => x.ProjectService.Projects, + x => x.AccountService.AccountUsers) + .Where(tuple => tuple.Item1?.Count > 0 && tuple.Item2?.Count > 0) + .Select(tuple => + { + var (projects, users) = tuple; + return users!.Values.Where(x => !string.IsNullOrWhiteSpace(x.LastName)); + }) + .Subscribe(dict => result = dict); + + Assert.Equal(result!.Count(), 3); + }); - /// - /// Whens any value with1 paramerters. - /// [Fact] - public void WhenAnyValueWith1Paramerters() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1).Subscribe(value => result = value); + public async Task WhenAnyValueWith1Paramerters() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1).Subscribe(value => result = value); - Assert.Equal(result, "1"); - } + Assert.Equal(result, "1"); + }); [Fact] - public void WhenAnyValueWith1ParamertersSequentialCheck() - { - var fixture = new WhenAnyTestFixture(); - var result = string.Empty; - fixture.Value1 = null!; - fixture.WhenAnyValue( - x => x.Value1).Subscribe(value => result = value); + public async Task WhenAnyValueWith1ParamertersSequentialCheck() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + var result = string.Empty; + fixture.Value1 = null!; + fixture.WhenAnyValue( + x => x.Value1).Subscribe(value => result = value); - Assert.Equal(result, null); + Assert.Equal(result, null); - fixture.Value1 = "A"; - Assert.Equal(result, "A"); + fixture.Value1 = "A"; + Assert.Equal(result, "A"); - fixture.Value1 = "B"; - Assert.Equal(result, "B"); + fixture.Value1 = "B"; + Assert.Equal(result, "B"); - fixture.Value1 = null!; - Assert.Equal(result, null); - } + fixture.Value1 = null!; + Assert.Equal(result, null); + }); [Fact] - public void WhenAnyValueWith1ParamertersSequentialCheckNullable() - { - var fixture = new WhenAnyTestFixture(); - var result = string.Empty; - fixture.WhenAnyValue( - x => x.Value2).Subscribe(value => result = value); + public async Task WhenAnyValueWith1ParamertersSequentialCheckNullable() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + var result = string.Empty; + fixture.WhenAnyValue( + x => x.Value2).Subscribe(value => result = value); - Assert.Equal(result, null); + Assert.Equal(result, null); - fixture.Value2 = "A"; - Assert.Equal(result, "A"); + fixture.Value2 = "A"; + Assert.Equal(result, "A"); - fixture.Value2 = "B"; - Assert.Equal(result, "B"); + fixture.Value2 = "B"; + Assert.Equal(result, "B"); - fixture.Value2 = null; - Assert.Equal(result, null); - } + fixture.Value2 = null; + Assert.Equal(result, null); + }); - /// - /// Whens any value with2 paramerters returns tuple. - /// [Fact] - public void WhenAnyValueWith2ParamertersReturnsTuple() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2) - .Select(tuple => - { - var (value1, value2) = tuple; - return value1 + value2; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1"); - } + public async Task WhenAnyValueWith2ParamertersReturnsTuple() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2) + .Select(tuple => + { + var (value1, value2) = tuple; + return value1 + value2; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1"); + }); - /// - /// Whens any value with2 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith2ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - (v1, v2) => (v1, v2)) - .Select(tuple => - { - var (value1, value2) = tuple; - return value1 + value2; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1"); - } + public async Task WhenAnyValueWith2ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + (v1, v2) => (v1, v2)) + .Select(tuple => + { + var (value1, value2) = tuple; + return value1 + value2; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1"); + }); - /// - /// Whens any value with3 paramerters returns tuple. - /// [Fact] - public void WhenAnyValueWith3ParamertersReturnsTuple() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3) - .Select(tuple => - { - var (value1, value2, value3) = tuple; - return value1 + value2 + value3; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13"); - } + public async Task WhenAnyValueWith3ParamertersReturnsTuple() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3) + .Select(tuple => + { + var (value1, value2, value3) = tuple; + return value1 + value2 + value3; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13"); + }); - /// - /// Whens any value with3 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith3ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - (v1, v2, v3) => (v1, v2, v3)) - .Select(tuple => - { - var (value1, value2, value3) = tuple; - return value1 + value2 + value3; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13"); - } + public async Task WhenAnyValueWith3ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + (v1, v2, v3) => (v1, v2, v3)) + .Select(tuple => + { + var (value1, value2, value3) = tuple; + return value1 + value2 + value3; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13"); + }); - /// - /// Whens any value with4 paramerters returns tuple. - /// [Fact] - public void WhenAnyValueWith4ParamertersReturnsTuple() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4) - .Select(tuple => - { - var (value1, value2, value3, value4) = tuple; - return value1 + value2 + value3 + value4; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13"); - } + public async Task WhenAnyValueWith4ParamertersReturnsTuple() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4) + .Select(tuple => + { + var (value1, value2, value3, value4) = tuple; + return value1 + value2 + value3 + value4; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13"); + }); - /// - /// Whens any value with4 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith4ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - (v1, v2, v3, v4) => (v1, v2, v3, v4)) - .Select(tuple => - { - var (value1, value2, value3, value4) = tuple; - return value1 + value2 + value3 + value4; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13"); - } + public async Task WhenAnyValueWith4ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + (v1, v2, v3, v4) => (v1, v2, v3, v4)) + .Select(tuple => + { + var (value1, value2, value3, value4) = tuple; + return value1 + value2 + value3 + value4; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13"); + }); - /// - /// Whens any value with5 paramerters returns tuple. - /// [Fact] - public void WhenAnyValueWith5ParamertersReturnsTuple() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5) - .Select(tuple => - { - var (value1, value2, value3, value4, value5) = tuple; - return value1 + value2 + value3 + value4 + value5; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "135"); - } + public async Task WhenAnyValueWith5ParamertersReturnsTuple() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5) + .Select(tuple => + { + var (value1, value2, value3, value4, value5) = tuple; + return value1 + value2 + value3 + value4 + value5; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "135"); + }); - /// - /// Whens any value with5 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith5ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - (v1, v2, v3, v4, v5) => (v1, v2, v3, v4, v5)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5) = tuple; - return value1 + value2 + value3 + value4 + value5; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "135"); - } + public async Task WhenAnyValueWith5ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + (v1, v2, v3, v4, v5) => (v1, v2, v3, v4, v5)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5) = tuple; + return value1 + value2 + value3 + value4 + value5; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "135"); + }); - /// - /// Whens any value with6 paramerters returns tuple. - /// [Fact] - public void WhenAnyValueWith6ParamertersReturnsTuple() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "135"); - } + public async Task WhenAnyValueWith6ParamertersReturnsTuple() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "135"); + }); - /// - /// Whens any value with6 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith6ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - (v1, v2, v3, v4, v5, v6) => (v1, v2, v3, v4, v5, v6)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "135"); - } + public async Task WhenAnyValueWith6ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + (v1, v2, v3, v4, v5, v6) => (v1, v2, v3, v4, v5, v6)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "135"); + }); - /// - /// Whens any value with7 paramerters returns tuple. - /// [Fact] - public void WhenAnyValueWith7ParamertersReturnsTuple() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1357"); - } + public async Task WhenAnyValueWith7ParamertersReturnsTuple() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1357"); + }); - /// - /// Whens any value with7 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith7ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - (v1, v2, v3, v4, v5, v6, v7) => (v1, v2, v3, v4, v5, v6, v7)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1357"); - } + public async Task WhenAnyValueWith7ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + (v1, v2, v3, v4, v5, v6, v7) => (v1, v2, v3, v4, v5, v6, v7)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1357"); + }); - /// - /// Whens any value with8 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith8ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - x => x.Value8, - (v1, v2, v3, v4, v5, v6, v7, v8) => (v1, v2, v3, v4, v5, v6, v7, v8)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7, value8) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1357"); - } + public async Task WhenAnyValueWith8ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + x => x.Value8, + (v1, v2, v3, v4, v5, v6, v7, v8) => (v1, v2, v3, v4, v5, v6, v7, v8)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7, value8) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1357"); + }); - /// - /// Whens any value with8 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith9ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - x => x.Value8, - x => x.Value9, - (v1, v2, v3, v4, v5, v6, v7, v8, v9) => (v1, v2, v3, v4, v5, v6, v7, v8, v9)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7, value8, value9) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13579"); - } + public async Task WhenAnyValueWith9ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + x => x.Value8, + x => x.Value9, + (v1, v2, v3, v4, v5, v6, v7, v8, v9) => (v1, v2, v3, v4, v5, v6, v7, v8, v9)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7, value8, value9) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13579"); + }); - /// - /// Whens any value with8 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith10ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - x => x.Value8, - x => x.Value9, - x => x.Value10, - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13579"); - } + public async Task WhenAnyValueWith10ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + x => x.Value8, + x => x.Value9, + x => x.Value10, + (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13579"); + }); - /// - /// Whens any value with8 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith11ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - x => x.Value8, - x => x.Value9, - x => x.Value10, - x => x.Value11, - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10 + value11; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1357911"); - } + public async Task WhenAnyValueWith11ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + x => x.Value8, + x => x.Value9, + x => x.Value10, + x => x.Value11, + (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10 + value11; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1357911"); + }); - /// - /// Whens any value with8 paramerters returns values. - /// [Fact] - public void WhenAnyValueWith12ParamertersReturnsValues() - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - x => x.Value8, - x => x.Value9, - x => x.Value10, - x => x.Value11, - x => x.Value12, - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11, value12) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10 + value11 + value12; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1357911"); - } + public async Task WhenAnyValueWith12ParamertersReturnsValues() => + await RunAppBuilderTestAsync(() => + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + x => x.Value8, + x => x.Value9, + x => x.Value10, + x => x.Value11, + x => x.Value12, + (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11, value12) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10 + value11 + value12; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1357911"); + }); [Fact] - public void WhenAnyValueWithToProperty() - { - var fixture = new HostTestFixture(); + public async Task WhenAnyValueWithToProperty() => + await RunAppBuilderTestAsync(() => + { + var fixture = new HostTestFixture(); - Assert.Equal(null, fixture.Owner); - Assert.Equal(null, fixture.OwnerName); + Assert.Equal(null, fixture.Owner); + Assert.Equal(null, fixture.OwnerName); - fixture.Owner = new() - { - Name = "Fred" - }; - Assert.NotNull(fixture.Owner); - Assert.Equal("Fred", fixture.OwnerName); + fixture.Owner = new() + { + Name = "Fred" + }; + Assert.NotNull(fixture.Owner); + Assert.Equal("Fred", fixture.OwnerName); - fixture.Owner.Name = "Wilma"; - Assert.Equal("Wilma", fixture.OwnerName); + fixture.Owner.Name = "Wilma"; + Assert.Equal("Wilma", fixture.OwnerName); - fixture.Owner.Name = null; - Assert.Equal(null, fixture.OwnerName); + fixture.Owner.Name = null; + Assert.Equal(null, fixture.OwnerName); - fixture.Owner.Name = "Barney"; - Assert.Equal("Barney", fixture.OwnerName); + fixture.Owner.Name = "Barney"; + Assert.Equal("Barney", fixture.OwnerName); - fixture.Owner.Name = "Betty"; - Assert.Equal("Betty", fixture.OwnerName); - } + fixture.Owner.Name = "Betty"; + Assert.Equal("Betty", fixture.OwnerName); + }); } diff --git a/src/ReactiveUI/Builder/ReactiveUIBuilder.cs b/src/ReactiveUI/Builder/ReactiveUIBuilder.cs index 6394c130a0..ca9ade9a83 100644 --- a/src/ReactiveUI/Builder/ReactiveUIBuilder.cs +++ b/src/ReactiveUI/Builder/ReactiveUIBuilder.cs @@ -3,7 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; using System.Reflection; using Splat.Builder; diff --git a/src/ReactiveUI/Mixins/DependencyResolverMixins.cs b/src/ReactiveUI/Mixins/DependencyResolverMixins.cs index 05c21dba38..4641c46d33 100644 --- a/src/ReactiveUI/Mixins/DependencyResolverMixins.cs +++ b/src/ReactiveUI/Mixins/DependencyResolverMixins.cs @@ -3,7 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; using System.Reflection; using Splat.Builder; diff --git a/src/ReactiveUI/Mixins/MutableDependencyResolverExtensions.cs b/src/ReactiveUI/Mixins/MutableDependencyResolverExtensions.cs index 3f234623e4..a977c3a625 100644 --- a/src/ReactiveUI/Mixins/MutableDependencyResolverExtensions.cs +++ b/src/ReactiveUI/Mixins/MutableDependencyResolverExtensions.cs @@ -3,8 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; - namespace ReactiveUI; /// diff --git a/src/ReactiveUI/View/DefaultViewLocator.AOT.cs b/src/ReactiveUI/View/DefaultViewLocator.AOT.cs index eed4427e2a..0dda87adc1 100644 --- a/src/ReactiveUI/View/DefaultViewLocator.AOT.cs +++ b/src/ReactiveUI/View/DefaultViewLocator.AOT.cs @@ -4,7 +4,6 @@ // See the LICENSE file in the project root for full license information. using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; namespace ReactiveUI; diff --git a/src/ReactiveUI/View/DefaultViewLocator.cs b/src/ReactiveUI/View/DefaultViewLocator.cs index d0af7f3f0a..4058baf95e 100644 --- a/src/ReactiveUI/View/DefaultViewLocator.cs +++ b/src/ReactiveUI/View/DefaultViewLocator.cs @@ -3,7 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; From 961c70c37b884d8cc9b239f278e74809f9046695 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Thu, 28 Aug 2025 07:51:16 +0100 Subject: [PATCH 09/11] Fix API tests --- .../API/ApiApprovalTests.Testing.DotNet8_0.verified.txt | 2 +- .../API/ApiApprovalTests.Testing.DotNet9_0.verified.txt | 2 +- .../API/ApiApprovalTests.Testing.Net4_7.verified.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt index c503136929..9d8befb502 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet8_0.verified.txt @@ -33,7 +33,7 @@ namespace ReactiveUI.Testing } public static class RxTest { - public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 30000) { } + public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 60000) { } } public static class SchedulerExtensions { diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt index bc32960280..657a91b7f3 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.DotNet9_0.verified.txt @@ -33,7 +33,7 @@ namespace ReactiveUI.Testing } public static class RxTest { - public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 30000) { } + public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 60000) { } } public static class SchedulerExtensions { diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt index 254d2da388..add251bfe2 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.Testing.Net4_7.verified.txt @@ -33,7 +33,7 @@ namespace ReactiveUI.Testing } public static class RxTest { - public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 30000) { } + public static System.Threading.Tasks.Task AppBuilderTestAsync(System.Func testBody, int maxWaitMs = 60000) { } } public static class SchedulerExtensions { From de7f5af34d1dd0bdf07bdc0c529a09f76d3e6bf5 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Thu, 28 Aug 2025 09:01:36 +0100 Subject: [PATCH 10/11] Revert tests --- .../AOTCompatibilityTests.cs | 1 - src/ReactiveUI.AOTTests/AdvancedAOTTests.cs | 1 - .../ComprehensiveAOTMarkupTests.cs | 1 - .../ComprehensiveAOTTests.cs | 3 +- .../FinalAOTValidationTests.cs | 1 - .../Properties/TestConfiguration.cs | 6 - .../StringBasedObservationTests.cs | 2 + .../StringBasedSemanticsTests.cs | 1 - .../{Mocks => }/TestActivatableViewModel.cs | 2 +- .../{Mocks => }/TestReactiveObject.cs | 2 +- .../{Mocks => }/TestRoutableViewModel.cs | 2 +- .../ViewLocatorAOTMappingTests.cs | 2 + .../ReactiveUI.Builder.Maui.Tests.csproj | 1 - .../ReactiveUIBuilderMauiTests.cs | 43 +- .../TestConfiguration.cs | 6 - .../Blazor/ReactiveUIBuilderBlazorTests.cs | 49 +- .../Drawing/ReactiveUIBuilderDrawingTests.cs | 27 +- .../ReactiveUIBuilderWinFormsTests.cs | 49 +- .../Wpf/ReactiveUIBuilderWpfTests.cs | 49 +- .../ReactiveUI.Builder.Tests.csproj | 1 - .../ReactiveUIBuilderBlockingTests.cs | 24 +- .../ReactiveUIBuilderCoreTests.cs | 221 +- .../TestConfiguration.cs | 6 - src/ReactiveUI.LeakTests/TestConfiguration.cs | 8 - .../TestConfiguration.cs | 8 - .../TestConfiguration.cs | 8 - .../xunit.runner.json | 4 +- src/ReactiveUI.Tests/API/ApiApprovalTests.cs | 2 +- .../Activation/{Mocks => }/ActivatingView.cs | 2 +- .../{Mocks => }/ActivatingViewFetcher.cs | 2 +- .../{Mocks => }/ActivatingViewModel.cs | 2 +- .../Activation/ActivatingViewModelTests.cs | 78 +- .../Activation/ActivatingViewTests.cs | 267 +- .../Activation/CanActivateViewFetcherTests.cs | 83 +- .../{Mocks => }/DerivedActivatingViewModel.cs | 2 +- .../Activation/ViewModelActivatorTests.cs | 96 +- .../AutoPersist/AutoPersistCollectionTests.cs | 4 +- .../AutoPersist/AutoPersistHelperTest.cs | 4 +- src/ReactiveUI.Tests/AwaiterTest.cs | 2 +- .../BindingTypeConvertersTest.cs | 2 +- .../Commands/CombinedReactiveCommandTest.cs | 4 +- .../Commands/CreatesCommandBindingTests.cs | 36 +- .../Commands/ReactiveCommandTest.cs | 4 +- .../Comparers/OrderedComparerTests.cs | 2 +- src/ReactiveUI.Tests/GlobalUsings.cs | 3 - .../InteractionBinderImplementationTests.cs | 2 +- src/ReactiveUI.Tests/InteractionsTest.cs | 4 +- .../Locator/DefaultViewLocatorTests.cs | 2 +- src/ReactiveUI.Tests/MessageBusTest.cs | 326 ++- .../ObservableAsPropertyHelperTest.cs | 4 +- .../ObservedChanged/NewGameViewModelTests.cs | 2 +- .../ObservedChangedMixinTest.cs | 4 +- .../CommandBindingImplementationTests.cs | 260 +- .../windows-xaml/PropertyBindingTest.cs | 436 +++- .../RxAppDependencyObjectTests.cs | 16 +- .../WhenAnyThroughDependencyObjectTests.cs | 44 +- .../XamlViewDependencyResolverTests.cs | 36 +- .../Platforms/winforms/ActivationTests.cs | 194 +- .../CommandBindingImplementationTests.cs | 166 +- .../Platforms/winforms/CommandBindingTests.cs | 208 +- .../ReactiveUIBuilderWinFormsTests.cs | 62 - .../WinFormsViewDependencyResolverTests.cs | 125 +- .../wpf/ReactiveUIBuilderWpfTests.cs | 70 - .../wpf/WpfActivationForViewFetcherTest.cs | 192 +- .../Platforms/wpf/WpfActiveContentTests.cs | 519 ++-- .../WpfCommandBindingImplementationTests.cs | 398 ++- .../wpf/WpfViewDependencyResolverTests.cs | 17 +- .../ReactiveObject/ReactiveObjectTests.cs | 2 +- .../ReactiveProperty/ReactivePropertyTest.cs | 3 +- .../Resolvers/DependencyResolverTests.cs | 2 +- .../INPCObservableForPropertyTests.cs | 2 +- .../PocoObservableForPropertyTests.cs | 2 +- .../Routing/RoutableViewModelMixinTests.cs | 2 +- .../Routing/RoutedViewHostTests.cs | 2 +- .../Routing/RoutingStateTests.cs | 4 +- .../Routing/ViewModelViewHostTests.cs | 2 +- src/ReactiveUI.Tests/RxAppTest.cs | 15 +- .../SuspensionHostExtensionsTests.cs | 2 +- .../{Properties => }/TestConfiguration.cs | 0 .../WaitForDispatcherSchedulerTests.cs | 2 +- .../ReactiveNotifyPropertyChangedMixinTest.cs | 2228 +++++++++-------- .../WhenAny/WhenAnyObservableTests.cs | 2 +- src/ReactiveUI.Tests/xunit.runner.json | 4 +- 83 files changed, 3222 insertions(+), 3262 deletions(-) delete mode 100644 src/ReactiveUI.AOTTests/Properties/TestConfiguration.cs rename src/ReactiveUI.AOTTests/{Mocks => }/TestActivatableViewModel.cs (93%) rename src/ReactiveUI.AOTTests/{Mocks => }/TestReactiveObject.cs (98%) rename src/ReactiveUI.AOTTests/{Mocks => }/TestRoutableViewModel.cs (94%) delete mode 100644 src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs delete mode 100644 src/ReactiveUI.Builder.Tests/TestConfiguration.cs delete mode 100644 src/ReactiveUI.LeakTests/TestConfiguration.cs delete mode 100644 src/ReactiveUI.Splat.Tests/TestConfiguration.cs delete mode 100644 src/ReactiveUI.Testing.Tests/TestConfiguration.cs rename src/ReactiveUI.Tests/Activation/{Mocks => }/ActivatingView.cs (97%) rename src/ReactiveUI.Tests/Activation/{Mocks => }/ActivatingViewFetcher.cs (97%) rename src/ReactiveUI.Tests/Activation/{Mocks => }/ActivatingViewModel.cs (96%) rename src/ReactiveUI.Tests/Activation/{Mocks => }/DerivedActivatingViewModel.cs (95%) delete mode 100644 src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs delete mode 100644 src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs rename src/ReactiveUI.Tests/{Properties => }/TestConfiguration.cs (100%) diff --git a/src/ReactiveUI.AOTTests/AOTCompatibilityTests.cs b/src/ReactiveUI.AOTTests/AOTCompatibilityTests.cs index 2db7ce8bc1..aab6a4ca7d 100644 --- a/src/ReactiveUI.AOTTests/AOTCompatibilityTests.cs +++ b/src/ReactiveUI.AOTTests/AOTCompatibilityTests.cs @@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis; using System.Reactive.Linq; -using ReactiveUI.AOT.Tests.Mocks; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/AdvancedAOTTests.cs b/src/ReactiveUI.AOTTests/AdvancedAOTTests.cs index 69a3e40d79..a51b5bffde 100644 --- a/src/ReactiveUI.AOTTests/AdvancedAOTTests.cs +++ b/src/ReactiveUI.AOTTests/AdvancedAOTTests.cs @@ -7,7 +7,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; -using ReactiveUI.AOT.Tests.Mocks; using Splat; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/ComprehensiveAOTMarkupTests.cs b/src/ReactiveUI.AOTTests/ComprehensiveAOTMarkupTests.cs index b7a32c343a..0a4398c7ed 100644 --- a/src/ReactiveUI.AOTTests/ComprehensiveAOTMarkupTests.cs +++ b/src/ReactiveUI.AOTTests/ComprehensiveAOTMarkupTests.cs @@ -8,7 +8,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; -using ReactiveUI.AOT.Tests.Mocks; using Splat; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/ComprehensiveAOTTests.cs b/src/ReactiveUI.AOTTests/ComprehensiveAOTTests.cs index 9a6332cecd..cc4249218d 100644 --- a/src/ReactiveUI.AOTTests/ComprehensiveAOTTests.cs +++ b/src/ReactiveUI.AOTTests/ComprehensiveAOTTests.cs @@ -8,7 +8,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; -using ReactiveUI.AOT.Tests.Mocks; using Splat; namespace ReactiveUI.AOTTests; @@ -162,6 +161,8 @@ public void ObservableAsPropertyHelper_StringBased_WorksInAOT() [Fact] public void DependencyInjection_BasicUsage_WorksInAOT() { + Splat.Builder.AppBuilder.ResetBuilderStateForTests(); + // Basic DI operations that work in AOT var resolver = Locator.CurrentMutable; diff --git a/src/ReactiveUI.AOTTests/FinalAOTValidationTests.cs b/src/ReactiveUI.AOTTests/FinalAOTValidationTests.cs index 84044a9dbc..1650608ca1 100644 --- a/src/ReactiveUI.AOTTests/FinalAOTValidationTests.cs +++ b/src/ReactiveUI.AOTTests/FinalAOTValidationTests.cs @@ -9,7 +9,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; -using ReactiveUI.AOT.Tests.Mocks; using Splat; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/Properties/TestConfiguration.cs b/src/ReactiveUI.AOTTests/Properties/TestConfiguration.cs deleted file mode 100644 index 7ff7f58d81..0000000000 --- a/src/ReactiveUI.AOTTests/Properties/TestConfiguration.cs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.AOTTests/StringBasedObservationTests.cs b/src/ReactiveUI.AOTTests/StringBasedObservationTests.cs index 7e0aefa922..00787e8119 100644 --- a/src/ReactiveUI.AOTTests/StringBasedObservationTests.cs +++ b/src/ReactiveUI.AOTTests/StringBasedObservationTests.cs @@ -3,6 +3,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; +using System.Reactive.Concurrency; using System.Reactive.Linq; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/StringBasedSemanticsTests.cs b/src/ReactiveUI.AOTTests/StringBasedSemanticsTests.cs index 6f000ba150..c1ecf8cc7e 100644 --- a/src/ReactiveUI.AOTTests/StringBasedSemanticsTests.cs +++ b/src/ReactiveUI.AOTTests/StringBasedSemanticsTests.cs @@ -4,7 +4,6 @@ // See the LICENSE file in the project root for full license information. using System.Reactive.Linq; -using ReactiveUI.AOT.Tests.Mocks; namespace ReactiveUI.AOTTests; diff --git a/src/ReactiveUI.AOTTests/Mocks/TestActivatableViewModel.cs b/src/ReactiveUI.AOTTests/TestActivatableViewModel.cs similarity index 93% rename from src/ReactiveUI.AOTTests/Mocks/TestActivatableViewModel.cs rename to src/ReactiveUI.AOTTests/TestActivatableViewModel.cs index 9184596ad5..594bc9b107 100644 --- a/src/ReactiveUI.AOTTests/Mocks/TestActivatableViewModel.cs +++ b/src/ReactiveUI.AOTTests/TestActivatableViewModel.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.AOT.Tests.Mocks; +namespace ReactiveUI.AOTTests; /// /// Test activatable view model for AOT testing. diff --git a/src/ReactiveUI.AOTTests/Mocks/TestReactiveObject.cs b/src/ReactiveUI.AOTTests/TestReactiveObject.cs similarity index 98% rename from src/ReactiveUI.AOTTests/Mocks/TestReactiveObject.cs rename to src/ReactiveUI.AOTTests/TestReactiveObject.cs index b69cbb9182..5c8776e8f5 100644 --- a/src/ReactiveUI.AOTTests/Mocks/TestReactiveObject.cs +++ b/src/ReactiveUI.AOTTests/TestReactiveObject.cs @@ -6,7 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reactive.Linq; -namespace ReactiveUI.AOT.Tests.Mocks; +namespace ReactiveUI.AOTTests; /// /// Test ReactiveObject for AOT compatibility testing. diff --git a/src/ReactiveUI.AOTTests/Mocks/TestRoutableViewModel.cs b/src/ReactiveUI.AOTTests/TestRoutableViewModel.cs similarity index 94% rename from src/ReactiveUI.AOTTests/Mocks/TestRoutableViewModel.cs rename to src/ReactiveUI.AOTTests/TestRoutableViewModel.cs index 894aa3b586..83b0bb9b7b 100644 --- a/src/ReactiveUI.AOTTests/Mocks/TestRoutableViewModel.cs +++ b/src/ReactiveUI.AOTTests/TestRoutableViewModel.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.AOT.Tests.Mocks; +namespace ReactiveUI.AOTTests; /// /// Test routable view model for AOT testing. diff --git a/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs b/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs index b44cd9fe05..031f49f5f8 100644 --- a/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs +++ b/src/ReactiveUI.AOTTests/ViewLocatorAOTMappingTests.cs @@ -3,6 +3,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Reactive.Linq; + namespace ReactiveUI.AOTTests; /// diff --git a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUI.Builder.Maui.Tests.csproj b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUI.Builder.Maui.Tests.csproj index 6ff58cd528..e823efff5c 100644 --- a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUI.Builder.Maui.Tests.csproj +++ b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUI.Builder.Maui.Tests.csproj @@ -8,7 +8,6 @@ - diff --git a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs index ef9738d390..99e8ce7d19 100644 --- a/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs +++ b/src/ReactiveUI.Builder.Maui.Tests/ReactiveUIBuilderMauiTests.cs @@ -3,41 +3,26 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Threading.Tasks; -using ReactiveUI.Testing; +using Splat.Builder; namespace ReactiveUI.Builder.Maui.Tests; -public class ReactiveUIBuilderMauiTests : AppBuilderTestBase +public class ReactiveUIBuilderMauiTests { [Fact] - public async Task WithMaui_Should_Register_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); + public void WithMaui_Should_Register_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); - locator.CreateReactiveUIBuilder() - .WithMaui() - .Build(); + locator.CreateReactiveUIBuilder() + .WithMaui() + .Build(); - var typeConverters = locator.GetServices(); - Assert.NotNull(typeConverters); - }); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - [Fact] - public async Task WithCoreServices_AndMaui_Should_Register_All_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - - locator.CreateReactiveUIBuilder() - .WithMaui() - .Build(); - - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); - - var typeConverters = locator.GetServices(); - Assert.NotNull(typeConverters); - }); + var typeConverters = locator.GetServices(); + Assert.NotNull(typeConverters); + } } diff --git a/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs b/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs deleted file mode 100644 index 7ff7f58d81..0000000000 --- a/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs index 57d066fb2e..976e9dd336 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/Blazor/ReactiveUIBuilderBlazorTests.cs @@ -3,41 +3,42 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Testing; +using ReactiveUI.Blazor; +using Splat.Builder; namespace ReactiveUI.Builder.Tests.Platforms.Blazor; -public class ReactiveUIBuilderBlazorTests : AppBuilderTestBase +public class ReactiveUIBuilderBlazorTests { [Fact] - public async Task WithBlazor_Should_Register_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public void WithBlazor_Should_Register_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithBlazor().Build(); + builder.WithBlazor().Build(); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); - var typeConverters = locator.GetServices(); - Assert.NotEmpty(typeConverters); - }); + var typeConverters = locator.GetServices(); + Assert.NotEmpty(typeConverters); + } [Fact] - public async Task WithCoreServices_AndBlazor_Should_Register_All_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public void WithCoreServices_AndBlazor_Should_Register_All_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithBlazor().Build(); + builder.WithBlazor().Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - }); + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); + } } diff --git a/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs index 98675c3e9e..01886f3c94 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/Drawing/ReactiveUIBuilderDrawingTests.cs @@ -3,24 +3,25 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Testing; +using ReactiveUI.Drawing; +using Splat.Builder; namespace ReactiveUI.Builder.Tests.Platforms.Drawing; -public class ReactiveUIBuilderDrawingTests : AppBuilderTestBase +public class ReactiveUIBuilderDrawingTests { [Fact] - public async Task WithDrawing_Should_Register_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public void WithDrawing_Should_Register_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithDrawing().Build(); + builder.WithDrawing().Build(); - // Drawing registers bitmap loader in non-NETSTANDARD contexts; we can still assert no exception and core services with chaining - locator.CreateReactiveUIBuilder().WithDrawing().Build(); - var bindingConverters = locator.GetServices(); - Assert.NotNull(bindingConverters); - }); + // Drawing registers bitmap loader in non-NETSTANDARD contexts; we can still assert no exception and core services with chaining + locator.CreateReactiveUIBuilder().WithDrawing().Build(); + var bindingConverters = locator.GetServices(); + Assert.NotNull(bindingConverters); + } } diff --git a/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs index 1ee8170120..2383b62bf2 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/WinForms/ReactiveUIBuilderWinFormsTests.cs @@ -3,41 +3,42 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Testing; +using ReactiveUI.Winforms; +using Splat.Builder; namespace ReactiveUI.Builder.Tests.Platforms.WinForms; -public class ReactiveUIBuilderWinFormsTests : AppBuilderTestBase +public class ReactiveUIBuilderWinFormsTests { [Fact] - public async Task WithWinForms_Should_Register_WinForms_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public void WithWinForms_Should_Register_WinForms_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithWinForms().Build(); + builder.WithWinForms().Build(); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); - var activationFetcher = locator.GetService(); - Assert.NotNull(activationFetcher); - }); + var activationFetcher = locator.GetService(); + Assert.NotNull(activationFetcher); + } [Fact] - public async Task WithCoreServices_AndWinForms_Should_Register_All_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public void WithCoreServices_AndWinForms_Should_Register_All_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithWinForms().Build(); + builder.WithWinForms().Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - }); + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); + } } diff --git a/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs b/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs index e3f06cbc68..967e5ea291 100644 --- a/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs +++ b/src/ReactiveUI.Builder.Tests/Platforms/Wpf/ReactiveUIBuilderWpfTests.cs @@ -3,41 +3,42 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Testing; +using ReactiveUI.Wpf; +using Splat.Builder; namespace ReactiveUI.Builder.Tests.Platforms.Wpf; -public class ReactiveUIBuilderWpfTests : AppBuilderTestBase +public class ReactiveUIBuilderWpfTests { [Fact] - public async Task WithWpf_Should_Register_Wpf_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public void WithWpf_Should_Register_Wpf_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithWpf().Build(); + builder.WithWpf().Build(); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); - var activationFetcher = locator.GetService(); - Assert.NotNull(activationFetcher); - }); + var activationFetcher = locator.GetService(); + Assert.NotNull(activationFetcher); + } [Fact] - public async Task WithCoreServices_AndWpf_Should_Register_All_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public void WithCoreServices_AndWpf_Should_Register_All_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithWpf().Build(); + builder.WithWpf().Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - }); + var platformOperations = locator.GetService(); + Assert.NotNull(platformOperations); + } } diff --git a/src/ReactiveUI.Builder.Tests/ReactiveUI.Builder.Tests.csproj b/src/ReactiveUI.Builder.Tests/ReactiveUI.Builder.Tests.csproj index fc9cb971df..f17d6c2922 100644 --- a/src/ReactiveUI.Builder.Tests/ReactiveUI.Builder.Tests.csproj +++ b/src/ReactiveUI.Builder.Tests/ReactiveUI.Builder.Tests.csproj @@ -16,7 +16,6 @@ - diff --git a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs index a0cc16b947..af8b9f6fc8 100644 --- a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs +++ b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderBlockingTests.cs @@ -3,27 +3,27 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Testing; +using Splat.Builder; namespace ReactiveUI.Builder.Tests; /// /// Tests ensuring the builder blocks reflection-based initialization. /// -public class ReactiveUIBuilderBlockingTests : AppBuilderTestBase +public class ReactiveUIBuilderBlockingTests { [Fact] - public async Task Build_SetsFlag_AndBlocks_InitializeReactiveUI() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); + public void Build_SetsFlag_AndBlocks_InitializeReactiveUI() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - builder.Build(); + var builder = locator.CreateReactiveUIBuilder(); + builder.WithCoreServices().Build(); - locator.InitializeReactiveUI(); + locator.InitializeReactiveUI(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); - }); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); + } } diff --git a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs index 59c8f0b8ec..96b6b0c97d 100644 --- a/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs +++ b/src/ReactiveUI.Builder.Tests/ReactiveUIBuilderCoreTests.cs @@ -3,149 +3,150 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using ReactiveUI.Testing; +using Splat.Builder; namespace ReactiveUI.Builder.Tests; /// /// Tests for the ReactiveUIBuilder core functionality. /// -public class ReactiveUIBuilderCoreTests : AppBuilderTestBase +public class ReactiveUIBuilderCoreTests { [Fact] - public async Task CreateBuilder_Should_Return_Builder_Instance() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - Assert.NotNull(builder); - Assert.IsType(builder); - }); + public void CreateBuilder_Should_Return_Builder_Instance() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + Assert.NotNull(builder); + Assert.IsType(builder); + } [Fact] - public async Task WithCoreServices_Should_Register_Core_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - builder.Build(); + public void WithCoreServices_Should_Register_Core_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + builder.WithCoreServices().Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); - var typeConverter = locator.GetService(); - Assert.NotNull(typeConverter); - }); + var typeConverter = locator.GetService(); + Assert.NotNull(typeConverter); + } [Fact] - public async Task WithPlatformServices_Should_Register_Platform_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - builder.Build(); - - var services = locator.GetServices(); - Assert.NotNull(services); - Assert.True(services.Any()); - }); + public void WithPlatformServices_Should_Register_Platform_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + builder.WithPlatformServices().Build(); + + var services = locator.GetServices(); + Assert.NotNull(services); + Assert.True(services.Any()); + } [Fact] - public async Task WithCustomRegistration_Should_Execute_Custom_Action() => - await RunAppBuilderTestAsync(() => + public void WithCustomRegistration_Should_Execute_Custom_Action() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + var customServiceRegistered = false; + + builder.WithCustomRegistration(r => { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - var customServiceRegistered = false; - - builder.WithCustomRegistration(r => - { - r.RegisterConstant("TestValue", typeof(string)); - customServiceRegistered = true; - }).Build(); + r.RegisterConstant("TestValue", typeof(string)); + customServiceRegistered = true; + }).Build(); - Assert.True(customServiceRegistered); - var service = locator.GetService(); - Assert.Equal("TestValue", service); - }); + Assert.True(customServiceRegistered); + var service = locator.GetService(); + Assert.Equal("TestValue", service); + } [Fact] - public async Task Build_Should_Always_Register_Core_Services() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public void Build_Should_Always_Register_Core_Services() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.Build(); + builder.Build(); - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); - }); + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); + } [Fact] - public async Task WithCustomRegistration_With_Null_Action_Should_Throw() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - Assert.Throws(() => builder.WithCustomRegistration(null!)); - }); + public void WithCustomRegistration_With_Null_Action_Should_Throw() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + Assert.Throws(() => builder.WithCustomRegistration(null!)); + } [Fact] - public async Task WithViewsFromAssembly_Should_Register_Views() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - var assembly = typeof(ReactiveUIBuilderCoreTests).Assembly; + public void WithViewsFromAssembly_Should_Register_Views() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + var assembly = typeof(ReactiveUIBuilderCoreTests).Assembly; - builder.WithViewsFromAssembly(assembly).Build(); - Assert.NotNull(builder); - }); + builder.WithViewsFromAssembly(assembly).Build(); + Assert.NotNull(builder); + } [Fact] - public async Task WithViewsFromAssembly_With_Null_Assembly_Should_Throw() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - Assert.Throws(() => builder.WithViewsFromAssembly(null!)); - }); + public void WithViewsFromAssembly_With_Null_Assembly_Should_Throw() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); + Assert.Throws(() => builder.WithViewsFromAssembly(null!)); + } [Fact] - public async Task WithCoreServices_Called_Multiple_Times_Should_Not_Register_Twice() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); + public void WithCoreServices_Called_Multiple_Times_Should_Not_Register_Twice() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var builder = locator.CreateReactiveUIBuilder(); - builder.WithCoreServices().WithCoreServices().Build(); + builder.WithCoreServices().WithCoreServices().Build(); - var services = locator.GetServices(); - Assert.NotNull(services); - Assert.True(services.Any()); - }); + var services = locator.GetServices(); + Assert.NotNull(services); + Assert.True(services.Any()); + } [Fact] - public async Task Builder_Should_Support_Fluent_Chaining() => - await RunAppBuilderTestAsync(() => - { - using var locator = new ModernDependencyResolver(); - var customServiceRegistered = false; - - locator.CreateReactiveUIBuilder() - .WithRegistration(r => - { - r.RegisterConstant("Test", typeof(string)); - customServiceRegistered = true; - }) - .Build(); - - Assert.True(customServiceRegistered); - var service = locator.GetService(); - Assert.Equal("Test", service); - - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); - }); + public void Builder_Should_Support_Fluent_Chaining() + { + AppBuilder.ResetBuilderStateForTests(); + using var locator = new ModernDependencyResolver(); + var customServiceRegistered = false; + + locator.CreateReactiveUIBuilder() + .WithCoreServices() + .WithCustomRegistration(r => + { + r.RegisterConstant("Test", typeof(string)); + customServiceRegistered = true; + }) + .Build(); + + Assert.True(customServiceRegistered); + var service = locator.GetService(); + Assert.Equal("Test", service); + + var observableProperty = locator.GetService(); + Assert.NotNull(observableProperty); + } } diff --git a/src/ReactiveUI.Builder.Tests/TestConfiguration.cs b/src/ReactiveUI.Builder.Tests/TestConfiguration.cs deleted file mode 100644 index 7ff7f58d81..0000000000 --- a/src/ReactiveUI.Builder.Tests/TestConfiguration.cs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.LeakTests/TestConfiguration.cs b/src/ReactiveUI.LeakTests/TestConfiguration.cs deleted file mode 100644 index 3d24fd781a..0000000000 --- a/src/ReactiveUI.LeakTests/TestConfiguration.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Xunit; - -[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Splat.Tests/TestConfiguration.cs b/src/ReactiveUI.Splat.Tests/TestConfiguration.cs deleted file mode 100644 index 3d24fd781a..0000000000 --- a/src/ReactiveUI.Splat.Tests/TestConfiguration.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Xunit; - -[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Testing.Tests/TestConfiguration.cs b/src/ReactiveUI.Testing.Tests/TestConfiguration.cs deleted file mode 100644 index 3d24fd781a..0000000000 --- a/src/ReactiveUI.Testing.Tests/TestConfiguration.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using Xunit; - -[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Testing.Tests/xunit.runner.json b/src/ReactiveUI.Testing.Tests/xunit.runner.json index d29baba233..503b7481f6 100644 --- a/src/ReactiveUI.Testing.Tests/xunit.runner.json +++ b/src/ReactiveUI.Testing.Tests/xunit.runner.json @@ -1,6 +1,4 @@ { "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", - "parallelizeAssembly": false, - "parallelizeTestCollections": false, - "maxParallelThreads": 1 + "parallelAlgorithm": "aggressive" } diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.cs b/src/ReactiveUI.Tests/API/ApiApprovalTests.cs index 5e31a9e9e2..0a32fa1f74 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.cs +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.cs @@ -9,7 +9,7 @@ namespace ReactiveUI.Tests.API; /// Checks to make sure that the API is consistent with previous releases, and new API changes are highlighted. /// [ExcludeFromCodeCoverage] -public class ApiApprovalTests : AppBuilderTestBase +public class ApiApprovalTests { /// /// Generates public API for the ReactiveUI.Testing API. diff --git a/src/ReactiveUI.Tests/Activation/Mocks/ActivatingView.cs b/src/ReactiveUI.Tests/Activation/ActivatingView.cs similarity index 97% rename from src/ReactiveUI.Tests/Activation/Mocks/ActivatingView.cs rename to src/ReactiveUI.Tests/Activation/ActivatingView.cs index 92a443427f..fd59ba885f 100644 --- a/src/ReactiveUI.Tests/Activation/Mocks/ActivatingView.cs +++ b/src/ReactiveUI.Tests/Activation/ActivatingView.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.Tests.Activation.Mocks; +namespace ReactiveUI.Tests; /// /// A view which simulates a activation. diff --git a/src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewFetcher.cs b/src/ReactiveUI.Tests/Activation/ActivatingViewFetcher.cs similarity index 97% rename from src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewFetcher.cs rename to src/ReactiveUI.Tests/Activation/ActivatingViewFetcher.cs index ec2c03a8a0..550eed6129 100644 --- a/src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewFetcher.cs +++ b/src/ReactiveUI.Tests/Activation/ActivatingViewFetcher.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.Tests.Activation.Mocks; +namespace ReactiveUI.Tests; /// /// Simulates a activating view fetcher. diff --git a/src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewModel.cs b/src/ReactiveUI.Tests/Activation/ActivatingViewModel.cs similarity index 96% rename from src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewModel.cs rename to src/ReactiveUI.Tests/Activation/ActivatingViewModel.cs index 08e457535c..832ea63332 100644 --- a/src/ReactiveUI.Tests/Activation/Mocks/ActivatingViewModel.cs +++ b/src/ReactiveUI.Tests/Activation/ActivatingViewModel.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.Tests.Activation.Mocks; +namespace ReactiveUI.Tests; /// /// Simulates a activating view model. diff --git a/src/ReactiveUI.Tests/Activation/ActivatingViewModelTests.cs b/src/ReactiveUI.Tests/Activation/ActivatingViewModelTests.cs index fca5480cf3..5d07a34c30 100644 --- a/src/ReactiveUI.Tests/Activation/ActivatingViewModelTests.cs +++ b/src/ReactiveUI.Tests/Activation/ActivatingViewModelTests.cs @@ -8,59 +8,55 @@ namespace ReactiveUI.Tests; /// /// Tests associated with activating view models. /// -public class ActivatingViewModelTests : AppBuilderTestBase +public class ActivatingViewModelTests { /// /// Tests for the activation to make sure it activates the appropriate number of times. /// - /// A representing the asynchronous operation. [Fact] - public async Task ActivationsGetRefCounted() => - await RunAppBuilderTestAsync(() => - { - var fixture = new ActivatingViewModel(); - Assert.Equal(0, fixture.IsActiveCount); + public void ActivationsGetRefCounted() + { + var fixture = new ActivatingViewModel(); + Assert.Equal(0, fixture.IsActiveCount); - fixture.Activator.Activate(); - Assert.Equal(1, fixture.IsActiveCount); + fixture.Activator.Activate(); + Assert.Equal(1, fixture.IsActiveCount); - fixture.Activator.Activate(); - Assert.Equal(1, fixture.IsActiveCount); + fixture.Activator.Activate(); + Assert.Equal(1, fixture.IsActiveCount); - fixture.Activator.Deactivate(); - Assert.Equal(1, fixture.IsActiveCount); + fixture.Activator.Deactivate(); + Assert.Equal(1, fixture.IsActiveCount); - // RefCount drops to zero - fixture.Activator.Deactivate(); - Assert.Equal(0, fixture.IsActiveCount); - }); + // RefCount drops to zero + fixture.Activator.Deactivate(); + Assert.Equal(0, fixture.IsActiveCount); + } /// /// Tests to make sure the activations of derived classes don't get stomped. /// - /// A representing the asynchronous operation. [Fact] - public async Task DerivedActivationsDontGetStomped() => - await RunAppBuilderTestAsync(() => - { - var fixture = new DerivedActivatingViewModel(); - Assert.Equal(0, fixture.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCountAlso); - - fixture.Activator.Activate(); - Assert.Equal(1, fixture.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCountAlso); - - fixture.Activator.Activate(); - Assert.Equal(1, fixture.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCountAlso); - - fixture.Activator.Deactivate(); - Assert.Equal(1, fixture.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCountAlso); - - fixture.Activator.Deactivate(); - Assert.Equal(0, fixture.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCountAlso); - }); + public void DerivedActivationsDontGetStomped() + { + var fixture = new DerivedActivatingViewModel(); + Assert.Equal(0, fixture.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCountAlso); + + fixture.Activator.Activate(); + Assert.Equal(1, fixture.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCountAlso); + + fixture.Activator.Activate(); + Assert.Equal(1, fixture.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCountAlso); + + fixture.Activator.Deactivate(); + Assert.Equal(1, fixture.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCountAlso); + + fixture.Activator.Deactivate(); + Assert.Equal(0, fixture.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCountAlso); + } } diff --git a/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs b/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs index d6fed2589a..4a26de35a2 100644 --- a/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs +++ b/src/ReactiveUI.Tests/Activation/ActivatingViewTests.cs @@ -3,182 +3,179 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using Splat.Builder; + namespace ReactiveUI.Tests; /// /// Tests for activating views. /// -public class ActivatingViewTests : AppBuilderTestBase +public class ActivatingViewTests { /// /// Tests to make sure that views generally activate. /// - /// A representing the asynchronous operation. [Fact] - public async Task ActivatingViewSmokeTest() => - await RunAppBuilderTestAsync(() => + public void ActivatingViewSmokeTest() + { + AppBuilder.ResetBuilderStateForTests(); + var locator = new ModernDependencyResolver(); + locator.InitializeSplat(); + locator.InitializeReactiveUI(); + locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); + + using (locator.WithResolver()) { - var locator = new ModernDependencyResolver(); - locator.InitializeSplat(); - locator.InitializeReactiveUI(); - locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - - using (locator.WithResolver()) + var vm = new ActivatingViewModel(); + var fixture = new ActivatingView { - var vm = new ActivatingViewModel(); - var fixture = new ActivatingView - { - ViewModel = vm - }; - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); - - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, vm.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCount); - - fixture.Unloaded.OnNext(Unit.Default); - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); - } - }); + ViewModel = vm + }; + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, vm.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCount); + + fixture.Unloaded.OnNext(Unit.Default); + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + } + } /// /// Tests for making sure nulling the view model deactivate it. /// - /// A representing the asynchronous operation. [Fact] - public async Task NullingViewModelDeactivateIt() => - await RunAppBuilderTestAsync(() => + public void NullingViewModelDeactivateIt() + { + AppBuilder.ResetBuilderStateForTests(); + var locator = new ModernDependencyResolver(); + locator.InitializeSplat(); + locator.InitializeReactiveUI(); + locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); + + using (locator.WithResolver()) { - var locator = new ModernDependencyResolver(); - locator.InitializeSplat(); - locator.InitializeReactiveUI(); - locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - - using (locator.WithResolver()) + var vm = new ActivatingViewModel(); + var fixture = new ActivatingView { - var vm = new ActivatingViewModel(); - var fixture = new ActivatingView - { - ViewModel = vm - }; - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); - - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, vm.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCount); - - fixture.ViewModel = null; - Assert.Equal(0, vm.IsActiveCount); - } - }); + ViewModel = vm + }; + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, vm.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCount); + + fixture.ViewModel = null; + Assert.Equal(0, vm.IsActiveCount); + } + } /// /// Tests switching the view model deactivates it. /// - /// A representing the asynchronous operation. [Fact] - public async Task SwitchingViewModelDeactivatesIt() => - await RunAppBuilderTestAsync(() => + public void SwitchingViewModelDeactivatesIt() + { + AppBuilder.ResetBuilderStateForTests(); + var locator = new ModernDependencyResolver(); + locator.InitializeSplat(); + locator.InitializeReactiveUI(); + locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); + + using (locator.WithResolver()) { - var locator = new ModernDependencyResolver(); - locator.InitializeSplat(); - locator.InitializeReactiveUI(); - locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - - using (locator.WithResolver()) + var vm = new ActivatingViewModel(); + var fixture = new ActivatingView { - var vm = new ActivatingViewModel(); - var fixture = new ActivatingView - { - ViewModel = vm - }; - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); - - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, vm.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCount); - - var newVm = new ActivatingViewModel(); - Assert.Equal(0, newVm.IsActiveCount); - - fixture.ViewModel = newVm; - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(1, newVm.IsActiveCount); - } - }); + ViewModel = vm + }; + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, vm.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCount); + + var newVm = new ActivatingViewModel(); + Assert.Equal(0, newVm.IsActiveCount); + + fixture.ViewModel = newVm; + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(1, newVm.IsActiveCount); + } + } /// /// Tests setting the view model after loaded loads it. /// - /// A representing the asynchronous operation. [Fact] - public async Task SettingViewModelAfterLoadedLoadsIt() => - await RunAppBuilderTestAsync(() => + public void SettingViewModelAfterLoadedLoadsIt() + { + AppBuilder.ResetBuilderStateForTests(); + var locator = new ModernDependencyResolver(); + locator.InitializeSplat(); + locator.InitializeReactiveUI(); + locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); + + using (locator.WithResolver()) { - var locator = new ModernDependencyResolver(); - locator.InitializeSplat(); - locator.InitializeReactiveUI(); - locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); + var vm = new ActivatingViewModel(); + var fixture = new ActivatingView(); - using (locator.WithResolver()) - { - var vm = new ActivatingViewModel(); - var fixture = new ActivatingView(); - - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, fixture.IsActiveCount); + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, fixture.IsActiveCount); - fixture.ViewModel = vm; - Assert.Equal(1, fixture.IsActiveCount); - Assert.Equal(1, vm.IsActiveCount); + fixture.ViewModel = vm; + Assert.Equal(1, fixture.IsActiveCount); + Assert.Equal(1, vm.IsActiveCount); - fixture.Unloaded.OnNext(Unit.Default); - Assert.Equal(0, fixture.IsActiveCount); - Assert.Equal(0, vm.IsActiveCount); - } - }); + fixture.Unloaded.OnNext(Unit.Default); + Assert.Equal(0, fixture.IsActiveCount); + Assert.Equal(0, vm.IsActiveCount); + } + } /// /// Tests the can unload and load view again. /// - /// A representing the asynchronous operation. [Fact] - public async Task CanUnloadAndLoadViewAgain() => - await RunAppBuilderTestAsync(() => + public void CanUnloadAndLoadViewAgain() + { + AppBuilder.ResetBuilderStateForTests(); + var locator = new ModernDependencyResolver(); + locator.InitializeSplat(); + locator.InitializeReactiveUI(); + locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); + + using (locator.WithResolver()) { - var locator = new ModernDependencyResolver(); - locator.InitializeSplat(); - locator.InitializeReactiveUI(); - locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher)); - - using (locator.WithResolver()) + var vm = new ActivatingViewModel(); + var fixture = new ActivatingView { - var vm = new ActivatingViewModel(); - var fixture = new ActivatingView - { - ViewModel = vm - }; - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); - - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, vm.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCount); - - fixture.Unloaded.OnNext(Unit.Default); - Assert.Equal(0, vm.IsActiveCount); - Assert.Equal(0, fixture.IsActiveCount); - - fixture.Loaded.OnNext(Unit.Default); - Assert.Equal(1, vm.IsActiveCount); - Assert.Equal(1, fixture.IsActiveCount); - } - }); + ViewModel = vm + }; + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, vm.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCount); + + fixture.Unloaded.OnNext(Unit.Default); + Assert.Equal(0, vm.IsActiveCount); + Assert.Equal(0, fixture.IsActiveCount); + + fixture.Loaded.OnNext(Unit.Default); + Assert.Equal(1, vm.IsActiveCount); + Assert.Equal(1, fixture.IsActiveCount); + } + } } diff --git a/src/ReactiveUI.Tests/Activation/CanActivateViewFetcherTests.cs b/src/ReactiveUI.Tests/Activation/CanActivateViewFetcherTests.cs index 41814ca127..a4a502c9f3 100644 --- a/src/ReactiveUI.Tests/Activation/CanActivateViewFetcherTests.cs +++ b/src/ReactiveUI.Tests/Activation/CanActivateViewFetcherTests.cs @@ -4,6 +4,7 @@ // See the LICENSE file in the project root for full license information. using Microsoft.Reactive.Testing; + using ReactiveUI.Tests.Winforms; namespace ReactiveUI.Tests; @@ -11,83 +12,71 @@ namespace ReactiveUI.Tests; /// /// Tests to make sure the can activate view fetcher works correctly. /// -public class CanActivateViewFetcherTests : AppBuilderTestBase +public class CanActivateViewFetcherTests { /// /// Tests return negative for ICanActivate. /// - /// A representing the asynchronous operation. [Fact] - public async Task CanNotFetchActivatorForNonCanActivateableForm() => - await RunAppBuilderTestAsync(() => - { - var form = new TestFormNotCanActivate(); - var canActivateViewFetcher = new CanActivateViewFetcher(); - canActivateViewFetcher.GetActivationForView(form).AssertEqual(Observable.Return(false)); - }); + public void CanNotFetchActivatorForNonCanActivateableForm() + { + var form = new TestFormNotCanActivate(); + var canActivateViewFetcher = new CanActivateViewFetcher(); + canActivateViewFetcher.GetActivationForView(form).AssertEqual(Observable.Return(false)); + } /// /// Tests return positive for ICanActivate. /// - /// A representing the asynchronous operation. [Fact] - public async Task CanGetActivationForViewForCanActivateableFormActivated() => - await RunAppBuilderTestAsync(() => - { - var canActivateViewFetcher = new CanActivateViewFetcher(); - canActivateViewFetcher.GetActivationForView(new TestForm(1)).FirstAsync().AssertEqual(Observable.Return(true)); - }); + public void CanGetActivationForViewForCanActivateableFormActivated() + { + var canActivateViewFetcher = new CanActivateViewFetcher(); + canActivateViewFetcher.GetActivationForView(new TestForm(1)).FirstAsync().AssertEqual(Observable.Return(true)); + } /// /// Tests return negative for ICanActivate. /// - /// A representing the asynchronous operation. [Fact] - public async Task CanGetActivationForViewForCanActivateableFormDeactivated() => - await RunAppBuilderTestAsync(() => - { - var canActivateViewFetcher = new CanActivateViewFetcher(); - canActivateViewFetcher.GetActivationForView(new TestForm(2)).FirstAsync().AssertEqual(Observable.Return(false)); - }); + public void CanGetActivationForViewForCanActivateableFormDeactivated() + { + var canActivateViewFetcher = new CanActivateViewFetcher(); + canActivateViewFetcher.GetActivationForView(new TestForm(2)).FirstAsync().AssertEqual(Observable.Return(false)); + } /// /// Tests return positive for ICanActivate. /// - /// A representing the asynchronous operation. [Fact] - public async Task ReturnPositiveForICanActivate() => - await RunAppBuilderTestAsync(() => - { - var canActivateViewFetcher = new CanActivateViewFetcher(); - var affinity = canActivateViewFetcher.GetAffinityForView(typeof(ICanActivate)); - Assert.True(affinity > 0); - }); + public void ReturnPositiveForICanActivate() + { + var canActivateViewFetcher = new CanActivateViewFetcher(); + var affinity = canActivateViewFetcher.GetAffinityForView(typeof(ICanActivate)); + Assert.True(affinity > 0); + } /// /// Tests return positive for ICanActivate derivatives. /// - /// A representing the asynchronous operation. [Fact] - public async Task ReturnPositiveForICanActivateDerivatives() => - await RunAppBuilderTestAsync(() => - { - var canActivateViewFetcher = new CanActivateViewFetcher(); - var affinity = canActivateViewFetcher.GetAffinityForView(typeof(CanActivateStub)); - Assert.True(affinity > 0); - }); + public void ReturnPositiveForICanActivateDerivatives() + { + var canActivateViewFetcher = new CanActivateViewFetcher(); + var affinity = canActivateViewFetcher.GetAffinityForView(typeof(CanActivateStub)); + Assert.True(affinity > 0); + } /// /// Tests return zero for non ICanActivate derivatives. /// - /// A representing the asynchronous operation. [Fact] - public async Task ReturnZeroForNonICanActivateDerivatives() => - await RunAppBuilderTestAsync(() => - { - var canActivateViewFetcher = new CanActivateViewFetcher(); - var affinity = canActivateViewFetcher.GetAffinityForView(typeof(CanActivateViewFetcherTests)); - Assert.Equal(0, affinity); - }); + public void ReturnZeroForNonICanActivateDerivatives() + { + var canActivateViewFetcher = new CanActivateViewFetcher(); + var affinity = canActivateViewFetcher.GetAffinityForView(typeof(CanActivateViewFetcherTests)); + Assert.Equal(0, affinity); + } #pragma warning disable CA1812 // Class is not instantiated diff --git a/src/ReactiveUI.Tests/Activation/Mocks/DerivedActivatingViewModel.cs b/src/ReactiveUI.Tests/Activation/DerivedActivatingViewModel.cs similarity index 95% rename from src/ReactiveUI.Tests/Activation/Mocks/DerivedActivatingViewModel.cs rename to src/ReactiveUI.Tests/Activation/DerivedActivatingViewModel.cs index 3b7796502f..5505b326c9 100644 --- a/src/ReactiveUI.Tests/Activation/Mocks/DerivedActivatingViewModel.cs +++ b/src/ReactiveUI.Tests/Activation/DerivedActivatingViewModel.cs @@ -3,7 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -namespace ReactiveUI.Tests.Activation.Mocks; +namespace ReactiveUI.Tests; /// /// A activating view model which is derived from another ActivatingViewModel. diff --git a/src/ReactiveUI.Tests/Activation/ViewModelActivatorTests.cs b/src/ReactiveUI.Tests/Activation/ViewModelActivatorTests.cs index 86d8640fb5..881814efe2 100644 --- a/src/ReactiveUI.Tests/Activation/ViewModelActivatorTests.cs +++ b/src/ReactiveUI.Tests/Activation/ViewModelActivatorTests.cs @@ -10,92 +10,82 @@ namespace ReactiveUI.Tests; /// /// Tests for the view model activator. /// -public class ViewModelActivatorTests : AppBuilderTestBase +public class ViewModelActivatorTests { /// /// Tests the activating ticks activated observable. /// - /// A representing the asynchronous operation. [Fact] - public async Task TestActivatingTicksActivatedObservable() => - await RunAppBuilderTestAsync(() => - { - var viewModelActivator = new ViewModelActivator(); - viewModelActivator.Activated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + public void TestActivatingTicksActivatedObservable() + { + var viewModelActivator = new ViewModelActivator(); + viewModelActivator.Activated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - viewModelActivator.Activate(); + viewModelActivator.Activate(); - Assert.Equal(1, activated.Count); - }); + Assert.Equal(1, activated.Count); + } /// /// Tests the deactivating ignoring reference count ticks deactivated observable. /// - /// A representing the asynchronous operation. [Fact] - public async Task TestDeactivatingIgnoringRefCountTicksDeactivatedObservable() => - await RunAppBuilderTestAsync(() => - { - var viewModelActivator = new ViewModelActivator(); - viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); + public void TestDeactivatingIgnoringRefCountTicksDeactivatedObservable() + { + var viewModelActivator = new ViewModelActivator(); + viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); - viewModelActivator.Deactivate(true); + viewModelActivator.Deactivate(true); - Assert.Equal(1, deactivated.Count); - }); + Assert.Equal(1, deactivated.Count); + } /// /// Tests the deactivating count doesnt tick deactivated observable. /// - /// A representing the asynchronous operation. [Fact] - public async Task TestDeactivatingCountDoesntTickDeactivatedObservable() => - await RunAppBuilderTestAsync(() => - { - var viewModelActivator = new ViewModelActivator(); - viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); + public void TestDeactivatingCountDoesntTickDeactivatedObservable() + { + var viewModelActivator = new ViewModelActivator(); + viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); - viewModelActivator.Deactivate(false); + viewModelActivator.Deactivate(false); - Assert.Equal(0, deactivated.Count); - }); + Assert.Equal(0, deactivated.Count); + } /// /// Tests the deactivating following activating ticks deactivated observable. /// - /// A representing the asynchronous operation. [Fact] - public async Task TestDeactivatingFollowingActivatingTicksDeactivatedObservable() => - await RunAppBuilderTestAsync(() => - { - var viewModelActivator = new ViewModelActivator(); - viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); + public void TestDeactivatingFollowingActivatingTicksDeactivatedObservable() + { + var viewModelActivator = new ViewModelActivator(); + viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); - viewModelActivator.Activate(); - viewModelActivator.Deactivate(false); + viewModelActivator.Activate(); + viewModelActivator.Deactivate(false); - Assert.Equal(1, deactivated.Count); - }); + Assert.Equal(1, deactivated.Count); + } /// /// Tests the disposing after activation deactivates view model. /// - /// A representing the asynchronous operation. [Fact] - public async Task TestDisposingAfterActivationDeactivatesViewModel() => - await RunAppBuilderTestAsync(() => - { - var viewModelActivator = new ViewModelActivator(); - viewModelActivator.Activated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); - - using (viewModelActivator.Activate()) - { - Assert.Equal(1, activated.Count); - Assert.Equal(0, deactivated.Count); - } + public void TestDisposingAfterActivationDeactivatesViewModel() + { + var viewModelActivator = new ViewModelActivator(); + viewModelActivator.Activated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + viewModelActivator.Deactivated.ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var deactivated).Subscribe(); + using (viewModelActivator.Activate()) + { Assert.Equal(1, activated.Count); - Assert.Equal(1, deactivated.Count); - }); + Assert.Equal(0, deactivated.Count); + } + + Assert.Equal(1, activated.Count); + Assert.Equal(1, deactivated.Count); + } } diff --git a/src/ReactiveUI.Tests/AutoPersist/AutoPersistCollectionTests.cs b/src/ReactiveUI.Tests/AutoPersist/AutoPersistCollectionTests.cs index 5a51fc09d1..bed7a9fef7 100644 --- a/src/ReactiveUI.Tests/AutoPersist/AutoPersistCollectionTests.cs +++ b/src/ReactiveUI.Tests/AutoPersist/AutoPersistCollectionTests.cs @@ -7,12 +7,14 @@ using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; + namespace ReactiveUI.Tests; /// /// Tests to make sure that the auto persist collection works. /// -public class AutoPersistCollectionTests : AppBuilderTestBase +public class AutoPersistCollectionTests { /// /// Test the automatic persist collection smoke test. diff --git a/src/ReactiveUI.Tests/AutoPersist/AutoPersistHelperTest.cs b/src/ReactiveUI.Tests/AutoPersist/AutoPersistHelperTest.cs index 4d8a56b599..79575428fa 100644 --- a/src/ReactiveUI.Tests/AutoPersist/AutoPersistHelperTest.cs +++ b/src/ReactiveUI.Tests/AutoPersist/AutoPersistHelperTest.cs @@ -5,12 +5,14 @@ using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; + namespace ReactiveUI.Tests; /// /// Tests the AutoPersistHelper. /// -public class AutoPersistHelperTest : AppBuilderTestBase +public class AutoPersistHelperTest { /// /// Test the automatic persist doesnt work on non data contract classes. diff --git a/src/ReactiveUI.Tests/AwaiterTest.cs b/src/ReactiveUI.Tests/AwaiterTest.cs index 678d39499e..28720b3bd0 100644 --- a/src/ReactiveUI.Tests/AwaiterTest.cs +++ b/src/ReactiveUI.Tests/AwaiterTest.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Tests the awaiters. /// -public class AwaiterTest : AppBuilderTestBase +public class AwaiterTest { /// /// A smoke test for Awaiters. diff --git a/src/ReactiveUI.Tests/BindingTypeConvertersTest.cs b/src/ReactiveUI.Tests/BindingTypeConvertersTest.cs index 1ad501394d..354d6776ec 100644 --- a/src/ReactiveUI.Tests/BindingTypeConvertersTest.cs +++ b/src/ReactiveUI.Tests/BindingTypeConvertersTest.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Tests for binding type converters. /// -public class BindingTypeConvertersTest : AppBuilderTestBase +public class BindingTypeConvertersTest { /// /// Tests that equality type converter do reference cast should convert null nullable values. diff --git a/src/ReactiveUI.Tests/Commands/CombinedReactiveCommandTest.cs b/src/ReactiveUI.Tests/Commands/CombinedReactiveCommandTest.cs index e5c32fc167..e3b1f5466d 100644 --- a/src/ReactiveUI.Tests/Commands/CombinedReactiveCommandTest.cs +++ b/src/ReactiveUI.Tests/Commands/CombinedReactiveCommandTest.cs @@ -7,12 +7,14 @@ using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; + namespace ReactiveUI.Tests; /// /// Tests for the ReactiveCommand Combined functionality. /// -public class CombinedReactiveCommandTest : AppBuilderTestBase +public class CombinedReactiveCommandTest { /// /// Tests that determines whether this instance [can execute is false if any child cannot execute]. diff --git a/src/ReactiveUI.Tests/Commands/CreatesCommandBindingTests.cs b/src/ReactiveUI.Tests/Commands/CreatesCommandBindingTests.cs index 8bafbefb74..727dc1df5a 100644 --- a/src/ReactiveUI.Tests/Commands/CreatesCommandBindingTests.cs +++ b/src/ReactiveUI.Tests/Commands/CreatesCommandBindingTests.cs @@ -8,31 +8,29 @@ namespace ReactiveUI.Tests; /// /// Tests for the CreateCommand binding. /// -public class CreatesCommandBindingTests : AppBuilderTestBase +public class CreatesCommandBindingTests { /// /// Test that makes sure events binder binds to explicit event. /// - /// A representing the asynchronous operation. [Fact] - public async Task EventBinderBindsToExplicitEvent() => - await RunAppBuilderTestAsync(() => - { - var input = new TestFixture(); - var fixture = new CreatesCommandBindingViaEvent(); - var wasCalled = false; - var cmd = ReactiveCommand.Create(_ => wasCalled = true); + public void EventBinderBindsToExplicitEvent() + { + var input = new TestFixture(); + var fixture = new CreatesCommandBindingViaEvent(); + var wasCalled = false; + var cmd = ReactiveCommand.Create(_ => wasCalled = true); - Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); - Assert.False(fixture.GetAffinityForObject(input.GetType(), false) > 0); + Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); + Assert.False(fixture.GetAffinityForObject(input.GetType(), false) > 0); - var disposable = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5), "PropertyChanged"); - input.IsNotNullString = "Foo"; - Assert.True(wasCalled); + var disposable = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5), "PropertyChanged"); + input.IsNotNullString = "Foo"; + Assert.True(wasCalled); - wasCalled = false; - disposable?.Dispose(); - input.IsNotNullString = "Bar"; - Assert.False(wasCalled); - }); + wasCalled = false; + disposable?.Dispose(); + input.IsNotNullString = "Bar"; + Assert.False(wasCalled); + } } diff --git a/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs b/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs index 6db8949b49..1726b6dcf9 100644 --- a/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs +++ b/src/ReactiveUI.Tests/Commands/ReactiveCommandTest.cs @@ -9,12 +9,14 @@ using FluentAssertions; using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; + namespace ReactiveUI.Tests; /// /// Tests for the ReactiveCommand class. /// -public class ReactiveCommandTest : AppBuilderTestBase +public class ReactiveCommandTest { public ReactiveCommandTest() { diff --git a/src/ReactiveUI.Tests/Comparers/OrderedComparerTests.cs b/src/ReactiveUI.Tests/Comparers/OrderedComparerTests.cs index 408c15234c..f5849edc0e 100644 --- a/src/ReactiveUI.Tests/Comparers/OrderedComparerTests.cs +++ b/src/ReactiveUI.Tests/Comparers/OrderedComparerTests.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.Tests; /// /// Tests for the ordered comparer. /// -public class OrderedComparerTests : AppBuilderTestBase +public class OrderedComparerTests { /// /// A general smoke test. diff --git a/src/ReactiveUI.Tests/GlobalUsings.cs b/src/ReactiveUI.Tests/GlobalUsings.cs index 0c3154674f..a2fcae5614 100644 --- a/src/ReactiveUI.Tests/GlobalUsings.cs +++ b/src/ReactiveUI.Tests/GlobalUsings.cs @@ -3,9 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -global using global::ReactiveUI; -global using global::ReactiveUI.Testing; -global using global::ReactiveUI.Tests.Activation.Mocks; global using global::Splat; global using global::System; global using global::System.Collections.Generic; diff --git a/src/ReactiveUI.Tests/InteractionBinding/InteractionBinderImplementationTests.cs b/src/ReactiveUI.Tests/InteractionBinding/InteractionBinderImplementationTests.cs index 888e9ed99b..873846b99e 100644 --- a/src/ReactiveUI.Tests/InteractionBinding/InteractionBinderImplementationTests.cs +++ b/src/ReactiveUI.Tests/InteractionBinding/InteractionBinderImplementationTests.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.Tests; /// /// Tests for the Interaction bindings. /// -public class InteractionBinderImplementationTests : AppBuilderTestBase +public class InteractionBinderImplementationTests { /// /// Tests that make sure that the we receive output from task handler. diff --git a/src/ReactiveUI.Tests/InteractionsTest.cs b/src/ReactiveUI.Tests/InteractionsTest.cs index cdc18035bc..110c11a8c1 100644 --- a/src/ReactiveUI.Tests/InteractionsTest.cs +++ b/src/ReactiveUI.Tests/InteractionsTest.cs @@ -7,12 +7,14 @@ using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; + namespace ReactiveUI.Tests; /// /// Tests interactions. /// -public class InteractionsTest : AppBuilderTestBase +public class InteractionsTest { /// /// Tests that registers null handler should cause exception. diff --git a/src/ReactiveUI.Tests/Locator/DefaultViewLocatorTests.cs b/src/ReactiveUI.Tests/Locator/DefaultViewLocatorTests.cs index c9a9956749..ea2c6590aa 100644 --- a/src/ReactiveUI.Tests/Locator/DefaultViewLocatorTests.cs +++ b/src/ReactiveUI.Tests/Locator/DefaultViewLocatorTests.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Tests for the default view locators. /// -public class DefaultViewLocatorTests : AppBuilderTestBase +public class DefaultViewLocatorTests { /// /// Tests that the default name of the view model is replaced with view when determining the service. diff --git a/src/ReactiveUI.Tests/MessageBusTest.cs b/src/ReactiveUI.Tests/MessageBusTest.cs index 7891f56cdb..8badadb0c8 100644 --- a/src/ReactiveUI.Tests/MessageBusTest.cs +++ b/src/ReactiveUI.Tests/MessageBusTest.cs @@ -7,255 +7,237 @@ using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; + namespace ReactiveUI.Tests; /// /// Tests the MessageBus class. /// -public class MessageBusTest : AppBuilderTestBase +public class MessageBusTest { /// /// Smoke tests the MessageBus. /// - /// A representing the asynchronous operation. [Fact] - public async Task MessageBusSmokeTest() => - await RunAppBuilderTestAsync(() => - { - var input = new[] { 1, 2, 3, 4 }; + public void MessageBusSmokeTest() + { + var input = new[] { 1, 2, 3, 4 }; - var result = new TestScheduler().With(scheduler => - { - var source = new Subject(); - var fixture = new MessageBus(); - - fixture.RegisterMessageSource(source, "Test"); - Assert.False(fixture.IsRegistered(typeof(int))); - Assert.False(fixture.IsRegistered(typeof(int), "Foo")); + var result = new TestScheduler().With(scheduler => + { + var source = new Subject(); + var fixture = new MessageBus(); - fixture.Listen("Test").ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var output).Subscribe(); + fixture.RegisterMessageSource(source, "Test"); + Assert.False(fixture.IsRegistered(typeof(int))); + Assert.False(fixture.IsRegistered(typeof(int), "Foo")); - input.Run(source.OnNext); + fixture.Listen("Test").ToObservableChangeSet(ImmediateScheduler.Instance).Bind(out var output).Subscribe(); - scheduler.Start(); - return output; - }); + input.Run(source.OnNext); - input.AssertAreEqual(result); + scheduler.Start(); + return output; }); + input.AssertAreEqual(result); + } + /// /// Tests that explicits send message should work even after registering source. /// - /// A representing the asynchronous operation. [Fact] - public async Task ExplicitSendMessageShouldWorkEvenAfterRegisteringSource() => - await RunAppBuilderTestAsync(() => - { - var fixture = new MessageBus(); - fixture.RegisterMessageSource(Observable.Never); + public void ExplicitSendMessageShouldWorkEvenAfterRegisteringSource() + { + var fixture = new MessageBus(); + fixture.RegisterMessageSource(Observable.Never); - var messageReceived = false; - fixture.Listen().Subscribe(_ => messageReceived = true); + var messageReceived = false; + fixture.Listen().Subscribe(_ => messageReceived = true); - fixture.SendMessage(42); - Assert.True(messageReceived); - }); + fixture.SendMessage(42); + Assert.True(messageReceived); + } /// /// Tests that listening before registering a source should work. /// - /// A representing the asynchronous operation. [Fact] - public async Task ListeningBeforeRegisteringASourceShouldWork() => - await RunAppBuilderTestAsync(() => - { - var fixture = new MessageBus(); - var result = -1; + public void ListeningBeforeRegisteringASourceShouldWork() + { + var fixture = new MessageBus(); + var result = -1; - fixture.Listen().Subscribe(x => result = x); + fixture.Listen().Subscribe(x => result = x); - Assert.Equal(-1, result); + Assert.Equal(-1, result); - fixture.SendMessage(42); + fixture.SendMessage(42); - Assert.Equal(42, result); - }); + Assert.Equal(42, result); + } /// /// Tests that the Garbage Collector should not kill message service. /// - /// A representing the asynchronous operation. [Fact] - public async Task GcShouldNotKillMessageService() => - await RunAppBuilderTestAsync(() => - { - var bus = new MessageBus(); + public void GcShouldNotKillMessageService() + { + var bus = new MessageBus(); - var receivedMessage = false; - var dispose = bus.Listen().Subscribe(_ => receivedMessage = true); - bus.SendMessage(1); - Assert.True(receivedMessage); + var receivedMessage = false; + var dispose = bus.Listen().Subscribe(_ => receivedMessage = true); + bus.SendMessage(1); + Assert.True(receivedMessage); - GC.Collect(); - GC.WaitForPendingFinalizers(); + GC.Collect(); + GC.WaitForPendingFinalizers(); - receivedMessage = false; - bus.SendMessage(2); - Assert.True(receivedMessage); - }); + receivedMessage = false; + bus.SendMessage(2); + Assert.True(receivedMessage); + } /// /// Tests that Registering the second message source should merge both sources. /// - /// A representing the asynchronous operation. [Fact] - public async Task RegisteringSecondMessageSourceShouldMergeBothSources() => - await RunAppBuilderTestAsync(() => - { - var bus = new MessageBus(); - var source1 = new Subject(); - var source2 = new Subject(); - var receivedMessage1 = false; - var receivedMessage2 = false; + public void RegisteringSecondMessageSourceShouldMergeBothSources() + { + var bus = new MessageBus(); + var source1 = new Subject(); + var source2 = new Subject(); + var receivedMessage1 = false; + var receivedMessage2 = false; - bus.RegisterMessageSource(source1); - bus.Listen().Subscribe(_ => receivedMessage1 = true); + bus.RegisterMessageSource(source1); + bus.Listen().Subscribe(_ => receivedMessage1 = true); - bus.RegisterMessageSource(source2); - bus.Listen().Subscribe(_ => receivedMessage2 = true); + bus.RegisterMessageSource(source2); + bus.Listen().Subscribe(_ => receivedMessage2 = true); - source1.OnNext(1); - Assert.True(receivedMessage1); - Assert.True(receivedMessage2); + source1.OnNext(1); + Assert.True(receivedMessage1); + Assert.True(receivedMessage2); - receivedMessage1 = false; - receivedMessage2 = false; + receivedMessage1 = false; + receivedMessage2 = false; - source2.OnNext(2); - Assert.True(receivedMessage1); - Assert.True(receivedMessage2); - }); + source2.OnNext(2); + Assert.True(receivedMessage1); + Assert.True(receivedMessage2); + } /// /// Tests the MessageBus threading. /// - /// A representing the asynchronous operation. [Fact] - public async Task MessageBusThreadingTest() => - await RunAppBuilderTestAsync(() => + public void MessageBusThreadingTest() + { + var mb = new MessageBus(); + int? listenedThreadId = null; + int? otherThreadId = null; + var thisThreadId = Environment.CurrentManagedThreadId; + + var otherThread = new Thread(new ThreadStart(() => { - var mb = new MessageBus(); - int? listenedThreadId = null; - int? otherThreadId = null; - var thisThreadId = Environment.CurrentManagedThreadId; - - var otherThread = new Thread(new ThreadStart(() => - { - otherThreadId = Environment.CurrentManagedThreadId; - mb.Listen().Subscribe(_ => listenedThreadId = Environment.CurrentManagedThreadId); - mb.SendMessage(42); - })); - - otherThread.Start(); - otherThread.Join(); - - Assert.NotEqual(listenedThreadId!.Value, thisThreadId); - Assert.Equal(listenedThreadId.Value, otherThreadId!.Value); - }); + otherThreadId = Environment.CurrentManagedThreadId; + mb.Listen().Subscribe(_ => listenedThreadId = Environment.CurrentManagedThreadId); + mb.SendMessage(42); + })); + + otherThread.Start(); + otherThread.Join(); + + Assert.NotEqual(listenedThreadId!.Value, thisThreadId); + Assert.Equal(listenedThreadId.Value, otherThreadId!.Value); + } /// /// Tests MessageBus.RegisterScheduler method for complete coverage. /// - /// A representing the asynchronous operation. [Fact] - public async Task MessageBus_RegisterScheduler_ShouldWork() => - await RunAppBuilderTestAsync(() => - { - // Arrange - var messageBus = new MessageBus(); - var receivedMessages = new List(); - - // Act - Register scheduler without contract first - messageBus.RegisterScheduler(CurrentThreadScheduler.Instance); - messageBus.Listen().Subscribe(x => receivedMessages.Add(x)); - messageBus.SendMessage(42); - - // Assert - Assert.Single(receivedMessages); - Assert.Equal(42, receivedMessages[0]); - }); + public void MessageBus_RegisterScheduler_ShouldWork() + { + // Arrange + var messageBus = new MessageBus(); + var receivedMessages = new List(); + + // Act - Register scheduler without contract first + messageBus.RegisterScheduler(CurrentThreadScheduler.Instance); + messageBus.Listen().Subscribe(x => receivedMessages.Add(x)); + messageBus.SendMessage(42); + + // Assert + Assert.Single(receivedMessages); + Assert.Equal(42, receivedMessages[0]); + } /// /// Tests MessageBus.ListenIncludeLatest method for complete coverage. /// - /// A representing the asynchronous operation. [Fact] - public async Task MessageBus_ListenIncludeLatest_ShouldIncludeLastMessage() => - await RunAppBuilderTestAsync(() => - { - // Arrange - var messageBus = new MessageBus(); - var receivedMessages = new List(); + public void MessageBus_ListenIncludeLatest_ShouldIncludeLastMessage() + { + // Arrange + var messageBus = new MessageBus(); + var receivedMessages = new List(); - // Send a message first - messageBus.SendMessage(42); + // Send a message first + messageBus.SendMessage(42); - // Act - Listen including latest should get the previously sent message - messageBus.ListenIncludeLatest().Subscribe(x => receivedMessages.Add(x)); + // Act - Listen including latest should get the previously sent message + messageBus.ListenIncludeLatest().Subscribe(x => receivedMessages.Add(x)); - // Assert - Assert.Single(receivedMessages); - Assert.Equal(42, receivedMessages[0]); - }); + // Assert + Assert.Single(receivedMessages); + Assert.Equal(42, receivedMessages[0]); + } /// - /// Tests MessageBus.Current static property for 100% coverage. + /// Tests MessageBus.Current static property for complete coverage. /// - /// A representing the asynchronous operation. [Fact] - public async Task MessageBus_Current_ShouldBeAccessible() => - await RunAppBuilderTestAsync(() => - { - // Act - var current = MessageBus.Current; + public void MessageBus_Current_ShouldBeAccessible() + { + // Act + var current = MessageBus.Current; - // Assert - Assert.NotNull(current); - Assert.IsAssignableFrom(current); - }); + // Assert + Assert.NotNull(current); + Assert.IsAssignableFrom(current); + } /// /// Tests MessageBus with contracts to ensure message isolation. /// - /// A representing the asynchronous operation. [Fact] - public async Task MessageBus_WithContracts_ShouldIsolateMessages() => - await RunAppBuilderTestAsync(() => - { - // Arrange - var messageBus = new MessageBus(); - var contract1Messages = new List(); - var contract2Messages = new List(); - var noContractMessages = new List(); - - // Act - messageBus.Listen("Contract1").Subscribe(x => contract1Messages.Add(x)); - messageBus.Listen("Contract2").Subscribe(x => contract2Messages.Add(x)); - messageBus.Listen().Subscribe(x => noContractMessages.Add(x)); - - messageBus.SendMessage(1, "Contract1"); - messageBus.SendMessage(2, "Contract2"); - messageBus.SendMessage(3); - - // Assert - Assert.Single(contract1Messages); - Assert.Equal(1, contract1Messages[0]); - - Assert.Single(contract2Messages); - Assert.Equal(2, contract2Messages[0]); - - Assert.Single(noContractMessages); - Assert.Equal(3, noContractMessages[0]); - }); + public void MessageBus_WithContracts_ShouldIsolateMessages() + { + // Arrange + var messageBus = new MessageBus(); + var contract1Messages = new List(); + var contract2Messages = new List(); + var noContractMessages = new List(); + + // Act + messageBus.Listen("Contract1").Subscribe(x => contract1Messages.Add(x)); + messageBus.Listen("Contract2").Subscribe(x => contract2Messages.Add(x)); + messageBus.Listen().Subscribe(x => noContractMessages.Add(x)); + + messageBus.SendMessage(1, "Contract1"); + messageBus.SendMessage(2, "Contract2"); + messageBus.SendMessage(3); + + // Assert + Assert.Single(contract1Messages); + Assert.Equal(1, contract1Messages[0]); + + Assert.Single(contract2Messages); + Assert.Equal(2, contract2Messages[0]); + + Assert.Single(noContractMessages); + Assert.Equal(3, noContractMessages[0]); + } } diff --git a/src/ReactiveUI.Tests/ObservableAsPropertyHelper/ObservableAsPropertyHelperTest.cs b/src/ReactiveUI.Tests/ObservableAsPropertyHelper/ObservableAsPropertyHelperTest.cs index 471bc8d9d1..b356984adb 100644 --- a/src/ReactiveUI.Tests/ObservableAsPropertyHelper/ObservableAsPropertyHelperTest.cs +++ b/src/ReactiveUI.Tests/ObservableAsPropertyHelper/ObservableAsPropertyHelperTest.cs @@ -7,12 +7,14 @@ using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; + namespace ReactiveUI.Tests; /// /// Tests for the observable as property helper. /// -public class ObservableAsPropertyHelperTest : AppBuilderTestBase +public class ObservableAsPropertyHelperTest { /// /// Tests that Observable As Property Helpers should fire change notifications. diff --git a/src/ReactiveUI.Tests/ObservedChanged/NewGameViewModelTests.cs b/src/ReactiveUI.Tests/ObservedChanged/NewGameViewModelTests.cs index adf142eace..b9a547064b 100644 --- a/src/ReactiveUI.Tests/ObservedChanged/NewGameViewModelTests.cs +++ b/src/ReactiveUI.Tests/ObservedChanged/NewGameViewModelTests.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Tests for a sample game. /// -public class NewGameViewModelTests : AppBuilderTestBase +public class NewGameViewModelTests { private readonly NewGameViewModel _viewmodel; diff --git a/src/ReactiveUI.Tests/ObservedChanged/ObservedChangedMixinTest.cs b/src/ReactiveUI.Tests/ObservedChanged/ObservedChangedMixinTest.cs index ef24eb7d52..8ffaad7b2d 100644 --- a/src/ReactiveUI.Tests/ObservedChanged/ObservedChangedMixinTest.cs +++ b/src/ReactiveUI.Tests/ObservedChanged/ObservedChangedMixinTest.cs @@ -5,12 +5,14 @@ using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; + namespace ReactiveUI.Tests; /// /// Tests for the ObservedChangedMixin. /// -public class ObservedChangedMixinTest : AppBuilderTestBase +public class ObservedChangedMixinTest { /// /// Tests that getting the value should actually return the value. diff --git a/src/ReactiveUI.Tests/Platforms/windows-xaml/CommandBindingImplementationTests.cs b/src/ReactiveUI.Tests/Platforms/windows-xaml/CommandBindingImplementationTests.cs index 85070672f0..d137b1d01d 100644 --- a/src/ReactiveUI.Tests/Platforms/windows-xaml/CommandBindingImplementationTests.cs +++ b/src/ReactiveUI.Tests/Platforms/windows-xaml/CommandBindingImplementationTests.cs @@ -15,236 +15,216 @@ namespace ReactiveUI.Tests.Xaml; /// /// Tests with the command binding implementation. /// -public class CommandBindingImplementationTests : AppBuilderTestBase +public class CommandBindingImplementationTests { /// /// Tests the command bind by name wireup. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindByNameWireup() => - await RunAppBuilderTestAsync(() => - { - var view = new CommandBindView { ViewModel = new() }; + public void CommandBindByNameWireup() + { + var view = new CommandBindView { ViewModel = new() }; - Assert.Null(view.Command1.Command); + Assert.Null(view.Command1.Command); - var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); - Assert.Equal(view.ViewModel.Command1, view.Command1.Command); + var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); + Assert.Equal(view.ViewModel.Command1, view.Command1.Command); - var newCmd = ReactiveCommand.Create(_ => { }); - view.ViewModel.Command1 = newCmd; - Assert.Equal(newCmd, view.Command1.Command); + var newCmd = ReactiveCommand.Create(_ => { }); + view.ViewModel.Command1 = newCmd; + Assert.Equal(newCmd, view.Command1.Command); - disp.Dispose(); - Assert.Null(view.Command1.Command); - }); + disp.Dispose(); + Assert.Null(view.Command1.Command); + } /// /// Tests the command bind nested command wireup. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindNestedCommandWireup() => - await RunAppBuilderTestAsync(() => + public void CommandBindNestedCommandWireup() + { + var vm = new CommandBindViewModel { - var vm = new CommandBindViewModel - { - NestedViewModel = new() - }; + NestedViewModel = new() + }; - var view = new CommandBindView { ViewModel = vm }; + var view = new CommandBindView { ViewModel = vm }; - view.BindCommand(view.ViewModel, m => m.NestedViewModel.NestedCommand, x => x.Command1); + view.BindCommand(view.ViewModel, m => m.NestedViewModel.NestedCommand, x => x.Command1); - Assert.Equal(view.ViewModel.NestedViewModel.NestedCommand, view.Command1.Command); - }); + Assert.Equal(view.ViewModel.NestedViewModel.NestedCommand, view.Command1.Command); + } /// /// Tests the command bind sets initial enabled state true. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindSetsInitialEnabledState_True() => - await RunAppBuilderTestAsync(() => - { - var view = new CommandBindView { ViewModel = new() }; + public void CommandBindSetsInitialEnabledState_True() + { + var view = new CommandBindView { ViewModel = new() }; - var canExecute1 = new BehaviorSubject(true); - view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); + var canExecute1 = new BehaviorSubject(true); + view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); - view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); + view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); - Assert.True(view.Command1.IsEnabled); - }); + Assert.True(view.Command1.IsEnabled); + } /// /// Tests the command bind sets disables command when can execute changed. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindSetsDisablesCommandWhenCanExecuteChanged() => - await RunAppBuilderTestAsync(() => - { - var view = new CommandBindView { ViewModel = new() }; + public void CommandBindSetsDisablesCommandWhenCanExecuteChanged() + { + var view = new CommandBindView { ViewModel = new() }; - var canExecute1 = new BehaviorSubject(true); - view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); + var canExecute1 = new BehaviorSubject(true); + view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); - view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); + view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); - Assert.True(view.Command1.IsEnabled); + Assert.True(view.Command1.IsEnabled); - canExecute1.OnNext(false); + canExecute1.OnNext(false); - Assert.False(view.Command1.IsEnabled); - }); + Assert.False(view.Command1.IsEnabled); + } /// /// Tests the command bind sets initial enabled state false. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindSetsInitialEnabledState_False() => - await RunAppBuilderTestAsync(() => - { - var view = new CommandBindView { ViewModel = new() }; + public void CommandBindSetsInitialEnabledState_False() + { + var view = new CommandBindView { ViewModel = new() }; - var canExecute1 = new BehaviorSubject(false); - view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); + var canExecute1 = new BehaviorSubject(false); + view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); - view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); + view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); - Assert.False(view.Command1.IsEnabled); - }); + Assert.False(view.Command1.IsEnabled); + } /// /// Tests the command bind raises can execute changed on bind. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindRaisesCanExecuteChangedOnBind() => - await RunAppBuilderTestAsync(() => - { - var view = new CommandBindView { ViewModel = new() }; + public void CommandBindRaisesCanExecuteChangedOnBind() + { + var view = new CommandBindView { ViewModel = new() }; - var canExecute1 = new BehaviorSubject(true); - view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); + var canExecute1 = new BehaviorSubject(true); + view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute1); - view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); + view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1); - Assert.True(view.Command1.IsEnabled); + Assert.True(view.Command1.IsEnabled); - // Now change to a disabled cmd - var canExecute2 = new BehaviorSubject(false); - view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute2); + // Now change to a disabled cmd + var canExecute2 = new BehaviorSubject(false); + view.ViewModel.Command1 = ReactiveCommand.Create(_ => { }, canExecute2); - Assert.False(view.Command1.IsEnabled); - }); + Assert.False(view.Command1.IsEnabled); + } /// /// Tests the command bind with parameter expression. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindWithParameterExpression() => - await RunAppBuilderTestAsync(() => - { - var view = new CommandBindView { ViewModel = new() }; + public void CommandBindWithParameterExpression() + { + var view = new CommandBindView { ViewModel = new() }; - var received = 0; - view.ViewModel.Command1 = ReactiveCommand.Create(i => received = i); + var received = 0; + view.ViewModel.Command1 = ReactiveCommand.Create(i => received = i); - var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); + var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); - view.ViewModel.Value = 42; - view.Command1.RaiseCustomClick(); - Assert.Equal(42, received); + view.ViewModel.Value = 42; + view.Command1.RaiseCustomClick(); + Assert.Equal(42, received); - view.ViewModel.Value = 13; - view.Command1.RaiseCustomClick(); - Assert.Equal(13, received); - }); + view.ViewModel.Value = 13; + view.Command1.RaiseCustomClick(); + Assert.Equal(13, received); + } /// /// Tests the command bind with delay set vm parameter expression. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindWithDelaySetVMParameterExpression() => - await RunAppBuilderTestAsync(() => + public void CommandBindWithDelaySetVMParameterExpression() + { + var view = new ReactiveObjectCommandBindView { - var view = new ReactiveObjectCommandBindView - { - ViewModel = new() - }; + ViewModel = new() + }; - var received = 0; - view.ViewModel.Command1 = ReactiveCommand.Create(i => received = i); + var received = 0; + view.ViewModel.Command1 = ReactiveCommand.Create(i => received = i); - var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); + var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); - view.ViewModel.Value = 42; - view.Command1.RaiseCustomClick(); - Assert.Equal(42, received); + view.ViewModel.Value = 42; + view.Command1.RaiseCustomClick(); + Assert.Equal(42, received); - view.ViewModel.Value = 13; - view.Command1.RaiseCustomClick(); - Assert.Equal(13, received); - }); + view.ViewModel.Value = 13; + view.Command1.RaiseCustomClick(); + Assert.Equal(13, received); + } /// /// Tests the command bind with delay set vm parameter no inpc expression. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindWithDelaySetVMParameterNoINPCExpression() => - await RunAppBuilderTestAsync(() => - { - var view = new CommandBindView { ViewModel = new() }; + public void CommandBindWithDelaySetVMParameterNoINPCExpression() + { + var view = new CommandBindView { ViewModel = new() }; - var received = 0; - var cmd = ReactiveCommand.Create(i => received = i); - view.ViewModel.Command1 = cmd; - view.ViewModel.Value = 10; + var received = 0; + var cmd = ReactiveCommand.Create(i => received = i); + view.ViewModel.Command1 = cmd; + view.ViewModel.Value = 10; - view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); + view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, x => x.Value, nameof(CustomClickButton.CustomClick)); - view.Command1.RaiseCustomClick(); - Assert.Equal(10, received); + view.Command1.RaiseCustomClick(); + Assert.Equal(10, received); - view.ViewModel.Value = 42; - view.Command1.RaiseCustomClick(); - Assert.Equal(42, received); + view.ViewModel.Value = 42; + view.Command1.RaiseCustomClick(); + Assert.Equal(42, received); - view.ViewModel.Value = 13; - view.Command1.RaiseCustomClick(); - Assert.Equal(13, received); - }); + view.ViewModel.Value = 13; + view.Command1.RaiseCustomClick(); + Assert.Equal(13, received); + } /// /// Tests the command bind with parameter observable. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindWithParameterObservable() => - await RunAppBuilderTestAsync(() => - { - var view = new CommandBindView { ViewModel = new() }; + public void CommandBindWithParameterObservable() + { + var view = new CommandBindView { ViewModel = new() }; - var received = 0; - var cmd = ReactiveCommand.Create(i => received = i); - view.ViewModel.Command1 = cmd; - view.ViewModel.Value = 10; - var value = view.ViewModel.WhenAnyValue(v => v.Value); - var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, value, nameof(CustomClickButton.CustomClick)); + var received = 0; + var cmd = ReactiveCommand.Create(i => received = i); + view.ViewModel.Command1 = cmd; + view.ViewModel.Value = 10; + var value = view.ViewModel.WhenAnyValue(v => v.Value); + var disp = view.BindCommand(view.ViewModel, x => x.Command1, x => x.Command1, value, nameof(CustomClickButton.CustomClick)); - view.Command1.RaiseCustomClick(); - Assert.Equal(10, received); + view.Command1.RaiseCustomClick(); + Assert.Equal(10, received); - view.ViewModel.Value = 42; - view.Command1.RaiseCustomClick(); + view.ViewModel.Value = 42; + view.Command1.RaiseCustomClick(); - Assert.Equal(42, received); - }); + Assert.Equal(42, received); + } } diff --git a/src/ReactiveUI.Tests/Platforms/windows-xaml/PropertyBindingTest.cs b/src/ReactiveUI.Tests/Platforms/windows-xaml/PropertyBindingTest.cs index 398c1d3fc3..624b64e0c8 100644 --- a/src/ReactiveUI.Tests/Platforms/windows-xaml/PropertyBindingTest.cs +++ b/src/ReactiveUI.Tests/Platforms/windows-xaml/PropertyBindingTest.cs @@ -20,136 +20,130 @@ namespace ReactiveUI.Tests.Xaml; /// /// Tests property bindings. /// -public class PropertyBindingTest : AppBuilderTestBase +public class PropertyBindingTest { /// /// Performs a smoke test with two way binding with func converter. /// - /// A representing the asynchronous operation. [Fact] [UseInvariantCulture] - public async Task TwoWayBindWithFuncConvertersSmokeTest() => - await RunAppBuilderTestAsync(() => - { - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var fixture = new PropertyBinderImplementation(); + public void TwoWayBindWithFuncConvertersSmokeTest() + { + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var fixture = new PropertyBinderImplementation(); - vm.JustADecimal = 123.45m; - Assert.NotEqual(vm.JustADecimal.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); + vm.JustADecimal = 123.45m; + Assert.NotEqual(vm.JustADecimal.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); - var disp = fixture.Bind(vm, view, x => x.JustADecimal, x => x.SomeTextBox.Text, (IObservable?)null, d => d.ToString(), t => decimal.TryParse(t, out var res) ? res : decimal.Zero); + var disp = fixture.Bind(vm, view, x => x.JustADecimal, x => x.SomeTextBox.Text, (IObservable?)null, d => d.ToString(), t => decimal.TryParse(t, out var res) ? res : decimal.Zero); - Assert.Equal(vm.JustADecimal.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); - Assert.Equal(123.45m, vm.JustADecimal); + Assert.Equal(vm.JustADecimal.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); + Assert.Equal(123.45m, vm.JustADecimal); - view.SomeTextBox.Text = "567.89"; - Assert.Equal(567.89m, vm.JustADecimal); + view.SomeTextBox.Text = "567.89"; + Assert.Equal(567.89m, vm.JustADecimal); - disp?.Dispose(); - vm.JustADecimal = 0; + disp?.Dispose(); + vm.JustADecimal = 0; - Assert.Equal(0, vm.JustADecimal); - Assert.Equal("567.89", view.SomeTextBox.Text); - }); + Assert.Equal(0, vm.JustADecimal); + Assert.Equal("567.89", view.SomeTextBox.Text); + } /// /// Performs a smoke test with two way binding. /// - /// A representing the asynchronous operation. [Fact] - public async Task TwoWayBindSmokeTest() => - await RunAppBuilderTestAsync(() => - { - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var fixture = new PropertyBinderImplementation(); + public void TwoWayBindSmokeTest() + { + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var fixture = new PropertyBinderImplementation(); - vm.Property1 = "Foo"; - Assert.NotEqual(vm.Property1, view.SomeTextBox.Text); + vm.Property1 = "Foo"; + Assert.NotEqual(vm.Property1, view.SomeTextBox.Text); - var disp = fixture.Bind(vm, view, x => x.Property1, x => x.SomeTextBox.Text, (IObservable?)null, null); + var disp = fixture.Bind(vm, view, x => x.Property1, x => x.SomeTextBox.Text, (IObservable?)null, null); - Assert.Equal(vm.Property1, view.SomeTextBox.Text); - Assert.Equal("Foo", vm.Property1); + Assert.Equal(vm.Property1, view.SomeTextBox.Text); + Assert.Equal("Foo", vm.Property1); - view.SomeTextBox.Text = "Bar"; - Assert.Equal(vm.Property1, "Bar"); + view.SomeTextBox.Text = "Bar"; + Assert.Equal(vm.Property1, "Bar"); - disp.Dispose(); - vm.Property1 = "Baz"; + disp.Dispose(); + vm.Property1 = "Baz"; - Assert.Equal("Baz", vm.Property1); - Assert.NotEqual(vm.Property1, view.SomeTextBox.Text); - }); + Assert.Equal("Baz", vm.Property1); + Assert.NotEqual(vm.Property1, view.SomeTextBox.Text); + } /// /// Performs a smoke test with two way binding with a type converter. /// - /// A representing the asynchronous operation. [Fact] - public async Task TypeConvertedTwoWayBindSmokeTest() => - await RunAppBuilderTestAsync(() => - { - var vm = new PropertyBindViewModel(); - var view = new PropertyBindView { ViewModel = vm }; - var fixture = new PropertyBinderImplementation(); + public void TypeConvertedTwoWayBindSmokeTest() + { + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var fixture = new PropertyBinderImplementation(); - vm.Property2 = 17; - Assert.NotEqual(vm.Property2.ToString(), view.SomeTextBox.Text); + vm.Property2 = 17; + Assert.NotEqual(vm.Property2.ToString(), view.SomeTextBox.Text); - var disp = fixture.Bind(vm, view, x => x.Property2, x => x.SomeTextBox.Text, (IObservable?)null, null); + var disp = fixture.Bind(vm, view, x => x.Property2, x => x.SomeTextBox.Text, (IObservable?)null, null); - Assert.Equal(vm.Property2.ToString(), view.SomeTextBox.Text); - Assert.Equal(17, vm.Property2); + Assert.Equal(vm.Property2.ToString(), view.SomeTextBox.Text); + Assert.Equal(17, vm.Property2); - view.SomeTextBox.Text = "42"; - Assert.Equal(42, vm.Property2); + view.SomeTextBox.Text = "42"; + Assert.Equal(42, vm.Property2); - // Bad formatting error - view.SomeTextBox.Text = "--"; - Assert.Equal(42, vm.Property2); + // Bad formatting error + view.SomeTextBox.Text = "--"; + Assert.Equal(42, vm.Property2); - disp.Dispose(); - vm.Property2 = 0; + disp.Dispose(); + vm.Property2 = 0; - Assert.Equal(0, vm.Property2); - Assert.NotEqual("0", view.SomeTextBox.Text); + Assert.Equal(0, vm.Property2); + Assert.NotEqual("0", view.SomeTextBox.Text); - vm.JustADecimal = 17.2m; - var disp1 = fixture.Bind(vm, view, x => x.JustADecimal, x => x.SomeTextBox.Text, (IObservable?)null, null); + vm.JustADecimal = 17.2m; + var disp1 = fixture.Bind(vm, view, x => x.JustADecimal, x => x.SomeTextBox.Text, (IObservable?)null, null); - Assert.Equal(vm.JustADecimal.ToString(CultureInfo.CurrentCulture), view.SomeTextBox.Text); - Assert.Equal(17.2m, vm.JustADecimal); + Assert.Equal(vm.JustADecimal.ToString(CultureInfo.CurrentCulture), view.SomeTextBox.Text); + Assert.Equal(17.2m, vm.JustADecimal); - view.SomeTextBox.Text = 42.3m.ToString(CultureInfo.CurrentCulture); - Assert.Equal(42.3m, vm.JustADecimal); + view.SomeTextBox.Text = 42.3m.ToString(CultureInfo.CurrentCulture); + Assert.Equal(42.3m, vm.JustADecimal); - // Bad formatting. - view.SomeTextBox.Text = "--"; - Assert.Equal(42.3m, vm.JustADecimal); + // Bad formatting. + view.SomeTextBox.Text = "--"; + Assert.Equal(42.3m, vm.JustADecimal); - disp1.Dispose(); + disp1.Dispose(); - vm.JustADecimal = 0; + vm.JustADecimal = 0; - Assert.Equal(0, vm.JustADecimal); - Assert.NotEqual("0", view.SomeTextBox.Text); + Assert.Equal(0, vm.JustADecimal); + Assert.NotEqual("0", view.SomeTextBox.Text); - // Empty test - vm.JustAInt32 = 12; - var disp2 = fixture.Bind(vm, view, x => x.JustAInt32, x => x.SomeTextBox.Text, (IObservable?)null, null); + // Empty test + vm.JustAInt32 = 12; + var disp2 = fixture.Bind(vm, view, x => x.JustAInt32, x => x.SomeTextBox.Text, (IObservable?)null, null); - view.SomeTextBox.Text = string.Empty; - Assert.Equal(12, vm.JustAInt32); + view.SomeTextBox.Text = string.Empty; + Assert.Equal(12, vm.JustAInt32); - view.SomeTextBox.Text = "1.2"; + view.SomeTextBox.Text = "1.2"; - Assert.Equal(12, vm.JustAInt32); + Assert.Equal(12, vm.JustAInt32); - view.SomeTextBox.Text = "13"; - Assert.Equal(13, vm.JustAInt32); - }); + view.SomeTextBox.Text = "13"; + Assert.Equal(13, vm.JustAInt32); + } /// /// Tests binding into model objects. @@ -790,6 +784,52 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithNullableDecimalCon Assert.True(dis.IsDisposed); } + [Fact] + public void BindWithFuncToTriggerUpdateTestViewToViewModel() + { + var dis = new CompositeDisposable(); + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var update = new Subject(); + + vm.JustADecimal = 123.45m; + Assert.NotEqual(vm.JustADecimal.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); + + view.Bind(vm, x => x.JustADecimal, x => x.SomeTextBox.Text, update.AsObservable(), d => d.ToString(CultureInfo.InvariantCulture), t => decimal.TryParse(t, out var res) ? res : decimal.Zero, TriggerUpdate.ViewToViewModel).DisposeWith(dis); + + view.SomeTextBox.Text = "1.0"; + + // value should have pre bind value + Assert.Equal(vm.JustADecimal, 123.45m); + + // trigger UI update + update.OnNext(true); + Assert.Equal(vm.JustADecimal, 1.0m); + + view.SomeTextBox.Text = "2.0"; + Assert.Equal(vm.JustADecimal, 1.0m); + + update.OnNext(true); + Assert.Equal(vm.JustADecimal, 2.0m); + + // test reverse bind no trigger required + vm.JustADecimal = 3.0m; + Assert.Equal(view.SomeTextBox.Text, "3.0"); + + vm.JustADecimal = 4.0m; + Assert.Equal(view.SomeTextBox.Text, "4.0"); + + // test forward bind to ensure trigger is still honoured. + view.SomeTextBox.Text = "2.0"; + Assert.Equal(vm.JustADecimal, 4.0m); + + update.OnNext(true); + Assert.Equal(vm.JustADecimal, 2.0m); + + dis.Dispose(); + Assert.True(dis.IsDisposed); + } + [Fact] public void BindWithFuncToTriggerUpdateTestViewModelToViewWithDoubleConverter() { @@ -1036,6 +1076,52 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithNullableSingleConv Assert.True(dis.IsDisposed); } + [Fact] + public void BindWithFuncToTriggerUpdateTestViewModelToViewWithSingleConverterNoRound() + { + var dis = new CompositeDisposable(); + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var update = new Subject(); + + vm.JustASingle = 123.45f; + Assert.NotEqual(vm.JustASingle.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); + + view.Bind(vm, x => x.JustASingle, x => x.SomeTextBox.Text, update.AsObservable(), null, triggerUpdate: TriggerUpdate.ViewModelToView).DisposeWith(dis); + + vm.JustASingle = 1.0f; + + // value should have pre bind value + Assert.Equal(view.SomeTextBox.Text, "123.45"); + + // trigger UI update + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "1"); + + vm.JustASingle = 2.0f; + Assert.Equal(view.SomeTextBox.Text, "1"); + + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "2"); + + // test reverse bind no trigger required + view.SomeTextBox.Text = "3"; + Assert.Equal(vm.JustASingle, 3.0f); + + view.SomeTextBox.Text = "4"; + Assert.Equal(vm.JustASingle, 4.0f); + + // test forward bind to ensure trigger is still honoured. + vm.JustASingle = 2.0f; + Assert.Equal(view.SomeTextBox.Text, "4"); + + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "2"); + + dis.Dispose(); + Assert.True(dis.IsDisposed); + } + [Fact] public void BindWithFuncToTriggerUpdateTestViewModelToViewWithByteConverter() { @@ -1136,6 +1222,52 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithNullableByteConver Assert.True(dis.IsDisposed); } + [Fact] + public void BindWithFuncToTriggerUpdateTestViewModelToViewWithByteConverterNoHint() + { + var dis = new CompositeDisposable(); + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var update = new Subject(); + + vm.JustAByte = 123; + Assert.NotEqual(vm.JustAByte.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); + + view.Bind(vm, x => x.JustAByte, x => x.SomeTextBox.Text, update.AsObservable(), null, triggerUpdate: TriggerUpdate.ViewModelToView).DisposeWith(dis); + + vm.JustAByte = 1; + + // value should have pre bind value + Assert.Equal(view.SomeTextBox.Text, "123"); + + // trigger UI update + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "1"); + + vm.JustAByte = 2; + Assert.Equal(view.SomeTextBox.Text, "1"); + + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "2"); + + // test reverse bind no trigger required + view.SomeTextBox.Text = "3"; + Assert.Equal(vm.JustAByte, 3); + + view.SomeTextBox.Text = "4"; + Assert.Equal(vm.JustAByte, 4); + + // test forward bind to ensure trigger is still honoured. + vm.JustAByte = 2; + Assert.Equal(view.SomeTextBox.Text, "4"); + + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "2"); + + dis.Dispose(); + Assert.True(dis.IsDisposed); + } + [Fact] public void BindWithFuncToTriggerUpdateTestViewModelToViewWithShortConverter() { @@ -1236,6 +1368,52 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithNullableShortConve Assert.True(dis.IsDisposed); } + [Fact] + public void BindWithFuncToTriggerUpdateTestViewModelToViewWithShortConverterNoHint() + { + var dis = new CompositeDisposable(); + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var update = new Subject(); + + vm.JustAInt16 = 123; + Assert.NotEqual(vm.JustAInt16.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); + + view.Bind(vm, x => x.JustAInt16, x => x.SomeTextBox.Text, update.AsObservable(), null, triggerUpdate: TriggerUpdate.ViewModelToView).DisposeWith(dis); + + vm.JustAInt16 = 1; + + // value should have pre bind value + Assert.Equal(view.SomeTextBox.Text, "123"); + + // trigger UI update + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "1"); + + vm.JustAInt16 = 2; + Assert.Equal(view.SomeTextBox.Text, "1"); + + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "2"); + + // test reverse bind no trigger required + view.SomeTextBox.Text = "3"; + Assert.Equal(vm.JustAInt16, 3); + + view.SomeTextBox.Text = "4"; + Assert.Equal(vm.JustAInt16, 4); + + // test forward bind to ensure trigger is still honoured. + vm.JustAInt16 = 2; + Assert.Equal(view.SomeTextBox.Text, "4"); + + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "2"); + + dis.Dispose(); + Assert.True(dis.IsDisposed); + } + [Fact] public void BindWithFuncToTriggerUpdateTestViewModelToViewWithIntegerConverter() { @@ -1336,6 +1514,52 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithNullableIntegerCon Assert.True(dis.IsDisposed); } + [Fact] + public void BindWithFuncToTriggerUpdateTestViewModelToViewWithIntegerConverterNoHint() + { + var dis = new CompositeDisposable(); + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var update = new Subject(); + + vm.JustAInt32 = 123; + Assert.NotEqual(vm.JustAInt32.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); + + view.Bind(vm, x => x.JustAInt32, x => x.SomeTextBox.Text, update.AsObservable(), null, triggerUpdate: TriggerUpdate.ViewModelToView).DisposeWith(dis); + + vm.JustAInt32 = 1; + + // value should have pre bind value + Assert.Equal(view.SomeTextBox.Text, "123"); + + // trigger UI update + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "1"); + + vm.JustAInt32 = 2; + Assert.Equal(view.SomeTextBox.Text, "1"); + + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "2"); + + // test reverse bind no trigger required + view.SomeTextBox.Text = "3"; + Assert.Equal(vm.JustAInt32, 3); + + view.SomeTextBox.Text = "4"; + Assert.Equal(vm.JustAInt32, 4); + + // test forward bind to ensure trigger is still honoured. + vm.JustAInt32 = 2; + Assert.Equal(view.SomeTextBox.Text, "4"); + + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "2"); + + dis.Dispose(); + Assert.True(dis.IsDisposed); + } + [Fact] public void BindWithFuncToTriggerUpdateTestViewModelToViewWithLongConverter() { @@ -1383,4 +1607,50 @@ public void BindWithFuncToTriggerUpdateTestViewModelToViewWithLongConverter() dis.Dispose(); Assert.True(dis.IsDisposed); } + + [Fact] + public void BindWithFuncToTriggerUpdateTestViewModelToViewWithLongConverterNoHint() + { + var dis = new CompositeDisposable(); + var vm = new PropertyBindViewModel(); + var view = new PropertyBindView { ViewModel = vm }; + var update = new Subject(); + + vm.JustAInt64 = 123; + Assert.NotEqual(vm.JustAInt64.ToString(CultureInfo.InvariantCulture), view.SomeTextBox.Text); + + view.Bind(vm, x => x.JustAInt64, x => x.SomeTextBox.Text, update.AsObservable(), null, triggerUpdate: TriggerUpdate.ViewModelToView).DisposeWith(dis); + + vm.JustAInt64 = 1; + + // value should have pre bind value + Assert.Equal(view.SomeTextBox.Text, "123"); + + // trigger UI update + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "1"); + + vm.JustAInt64 = 2; + Assert.Equal(view.SomeTextBox.Text, "1"); + + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "2"); + + // test reverse bind no trigger required + view.SomeTextBox.Text = "3"; + Assert.Equal(vm.JustAInt64, 3); + + view.SomeTextBox.Text = "4"; + Assert.Equal(vm.JustAInt64, 4); + + // test forward bind to ensure trigger is still honoured. + vm.JustAInt64 = 2; + Assert.Equal(view.SomeTextBox.Text, "4"); + + update.OnNext(true); + Assert.Equal(view.SomeTextBox.Text, "2"); + + dis.Dispose(); + Assert.True(dis.IsDisposed); + } } diff --git a/src/ReactiveUI.Tests/Platforms/windows-xaml/RxAppDependencyObjectTests.cs b/src/ReactiveUI.Tests/Platforms/windows-xaml/RxAppDependencyObjectTests.cs index 63c68db716..320223bb46 100644 --- a/src/ReactiveUI.Tests/Platforms/windows-xaml/RxAppDependencyObjectTests.cs +++ b/src/ReactiveUI.Tests/Platforms/windows-xaml/RxAppDependencyObjectTests.cs @@ -8,19 +8,17 @@ namespace ReactiveUI.Tests.Xaml; /// /// Checks RxApp dependency objects. /// -public class RxAppDependencyObjectTests : AppBuilderTestBase +public class RxAppDependencyObjectTests { /// /// Tests that Dependency Property notifiers should be found. /// - /// A representing the asynchronous operation. [Fact] - public async Task DepPropNotifierShouldBeFound() => - await RunAppBuilderTestAsync(() => - { - RxApp.EnsureInitialized(); + public void DepPropNotifierShouldBeFound() + { + RxApp.EnsureInitialized(); - Assert.True(Locator.Current.GetServices() - .Any(x => x is DependencyObjectObservableForProperty)); - }); + Assert.True(Locator.Current.GetServices() + .Any(x => x is DependencyObjectObservableForProperty)); + } } diff --git a/src/ReactiveUI.Tests/Platforms/windows-xaml/WhenAnyThroughDependencyObjectTests.cs b/src/ReactiveUI.Tests/Platforms/windows-xaml/WhenAnyThroughDependencyObjectTests.cs index 3273b3482e..3172cd7532 100644 --- a/src/ReactiveUI.Tests/Platforms/windows-xaml/WhenAnyThroughDependencyObjectTests.cs +++ b/src/ReactiveUI.Tests/Platforms/windows-xaml/WhenAnyThroughDependencyObjectTests.cs @@ -15,40 +15,38 @@ namespace ReactiveUI.Tests.Xaml; /// /// Tests that WhenAny dependency objects. /// -public class WhenAnyThroughDependencyObjectTests : AppBuilderTestBase +public class WhenAnyThroughDependencyObjectTests { /// /// Tests that WhenAny through a view shouldn't give null values. /// - /// A representing the asynchronous operation. [Fact] - public async Task WhenAnyThroughAViewShouldntGiveNullValues() => - await RunAppBuilderTestAsync(() => + public void WhenAnyThroughAViewShouldntGiveNullValues() + { + var vm = new HostTestFixture() { - var vm = new HostTestFixture() + Child = new TestFixture { - Child = new TestFixture - { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }, - }; + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }, + }; - var fixture = new HostTestView(); + var fixture = new HostTestView(); - var output = new List(); + var output = new List(); - Assert.Equal(0, output.Count); - Assert.Null(fixture.ViewModel); + Assert.Equal(0, output.Count); + Assert.Null(fixture.ViewModel); - fixture.WhenAnyValue(x => x.ViewModel!.Child!.IsNotNullString).Subscribe(output.Add); + fixture.WhenAnyValue(x => x.ViewModel!.Child!.IsNotNullString).Subscribe(output.Add); - fixture.ViewModel = vm; - Assert.Equal(1, output.Count); + fixture.ViewModel = vm; + Assert.Equal(1, output.Count); - fixture.ViewModel.Child.IsNotNullString = "Bar"; - Assert.Equal(2, output.Count); - new[] { "Foo", "Bar" }.AssertAreEqual(output); - }); + fixture.ViewModel.Child.IsNotNullString = "Bar"; + Assert.Equal(2, output.Count); + new[] { "Foo", "Bar" }.AssertAreEqual(output); + } } diff --git a/src/ReactiveUI.Tests/Platforms/windows-xaml/XamlViewDependencyResolverTests.cs b/src/ReactiveUI.Tests/Platforms/windows-xaml/XamlViewDependencyResolverTests.cs index 8b39d7d2ae..6c86ea803f 100644 --- a/src/ReactiveUI.Tests/Platforms/windows-xaml/XamlViewDependencyResolverTests.cs +++ b/src/ReactiveUI.Tests/Platforms/windows-xaml/XamlViewDependencyResolverTests.cs @@ -16,7 +16,7 @@ namespace ReactiveUI.Tests.Xaml; /// /// Tests associated with UI and the . /// -public sealed class XamlViewDependencyResolverTests : AppBuilderTestBase, IDisposable +public sealed class XamlViewDependencyResolverTests : IDisposable { private readonly IDependencyResolver _resolver; @@ -34,33 +34,29 @@ public XamlViewDependencyResolverTests() /// /// Test that register views for view model should register all views. /// - /// A representing the asynchronous operation. [Fact] - public async Task RegisterViewsForViewModelShouldRegisterAllViews() => - await RunAppBuilderTestAsync(() => + public void RegisterViewsForViewModelShouldRegisterAllViews() + { + using (_resolver.WithResolver()) { - using (_resolver.WithResolver()) - { - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - } - }); + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + } + } /// /// Test that register views for view model should include contracts. /// - /// A representing the asynchronous operation. [Fact] - public async Task RegisterViewsForViewModelShouldIncludeContracts() => - await RunAppBuilderTestAsync(() => + public void RegisterViewsForViewModelShouldIncludeContracts() + { + using (_resolver.WithResolver()) { - using (_resolver.WithResolver()) - { - Assert.Single(_resolver.GetServices(typeof(IViewFor), "contract")); - } - }); + Assert.Single(_resolver.GetServices(typeof(IViewFor), "contract")); + } + } /// public void Dispose() => _resolver?.Dispose(); diff --git a/src/ReactiveUI.Tests/Platforms/winforms/ActivationTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/ActivationTests.cs index 01b9161f49..bc68cfa0ce 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/ActivationTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/ActivationTests.cs @@ -10,140 +10,130 @@ namespace ReactiveUI.Tests.Winforms; /// /// Tests to make sure the activation works correctly. /// -public class ActivationTests : AppBuilderTestBase +public class ActivationTests { /// /// Tests activations for view fetcher supports default winforms components. /// - /// A representing the asynchronous operation. [Fact] - public async Task ActivationForViewFetcherSupportsDefaultWinformsComponents() => - await RunAppBuilderTestAsync(() => - { - var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); - var supportedComponents = new[] { typeof(Control), typeof(UserControl), typeof(Form) }; + public void ActivationForViewFetcherSupportsDefaultWinformsComponents() + { + var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); + var supportedComponents = new[] { typeof(Control), typeof(UserControl), typeof(Form) }; - foreach (var c in supportedComponents) - { - Assert.Equal(10, target.GetAffinityForView(c)); - } - }); + foreach (var c in supportedComponents) + { + Assert.Equal(10, target.GetAffinityForView(c)); + } + } /// /// Tests that determines whether this instance [can fetch activator for form]. /// - /// A representing the asynchronous operation. [Fact] - public async Task CanFetchActivatorForForm() => - await RunAppBuilderTestAsync(() => - { - var form = new TestForm(); - var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); - var formActivator = target.GetActivationForView(form); + public void CanFetchActivatorForForm() + { + var form = new TestForm(); + var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); + var formActivator = target.GetActivationForView(form); - Assert.NotNull(formActivator); - }); + Assert.NotNull(formActivator); + } /// /// Tests that determines whether this instance [can fetch activator for control]. /// - /// A representing the asynchronous operation. [Fact] - public async Task CanFetchActivatorForControl() => - await RunAppBuilderTestAsync(() => - { - var control = new TestControl(); - var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); - var activator = target.GetActivationForView(control); + public void CanFetchActivatorForControl() + { + var control = new TestControl(); + var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); + var activator = target.GetActivationForView(control); - Assert.NotNull(activator); - }); + Assert.NotNull(activator); + } /// /// Smokes the test windows form. /// - /// A representing the asynchronous operation. [Fact] - public async Task SmokeTestWindowsForm() => - await RunAppBuilderTestAsync(() => + public void SmokeTestWindowsForm() + { + var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); + using (var form = new TestForm()) { - var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); - using (var form = new TestForm()) - { - var formActivator = target.GetActivationForView(form); + var formActivator = target.GetActivationForView(form); - int formActivateCount = 0, formDeActivateCount = 0; - formActivator.Subscribe(activated => + int formActivateCount = 0, formDeActivateCount = 0; + formActivator.Subscribe(activated => + { + if (activated) { - if (activated) - { - formActivateCount++; - } - else - { - formDeActivateCount++; - } - }); - - Assert.Equal(0, formActivateCount); - Assert.Equal(0, formDeActivateCount); - - form.Visible = true; - Assert.Equal(1, formActivateCount); - - form.Visible = false; - Assert.Equal(1, formActivateCount); - Assert.Equal(1, formDeActivateCount); - - form.Visible = true; - Assert.Equal(2, formActivateCount); - - form.Close(); - Assert.Equal(2, formDeActivateCount); - } - }); + formActivateCount++; + } + else + { + formDeActivateCount++; + } + }); + + Assert.Equal(0, formActivateCount); + Assert.Equal(0, formDeActivateCount); + + form.Visible = true; + Assert.Equal(1, formActivateCount); + + form.Visible = false; + Assert.Equal(1, formActivateCount); + Assert.Equal(1, formDeActivateCount); + + form.Visible = true; + Assert.Equal(2, formActivateCount); + + form.Close(); + Assert.Equal(2, formDeActivateCount); + } + } /// /// Smokes the test user control. /// - /// A representing the asynchronous operation. [Fact] - public async Task SmokeTestUserControl() => - await RunAppBuilderTestAsync(() => + public void SmokeTestUserControl() + { + var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); + using (var userControl = new TestControl()) + using (var parent = new TestForm()) { - var target = new ReactiveUI.Winforms.ActivationForViewFetcher(); - using (var userControl = new TestControl()) - using (var parent = new TestForm()) - { - var userControlActivator = target.GetActivationForView(userControl); + var userControlActivator = target.GetActivationForView(userControl); - int userControlActivateCount = 0, userControlDeActivateCount = 0; - userControlActivator.Subscribe(activated => + int userControlActivateCount = 0, userControlDeActivateCount = 0; + userControlActivator.Subscribe(activated => + { + if (activated) + { + userControlActivateCount++; + } + else { - if (activated) - { - userControlActivateCount++; - } - else - { - userControlDeActivateCount++; - } - }); - - parent.Visible = true; - parent.Controls.Add(userControl); - - userControl.Visible = true; - Assert.Equal(1, userControlActivateCount); - userControl.Visible = false; - Assert.Equal(1, userControlDeActivateCount); - - userControl.Visible = true; - Assert.Equal(2, userControlActivateCount); - - // closing the form deactivated the usercontrol - parent.Close(); - Assert.Equal(2, userControlDeActivateCount); - } - }); + userControlDeActivateCount++; + } + }); + + parent.Visible = true; + parent.Controls.Add(userControl); + + userControl.Visible = true; + Assert.Equal(1, userControlActivateCount); + userControl.Visible = false; + Assert.Equal(1, userControlDeActivateCount); + + userControl.Visible = true; + Assert.Equal(2, userControlActivateCount); + + // closing the form deactivated the usercontrol + parent.Close(); + Assert.Equal(2, userControlDeActivateCount); + } + } } diff --git a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs index e576b83f9e..5177943c04 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingImplementationTests.cs @@ -4,136 +4,132 @@ // See the LICENSE file in the project root for full license information. using System.Windows.Forms; +using ReactiveUI.Testing; namespace ReactiveUI.Tests.Winforms; /// /// Checks the command bindings. /// -public class CommandBindingImplementationTests : AppBuilderTestBase +public class CommandBindingImplementationTests { /// /// Tests the command bind by name wireup. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBindByNameWireup() => - await RunAppBuilderTestAsync(() => - { - var vm = new WinformCommandBindViewModel(); - var view = new WinformCommandBindView { ViewModel = vm }; - var fixture = new CommandBinderImplementation(); + public void CommandBindByNameWireup() + { + var vm = new WinformCommandBindViewModel(); + var view = new WinformCommandBindView { ViewModel = vm }; + var fixture = new CommandBinderImplementation(); - var invokeCount = 0; - vm.Command1.Subscribe(_ => ++invokeCount); + var invokeCount = 0; + vm.Command1.Subscribe(_ => ++invokeCount); - var disp = fixture.BindCommand(vm, view, x => x.Command1, x => x.Command1); + var disp = fixture.BindCommand(vm, view, x => x.Command1, x => x.Command1); - view.Command1.PerformClick(); + view.Command1.PerformClick(); - Assert.Equal(1, invokeCount); + Assert.Equal(1, invokeCount); - var newCmd = ReactiveCommand.Create(() => { }); - vm.Command1 = newCmd; + var newCmd = ReactiveCommand.Create(() => { }); + vm.Command1 = newCmd; - view.Command1.PerformClick(); - Assert.Equal(1, invokeCount); + view.Command1.PerformClick(); + Assert.Equal(1, invokeCount); - disp.Dispose(); - }); + disp.Dispose(); + } /// /// Tests the command bind explicit event wire up. /// /// A representing the asynchronous unit test. [Fact] - public async Task CommandBindToExplicitEventWireupAsync() => - await RunAppBuilderTestAsync(async () => + public async Task CommandBindToExplicitEventWireupAsync() + { + using var testSequencer = new TestSequencer(); + var vm = new WinformCommandBindViewModel(); + var view = new WinformCommandBindView { ViewModel = vm }; + var fixture = new CommandBinderImplementation(); + + var invokeCount = 0; + vm.Command2.Subscribe(async _ => { - using var testSequencer = new TestSequencer(); - var vm = new WinformCommandBindViewModel(); - var view = new WinformCommandBindView { ViewModel = vm }; - var fixture = new CommandBinderImplementation(); + ++invokeCount; + await testSequencer.AdvancePhaseAsync(); + }); - var invokeCount = 0; - vm.Command2.Subscribe(async _ => - { - ++invokeCount; - await testSequencer.AdvancePhaseAsync(); - }); + var disp = fixture.BindCommand(vm, view, x => x.Command2, x => x.Command2, "MouseUp"); - var disp = fixture.BindCommand(vm, view, x => x.Command2, x => x.Command2, "MouseUp"); + view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); + disp.Dispose(); - disp.Dispose(); + view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - - await testSequencer.AdvancePhaseAsync(); - Assert.Equal(1, invokeCount); - }); + await testSequencer.AdvancePhaseAsync(); + Assert.Equal(1, invokeCount); + } [Fact] - public async Task CommandBindByNameWireupWithParameter() => - await RunAppBuilderTestAsync(() => - { - var vm = new WinformCommandBindViewModel(); - var view = new WinformCommandBindView { ViewModel = vm }; - ICommandBinderImplementation fixture = new CommandBinderImplementation(); + public void CommandBindByNameWireupWithParameter() + { + var vm = new WinformCommandBindViewModel(); + var view = new WinformCommandBindView { ViewModel = vm }; + ICommandBinderImplementation fixture = new CommandBinderImplementation(); - var invokeCount = 0; - vm.Command3.Subscribe(_ => ++invokeCount); + var invokeCount = 0; + vm.Command3.Subscribe(_ => ++invokeCount); - var disp = CommandBinderImplementationMixins.BindCommand(fixture, vm, view, vm => vm.Command3, v => v.Command1, vm => vm.Parameter); + var disp = CommandBinderImplementationMixins.BindCommand(fixture, vm, view, vm => vm.Command3, v => v.Command1, vm => vm.Parameter); - view.Command1.PerformClick(); - Assert.Equal(1, invokeCount); - Assert.Equal(10, vm.ParameterResult); + view.Command1.PerformClick(); + Assert.Equal(1, invokeCount); + Assert.Equal(10, vm.ParameterResult); - // update the parameter to ensure its updated when the command is executed - vm.Parameter = 2; - view.Command1.PerformClick(); - Assert.Equal(2, invokeCount); - Assert.Equal(20, vm.ParameterResult); + // update the parameter to ensure its updated when the command is executed + vm.Parameter = 2; + view.Command1.PerformClick(); + Assert.Equal(2, invokeCount); + Assert.Equal(20, vm.ParameterResult); - // break the Command3 subscription - var newCmd = ReactiveCommand.Create(i => vm.ParameterResult = i * 2); - vm.Command3 = newCmd; + // break the Command3 subscription + var newCmd = ReactiveCommand.Create(i => vm.ParameterResult = i * 2); + vm.Command3 = newCmd; - // ensure that the invoke count does not update and that the Command3 is now using the new math - view.Command1.PerformClick(); - Assert.Equal(2, invokeCount); - Assert.Equal(4, vm.ParameterResult); + // ensure that the invoke count does not update and that the Command3 is now using the new math + view.Command1.PerformClick(); + Assert.Equal(2, invokeCount); + Assert.Equal(4, vm.ParameterResult); - disp.Dispose(); - }); + disp.Dispose(); + } [Fact] - public async Task CommandBindToExplicitEventWireupWithParameter() => - await RunAppBuilderTestAsync(() => - { - var vm = new WinformCommandBindViewModel(); - var view = new WinformCommandBindView { ViewModel = vm }; - var fixture = new CommandBinderImplementation(); + public void CommandBindToExplicitEventWireupWithParameter() + { + var vm = new WinformCommandBindViewModel(); + var view = new WinformCommandBindView { ViewModel = vm }; + var fixture = new CommandBinderImplementation(); - var invokeCount = 0; - vm.Command3.Subscribe(_ => ++invokeCount); + var invokeCount = 0; + vm.Command3.Subscribe(_ => ++invokeCount); - var disp = CommandBinderImplementationMixins.BindCommand(fixture, vm, view, x => x.Command3, x => x.Command2, vm => vm.Parameter, "MouseUp"); + var disp = CommandBinderImplementationMixins.BindCommand(fixture, vm, view, x => x.Command3, x => x.Command2, vm => vm.Parameter, "MouseUp"); - view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - Assert.Equal(10, vm.ParameterResult); - Assert.Equal(1, invokeCount); + view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); + Assert.Equal(10, vm.ParameterResult); + Assert.Equal(1, invokeCount); - vm.Parameter = 2; - view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - Assert.Equal(20, vm.ParameterResult); - Assert.Equal(2, invokeCount); + vm.Parameter = 2; + view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); + Assert.Equal(20, vm.ParameterResult); + Assert.Equal(2, invokeCount); - disp.Dispose(); + disp.Dispose(); - view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); - Assert.Equal(2, invokeCount); - }); + view.Command2.RaiseMouseUpEvent(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0)); + Assert.Equal(2, invokeCount); + } } diff --git a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs index faf50f8bf4..f5c39b9278 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs @@ -4,6 +4,7 @@ // See the LICENSE file in the project root for full license information. using System.Windows.Forms; +using ReactiveUI.Testing; using ReactiveUI.Winforms; namespace ReactiveUI.Tests.Winforms; @@ -11,150 +12,141 @@ namespace ReactiveUI.Tests.Winforms; /// /// Command binding tests. /// -public class CommandBindingTests : AppBuilderTestBase +public class CommandBindingTests { /// /// Tests that the command binder binds to button. /// /// A representing the asynchronous unit test. [Fact] - public async Task CommandBinderBindsToButtonAsync() => - await RunAppBuilderTestAsync(async () => + public async Task CommandBinderBindsToButtonAsync() + { + using var testSequencer = new TestSequencer(); + var fixture = new CreatesWinformsCommandBinding(); + var cmd = ReactiveCommand.CreateRunInBackground(_ => { }); + var input = new Button(); + + Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); + Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); + var commandExecuted = false; + object? ea = null; + cmd.Subscribe(async o => { - using var testSequencer = new TestSequencer(); - var fixture = new CreatesWinformsCommandBinding(); - var cmd = ReactiveCommand.CreateRunInBackground(_ => { }); - var input = new Button(); - - Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); - Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); - var commandExecuted = false; - object? ea = null; - cmd.Subscribe(async o => - { - ea = o; - commandExecuted = true; - await testSequencer.AdvancePhaseAsync("Phase 1"); - }); - - using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) - { - input.PerformClick(); - await testSequencer.AdvancePhaseAsync("Phase 1"); - Assert.True(commandExecuted); - Assert.NotNull(ea); - } + ea = o; + commandExecuted = true; + await testSequencer.AdvancePhaseAsync("Phase 1"); }); + using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + { + input.PerformClick(); + await testSequencer.AdvancePhaseAsync("Phase 1"); + Assert.True(commandExecuted); + Assert.NotNull(ea); + } + } + /// /// Tests that the command binder binds to custom control. /// - /// A representing the asynchronous unit test. [Fact] - public async Task CommandBinderBindsToCustomControl() => - await RunAppBuilderTestAsync(() => + public void CommandBinderBindsToCustomControl() + { + var fixture = new CreatesWinformsCommandBinding(); + var cmd = ReactiveCommand.Create(_ => { }); + var input = new CustomClickableControl(); + + Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); + Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); + var commandExecuted = false; + object? ea = null; + cmd.Subscribe(o => { - var fixture = new CreatesWinformsCommandBinding(); - var cmd = ReactiveCommand.Create(_ => { }); - var input = new CustomClickableControl(); - - Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); - Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); - var commandExecuted = false; - object? ea = null; - cmd.Subscribe(o => - { - ea = o; - commandExecuted = true; - }); - - using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) - { - input.PerformClick(); - - Assert.True(commandExecuted); - Assert.NotNull(ea); - } + ea = o; + commandExecuted = true; }); + using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + { + input.PerformClick(); + + Assert.True(commandExecuted); + Assert.NotNull(ea); + } + } + /// /// Tests that the command binder binds to custom component. /// - /// A representing the asynchronous unit test. [Fact] - public async Task CommandBinderBindsToCustomComponent() => - await RunAppBuilderTestAsync(() => + public void CommandBinderBindsToCustomComponent() + { + var fixture = new CreatesWinformsCommandBinding(); + var cmd = ReactiveCommand.Create(_ => { }); + var input = new CustomClickableComponent(); + + Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); + Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); + var commandExecuted = false; + object? ea = null; + cmd.Subscribe(o => { - var fixture = new CreatesWinformsCommandBinding(); - var cmd = ReactiveCommand.Create(_ => { }); - var input = new CustomClickableComponent(); - - Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0); - Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0); - var commandExecuted = false; - object? ea = null; - cmd.Subscribe(o => - { - ea = o; - commandExecuted = true; - }); - - using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) - { - input.PerformClick(); - - Assert.True(commandExecuted); - Assert.NotNull(ea); - } + ea = o; + commandExecuted = true; }); + using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + { + input.PerformClick(); + + Assert.True(commandExecuted); + Assert.NotNull(ea); + } + } + /// /// Tests that the command binder affects enabled. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBinderAffectsEnabledState() => - await RunAppBuilderTestAsync(() => - { - var fixture = new CreatesWinformsCommandBinding(); - var canExecute = new Subject(); - canExecute.OnNext(true); + public void CommandBinderAffectsEnabledState() + { + var fixture = new CreatesWinformsCommandBinding(); + var canExecute = new Subject(); + canExecute.OnNext(true); - var cmd = ReactiveCommand.Create(() => { }, canExecute); - var input = new Button(); + var cmd = ReactiveCommand.Create(() => { }, canExecute); + var input = new Button(); - using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) - { - canExecute.OnNext(true); - Assert.True(input.Enabled); + using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + { + canExecute.OnNext(true); + Assert.True(input.Enabled); - canExecute.OnNext(false); - Assert.False(input.Enabled); - } - }); + canExecute.OnNext(false); + Assert.False(input.Enabled); + } + } /// /// Tests that the command binder affects enabled state for components. /// - /// A representing the asynchronous operation. [Fact] - public async Task CommandBinderAffectsEnabledStateForComponents() => - await RunAppBuilderTestAsync(() => - { - var fixture = new CreatesWinformsCommandBinding(); - var canExecute = new Subject(); - canExecute.OnNext(true); + public void CommandBinderAffectsEnabledStateForComponents() + { + var fixture = new CreatesWinformsCommandBinding(); + var canExecute = new Subject(); + canExecute.OnNext(true); - var cmd = ReactiveCommand.Create(() => { }, canExecute); - var input = new ToolStripButton(); // ToolStripButton is a Component, not a Control + var cmd = ReactiveCommand.Create(() => { }, canExecute); + var input = new ToolStripButton(); // ToolStripButton is a Component, not a Control - using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) - { - canExecute.OnNext(true); - Assert.True(input.Enabled); + using (fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) + { + canExecute.OnNext(true); + Assert.True(input.Enabled); - canExecute.OnNext(false); - Assert.False(input.Enabled); - } - }); + canExecute.OnNext(false); + Assert.False(input.Enabled); + } + } } diff --git a/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs deleted file mode 100644 index dffaf0cbfa..0000000000 --- a/src/ReactiveUI.Tests/Platforms/winforms/ReactiveUIBuilderWinFormsTests.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using ReactiveUI.Builder; - -namespace ReactiveUI.Tests.Platforms.Winforms; - -/// -/// Tests for WinForms-specific ReactiveUIBuilder functionality. -/// -public class ReactiveUIBuilderWinFormsTests : AppBuilderTestBase -{ - /// - /// Test that WinForms services can be registered using the builder. - /// - /// A representing the asynchronous operation. - [Fact] - public async Task WithWinForms_Should_Register_WinForms_Services() => - await RunAppBuilderTestAsync(() => - { - // Arrange - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - - // Act - builder.WithWinForms().Build(); - - // Assert - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - - var activationFetcher = locator.GetService(); - Assert.NotNull(activationFetcher); - }); - - /// - /// Test that the builder can chain WinForms registration with core services. - /// - /// A representing the asynchronous operation. - [Fact] - public async Task WithCoreServices_AndWinForms_Should_Register_All_Services() => - await RunAppBuilderTestAsync(() => - { - // Arrange - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - - // Act - builder.WithWinForms().Build(); - - // Assert - // Core services - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); - - // WinForms-specific services - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - }); -} diff --git a/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs b/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs index e8c7268e86..5aeec4f94f 100644 --- a/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs +++ b/src/ReactiveUI.Tests/Platforms/winforms/WinFormsViewDependencyResolverTests.cs @@ -3,16 +3,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using Splat.Builder; using FactAttribute = Xunit.WpfFactAttribute; namespace ReactiveUI.Tests.Winforms; -public sealed class WinFormsViewDependencyResolverTests : AppBuilderTestBase, IDisposable +public sealed class WinFormsViewDependencyResolverTests : IDisposable { private readonly IDependencyResolver _resolver; public WinFormsViewDependencyResolverTests() { + AppBuilder.ResetBuilderStateForTests(); + // Reset static counters to avoid cross-test interference when running entire suite SingleInstanceExampleView.ResetInstances(); SingleInstanceWithContractExampleView.ResetInstances(); @@ -24,85 +27,79 @@ public WinFormsViewDependencyResolverTests() _resolver.RegisterViewsForViewModels(GetType().Assembly); } - [FactAttribute] - public async Task RegisterViewsForViewModelShouldRegisterAllViews() => - await RunAppBuilderTestAsync(() => + [Fact] + public void RegisterViewsForViewModelShouldRegisterAllViews() + { + using (_resolver.WithResolver()) { - using (_resolver.WithResolver()) - { - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - Assert.Single(_resolver.GetServices>()); - } - }); - - [FactAttribute] - public async Task NonContractRegistrationsShouldResolveCorrectly() => - await RunAppBuilderTestAsync(() => + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + Assert.Single(_resolver.GetServices>()); + } + } + + [Fact] + public void NonContractRegistrationsShouldResolveCorrectly() + { + using (_resolver.WithResolver()) { - using (_resolver.WithResolver()) - { - Assert.IsType(_resolver.GetService>()); - } - }); + Assert.IsType(_resolver.GetService>()); + } + } /// public void Dispose() => _resolver?.Dispose(); - [FactAttribute] - public async Task ContractRegistrationsShouldResolveCorrectly() => - await RunAppBuilderTestAsync(() => + [Fact] + public void ContractRegistrationsShouldResolveCorrectly() + { + using (_resolver.WithResolver()) { - using (_resolver.WithResolver()) - { - Assert.IsType(_resolver.GetService(typeof(IViewFor), "contract")); - } - }); - - [FactAttribute] - public async Task SingleInstanceViewsShouldOnlyBeInstantiatedOnce() => - await RunAppBuilderTestAsync(() => + Assert.IsType(_resolver.GetService(typeof(IViewFor), "contract")); + } + } + + [Fact] + public void SingleInstanceViewsShouldOnlyBeInstantiatedOnce() + { + using (_resolver.WithResolver()) { - using (_resolver.WithResolver()) - { - Assert.Equal(0, SingleInstanceExampleView.Instances); + Assert.Equal(0, SingleInstanceExampleView.Instances); - var instance = _resolver.GetService(typeof(IViewFor)); - Assert.Equal(1, SingleInstanceExampleView.Instances); + var instance = _resolver.GetService(typeof(IViewFor)); + Assert.Equal(1, SingleInstanceExampleView.Instances); - var instance2 = _resolver.GetService(typeof(IViewFor)); - Assert.Equal(1, SingleInstanceExampleView.Instances); + var instance2 = _resolver.GetService(typeof(IViewFor)); + Assert.Equal(1, SingleInstanceExampleView.Instances); - Assert.Same(instance, instance2); - } - }); + Assert.Same(instance, instance2); + } + } - [FactAttribute] - public async Task SingleInstanceViewsWithContractShouldResolveCorrectly() => - await RunAppBuilderTestAsync(() => + [Fact] + public void SingleInstanceViewsWithContractShouldResolveCorrectly() + { + using (_resolver.WithResolver()) { - using (_resolver.WithResolver()) - { - Assert.Equal(0, SingleInstanceWithContractExampleView.Instances); + Assert.Equal(0, SingleInstanceWithContractExampleView.Instances); - var instance = _resolver.GetService(typeof(IViewFor), "contract"); - Assert.Equal(1, SingleInstanceWithContractExampleView.Instances); + var instance = _resolver.GetService(typeof(IViewFor), "contract"); + Assert.Equal(1, SingleInstanceWithContractExampleView.Instances); - var instance2 = _resolver.GetService(typeof(IViewFor), "contract"); - Assert.Equal(1, SingleInstanceWithContractExampleView.Instances); + var instance2 = _resolver.GetService(typeof(IViewFor), "contract"); + Assert.Equal(1, SingleInstanceWithContractExampleView.Instances); - Assert.Same(instance, instance2); - } - }); + Assert.Same(instance, instance2); + } + } - [FactAttribute] - public async Task SingleInstanceViewsShouldOnlyBeInstantiatedWhenRequested() => - await RunAppBuilderTestAsync(() => + [Fact] + public void SingleInstanceViewsShouldOnlyBeInstantiatedWhenRequested() + { + using (_resolver.WithResolver()) { - using (_resolver.WithResolver()) - { - Assert.Equal(0, NeverUsedView.Instances); - } - }); + Assert.Equal(0, NeverUsedView.Instances); + } + } } diff --git a/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs b/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs deleted file mode 100644 index 907f35601a..0000000000 --- a/src/ReactiveUI.Tests/Platforms/wpf/ReactiveUIBuilderWpfTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using ReactiveUI.Builder; - -namespace ReactiveUI.Tests.Platforms.Wpf; - -/// -/// Tests for WPF-specific ReactiveUIBuilder functionality. -/// -public class ReactiveUIBuilderWpfTests : AppBuilderTestBase -{ - /// - /// Initializes a new instance of the class. - /// - public ReactiveUIBuilderWpfTests() - { - RxApp.EnsureInitialized(); - } - - /// - /// Test that WPF services can be registered using the builder. - /// - /// A representing the asynchronous operation. - [Fact] - public async Task WithWpf_Should_Register_Wpf_Services() => - await RunAppBuilderTestAsync(() => - { - // Arrange - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - - // Act - builder.WithWpf().Build(); - - // Assert - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - - var activationFetcher = locator.GetService(); - Assert.NotNull(activationFetcher); - }); - - /// - /// Test that the builder can chain WPF registration with core services. - /// - /// A representing the asynchronous operation. - [Fact] - public async Task WithCoreServices_AndWpf_Should_Register_All_Services() => - await RunAppBuilderTestAsync(() => - { - // Arrange - using var locator = new ModernDependencyResolver(); - var builder = locator.CreateReactiveUIBuilder(); - - // Act - builder.WithWpf().Build(); - - // Assert - // Core services - var observableProperty = locator.GetService(); - Assert.NotNull(observableProperty); - - // WPF-specific services - var platformOperations = locator.GetService(); - Assert.NotNull(platformOperations); - }); -} diff --git a/src/ReactiveUI.Tests/Platforms/wpf/WpfActivationForViewFetcherTest.cs b/src/ReactiveUI.Tests/Platforms/wpf/WpfActivationForViewFetcherTest.cs index d581524b36..2721e3380e 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/WpfActivationForViewFetcherTest.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/WpfActivationForViewFetcherTest.cs @@ -11,152 +11,132 @@ namespace ReactiveUI.Tests.Wpf; -public class WpfActivationForViewFetcherTest : AppBuilderTestBase +public class WpfActivationForViewFetcherTest { - /// - /// Ensures FrameworkElement is activated and then deactivated. - /// - /// A representing the asynchronous operation. [Fact] - public async Task FrameworkElementIsActivatedAndDeactivated() => - await RunAppBuilderTestAsync(() => - { - var uc = new WpfTestUserControl(); - var activation = new ActivationForViewFetcher(); + public void FrameworkElementIsActivatedAndDeactivated() + { + var uc = new WpfTestUserControl(); + var activation = new ActivationForViewFetcher(); - var obs = activation.GetActivationForView(uc); - obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + var obs = activation.GetActivationForView(uc); + obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; - uc.RaiseEvent(loaded); + uc.RaiseEvent(loaded); - new[] { true }.AssertAreEqual(activated); + new[] { true }.AssertAreEqual(activated); - var unloaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.UnloadedEvent - }; + var unloaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.UnloadedEvent + }; - uc.RaiseEvent(unloaded); + uc.RaiseEvent(unloaded); - new[] { true, false }.AssertAreEqual(activated); - }); + new[] { true, false }.AssertAreEqual(activated); + } - /// - /// Ensures IsHitTestVisible activates FrameworkElement correctly. - /// - /// A representing the asynchronous operation. [Fact] - public async Task IsHitTestVisibleActivatesFrameworkElement() => - await RunAppBuilderTestAsync(() => + public void IsHitTestVisibleActivatesFrameworkElement() + { + var uc = new WpfTestUserControl { - var uc = new WpfTestUserControl - { - IsHitTestVisible = false - }; - var activation = new ActivationForViewFetcher(); + IsHitTestVisible = false + }; + var activation = new ActivationForViewFetcher(); - var obs = activation.GetActivationForView(uc); - obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + var obs = activation.GetActivationForView(uc); + obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; - uc.RaiseEvent(loaded); + uc.RaiseEvent(loaded); - // Loaded has happened. - new[] { true }.AssertAreEqual(activated); + // Loaded has happened. + new[] { true }.AssertAreEqual(activated); - uc.IsHitTestVisible = true; + uc.IsHitTestVisible = true; - // IsHitTestVisible true, we don't want the event to repeat unnecessarily. - new[] { true }.AssertAreEqual(activated); + // IsHitTestVisible true, we don't want the event to repeat unnecessarily. + new[] { true }.AssertAreEqual(activated); - var unloaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.UnloadedEvent - }; + var unloaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.UnloadedEvent + }; - uc.RaiseEvent(unloaded); + uc.RaiseEvent(unloaded); - // We had both a loaded/hit test visible change/unloaded happen. - new[] { true, false }.AssertAreEqual(activated); - }); + // We had both a loaded/hit test visible change/unloaded happen. + new[] { true, false }.AssertAreEqual(activated); + } - /// - /// Ensures IsHitTestVisible deactivates FrameworkElement correctly. - /// - /// A representing the asynchronous operation. [Fact] - public async Task IsHitTestVisibleDeactivatesFrameworkElement() => - await RunAppBuilderTestAsync(() => - { - var uc = new WpfTestUserControl(); - var activation = new ActivationForViewFetcher(); + public void IsHitTestVisibleDeactivatesFrameworkElement() + { + var uc = new WpfTestUserControl(); + var activation = new ActivationForViewFetcher(); - var obs = activation.GetActivationForView(uc); - obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + var obs = activation.GetActivationForView(uc); + obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; - uc.RaiseEvent(loaded); + uc.RaiseEvent(loaded); - new[] { true }.AssertAreEqual(activated); + new[] { true }.AssertAreEqual(activated); - uc.IsHitTestVisible = false; + uc.IsHitTestVisible = false; - new[] { true, false }.AssertAreEqual(activated); - }); + new[] { true, false }.AssertAreEqual(activated); + } - /// - /// Ensures FrameworkElement activation and deactivation with hit test visibility changes. - /// - /// A representing the asynchronous operation. [Fact] - public async Task FrameworkElementIsActivatedAndDeactivatedWithHitTest() => - await RunAppBuilderTestAsync(() => - { - var uc = new WpfTestUserControl(); - var activation = new ActivationForViewFetcher(); + public void FrameworkElementIsActivatedAndDeactivatedWithHitTest() + { + var uc = new WpfTestUserControl(); + var activation = new ActivationForViewFetcher(); - var obs = activation.GetActivationForView(uc); - obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); + var obs = activation.GetActivationForView(uc); + obs.ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var activated).Subscribe(); - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; - uc.RaiseEvent(loaded); + uc.RaiseEvent(loaded); - new[] { true }.AssertAreEqual(activated); + new[] { true }.AssertAreEqual(activated); - // this should deactivate it - uc.IsHitTestVisible = false; + // this should deactivate it + uc.IsHitTestVisible = false; - new[] { true, false }.AssertAreEqual(activated); + new[] { true, false }.AssertAreEqual(activated); - // this should activate it - uc.IsHitTestVisible = true; + // this should activate it + uc.IsHitTestVisible = true; - new[] { true, false, true }.AssertAreEqual(activated); + new[] { true, false, true }.AssertAreEqual(activated); - var unloaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.UnloadedEvent - }; + var unloaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.UnloadedEvent + }; - uc.RaiseEvent(unloaded); + uc.RaiseEvent(unloaded); - new[] { true, false, true, false }.AssertAreEqual(activated); - }); + new[] { true, false, true, false }.AssertAreEqual(activated); + } } diff --git a/src/ReactiveUI.Tests/Platforms/wpf/WpfActiveContentTests.cs b/src/ReactiveUI.Tests/Platforms/wpf/WpfActiveContentTests.cs index ed9f632232..aa6261c9d1 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/WpfActiveContentTests.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/WpfActiveContentTests.cs @@ -5,6 +5,7 @@ using System.Windows; using DynamicData; +using ReactiveUI.Testing; namespace ReactiveUI.Tests.Wpf; @@ -17,7 +18,7 @@ namespace ReactiveUI.Tests.Wpf; /// Initializes a new instance of the class. /// /// The fixture. -public class WpfActiveContentTests(WpfActiveContentFixture fixture) : AppBuilderTestBase, IClassFixture +public class WpfActiveContentTests(WpfActiveContentFixture fixture) : IClassFixture { /// /// Gets the fixture. @@ -30,331 +31,313 @@ public class WpfActiveContentTests(WpfActiveContentFixture fixture) : AppBuilder [StaFact] public void BindListFunctionalTest() { - RunAppBuilderTestAsync(() => + var window = Fixture?.App?.WpfTestWindowFactory(); + var view = new MockBindListView(); + window!.RootGrid.Children.Add(view); + + var loaded = new RoutedEventArgs + { + RoutedEvent = FrameworkElement.LoadedEvent + }; + + window.RaiseEvent(loaded); + view.RaiseEvent(loaded); + var test1 = new MockBindListItemViewModel("Test1"); + view.ViewModel?.ActiveListItem.Add(test1); + Assert.Equal(1, view.ItemList.Items.Count); + Assert.Equal(test1, view.ViewModel!.ActiveItem); + + var test2 = new MockBindListItemViewModel("Test2"); + view.ViewModel?.ActiveListItem.Add(test2); + Assert.Equal(2, view.ItemList.Items.Count); + Assert.Equal(test2, view.ViewModel!.ActiveItem); + + var test3 = new MockBindListItemViewModel("Test3"); + view.ViewModel?.ActiveListItem.Add(test3); + Assert.Equal(3, view.ItemList.Items.Count); + Assert.Equal(test3, view.ViewModel!.ActiveItem); + + view.ItemList.SelectedItem = view.ItemList.Items.GetItemAt(0); + Assert.Equal(1, view.ItemList.Items.Count); + Assert.Equal(test1, view.ViewModel!.ActiveItem); + + window.Close(); + } + + [StaFact] + public void ViewModelHostViewTestFallback() + { + var oldLocator = Locator.GetLocator(); + + var resolver = new ModernDependencyResolver(); + resolver.InitializeSplat(); + resolver.InitializeReactiveUI(); + + // test the resolving behavior + using (resolver.WithResolver()) + { + ResolveViewBIfViewBIsRegistered(resolver); + ResolveView0WithFallbck(resolver); + ResolveNoneWithFallbckByPass(resolver); + } + + void ResolveViewBIfViewBIsRegistered(ModernDependencyResolver resolver) { + resolver.Register(() => new FakeViewWithContract.View0(), typeof(IViewFor)); + resolver.Register(() => new FakeViewWithContract.ViewA(), typeof(IViewFor), FakeViewWithContract.ContractA); + resolver.Register(() => new FakeViewWithContract.ViewB(), typeof(IViewFor), FakeViewWithContract.ContractB); + var window = Fixture?.App?.WpfTestWindowFactory(); - var view = new MockBindListView(); - window!.RootGrid.Children.Add(view); + + var viewmodel = new FakeViewWithContract.MyViewModel(); + var vmvhost = new ViewModelViewHost() + { + ViewModel = viewmodel, + ViewContract = FakeViewWithContract.ContractB, + }; + window!.RootGrid.Children.Clear(); + window!.RootGrid.Children.Add(vmvhost); var loaded = new RoutedEventArgs { RoutedEvent = FrameworkElement.LoadedEvent }; - window.RaiseEvent(loaded); - view.RaiseEvent(loaded); - var test1 = new MockBindListItemViewModel("Test1"); - view.ViewModel?.ActiveListItem.Add(test1); - Assert.Equal(1, view.ItemList.Items.Count); - Assert.Equal(test1, view.ViewModel!.ActiveItem); - - var test2 = new MockBindListItemViewModel("Test2"); - view.ViewModel?.ActiveListItem.Add(test2); - Assert.Equal(2, view.ItemList.Items.Count); - Assert.Equal(test2, view.ViewModel!.ActiveItem); - - var test3 = new MockBindListItemViewModel("Test3"); - view.ViewModel?.ActiveListItem.Add(test3); - Assert.Equal(3, view.ItemList.Items.Count); - Assert.Equal(test3, view.ViewModel!.ActiveItem); - - view.ItemList.SelectedItem = view.ItemList.Items.GetItemAt(0); - Assert.Equal(1, view.ItemList.Items.Count); - Assert.Equal(test1, view.ViewModel!.ActiveItem); + vmvhost.RaiseEvent(loaded); + Assert.NotNull(vmvhost.Content); + Assert.IsType(typeof(FakeViewWithContract.ViewB), vmvhost.Content); window.Close(); - }).GetAwaiter().GetResult(); - } + } - [StaFact] - public void ViewModelHostViewTestFallback() - { - RunAppBuilderTestAsync(() => + void ResolveView0WithFallbck(ModernDependencyResolver resolver) { - var oldLocator = Locator.GetLocator(); + resolver.UnregisterCurrent(typeof(IViewFor), FakeViewWithContract.ContractB); - var resolver = new ModernDependencyResolver(); - resolver.InitializeSplat(); - resolver.InitializeReactiveUI(); + var window = Fixture?.App?.WpfTestWindowFactory(); - // test the resolving behavior - using (resolver.WithResolver()) + var viewmodel = new FakeViewWithContract.MyViewModel(); + var vmvhost = new ViewModelViewHost() { - ResolveViewBIfViewBIsRegistered(resolver); - ResolveView0WithFallbck(resolver); - ResolveNoneWithFallbckByPass(resolver); - } + ViewModel = viewmodel, + ViewContract = FakeViewWithContract.ContractB, + ContractFallbackByPass = false, + }; + window!.RootGrid.Children.Clear(); + window!.RootGrid.Children.Add(vmvhost); - void ResolveViewBIfViewBIsRegistered(ModernDependencyResolver resolver) + var loaded = new RoutedEventArgs { - resolver.Register(() => new FakeViewWithContract.View0(), typeof(IViewFor)); - resolver.Register(() => new FakeViewWithContract.ViewA(), typeof(IViewFor), FakeViewWithContract.ContractA); - resolver.Register(() => new FakeViewWithContract.ViewB(), typeof(IViewFor), FakeViewWithContract.ContractB); + RoutedEvent = FrameworkElement.LoadedEvent + }; + window.RaiseEvent(loaded); + vmvhost.RaiseEvent(loaded); - var window = Fixture?.App?.WpfTestWindowFactory(); + Assert.NotNull(vmvhost.Content); + Assert.IsType(typeof(FakeViewWithContract.View0), vmvhost.Content); + window.Close(); + } - var viewmodel = new FakeViewWithContract.MyViewModel(); - var vmvhost = new ViewModelViewHost() - { - ViewModel = viewmodel, - ViewContract = FakeViewWithContract.ContractB, - }; - window!.RootGrid.Children.Clear(); - window!.RootGrid.Children.Add(vmvhost); + void ResolveNoneWithFallbckByPass(ModernDependencyResolver resolver) + { + resolver.UnregisterCurrent(typeof(IViewFor), FakeViewWithContract.ContractB); - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; - window.RaiseEvent(loaded); - vmvhost.RaiseEvent(loaded); - - Assert.NotNull(vmvhost.Content); - Assert.IsType(typeof(FakeViewWithContract.ViewB), vmvhost.Content); - window.Close(); - } + var window = Fixture?.App?.WpfTestWindowFactory(); - void ResolveView0WithFallbck(ModernDependencyResolver resolver) + var viewmodel = new FakeViewWithContract.MyViewModel(); + var vmvhost = new ViewModelViewHost() { - resolver.UnregisterCurrent(typeof(IViewFor), FakeViewWithContract.ContractB); - - var window = Fixture?.App?.WpfTestWindowFactory(); - - var viewmodel = new FakeViewWithContract.MyViewModel(); - var vmvhost = new ViewModelViewHost() - { - ViewModel = viewmodel, - ViewContract = FakeViewWithContract.ContractB, - ContractFallbackByPass = false, - }; - window!.RootGrid.Children.Clear(); - window!.RootGrid.Children.Add(vmvhost); - - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; - window.RaiseEvent(loaded); - vmvhost.RaiseEvent(loaded); - - Assert.NotNull(vmvhost.Content); - Assert.IsType(typeof(FakeViewWithContract.View0), vmvhost.Content); - window.Close(); - } + ViewModel = viewmodel, + ViewContract = FakeViewWithContract.ContractB, + ContractFallbackByPass = true, + }; + window!.RootGrid.Children.Clear(); + window!.RootGrid.Children.Add(vmvhost); - void ResolveNoneWithFallbckByPass(ModernDependencyResolver resolver) + var loaded = new RoutedEventArgs { - resolver.UnregisterCurrent(typeof(IViewFor), FakeViewWithContract.ContractB); - - var window = Fixture?.App?.WpfTestWindowFactory(); - - var viewmodel = new FakeViewWithContract.MyViewModel(); - var vmvhost = new ViewModelViewHost() - { - ViewModel = viewmodel, - ViewContract = FakeViewWithContract.ContractB, - ContractFallbackByPass = true, - }; - window!.RootGrid.Children.Clear(); - window!.RootGrid.Children.Add(vmvhost); - - var loaded = new RoutedEventArgs - { - RoutedEvent = FrameworkElement.LoadedEvent - }; - window.RaiseEvent(loaded); - vmvhost.RaiseEvent(loaded); + RoutedEvent = FrameworkElement.LoadedEvent + }; + window.RaiseEvent(loaded); + vmvhost.RaiseEvent(loaded); - Assert.Null(vmvhost.Content); - window.Close(); - } - }).GetAwaiter().GetResult(); + Assert.Null(vmvhost.Content); + window.Close(); + } } [StaFact] public void TransitioningContentControlTest() { - RunAppBuilderTestAsync(() => + var window = Fixture?.App?.MockWindowFactory(); + window!.WhenActivated(async _ => { - var window = Fixture?.App?.MockWindowFactory(); - window!.WhenActivated(async _ => + window!.TransitioningContent.Duration = TimeSpan.FromMilliseconds(200); + var transitioning = false; + window.TransitioningContent.TransitionStarted += (s, e) => transitioning = true; + + window.TransitioningContent.TransitionCompleted += (s, e) => transitioning = false; + + await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); + await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); + + async Task TestTransiton() { - window!.TransitioningContent.Duration = TimeSpan.FromMilliseconds(200); - var transitioning = false; - window.TransitioningContent.TransitionStarted += (s, e) => transitioning = true; - - window.TransitioningContent.TransitionCompleted += (s, e) => transitioning = false; - - await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Bounce).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Drop).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Fade).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Move).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Down, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Left, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Right, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); - await TestCyle(TransitioningContentControl.TransitionDirection.Up, TransitioningContentControl.TransitionType.Slide).ConfigureAwait(true); - - async Task TestTransiton() + var view = new View1(); + window.TransitioningContent.Content = view; + Assert.True(transitioning); + while (transitioning) { - var view = new View1(); - window.TransitioningContent.Content = view; - Assert.True(transitioning); - while (transitioning) - { - await Task.Delay(5).ConfigureAwait(true); - } - - Assert.Equal(window.TransitioningContent.Content, view); - Assert.False(transitioning); - - var view2 = new View2(); - window.TransitioningContent.Content = view2; - Assert.True(transitioning); - while (transitioning) - { - await Task.Delay(5).ConfigureAwait(true); - } - - Assert.Equal(window.TransitioningContent.Content, view2); - Assert.False(transitioning); + await Task.Delay(5).ConfigureAwait(true); } - async Task TestCyle(TransitioningContentControl.TransitionDirection direction, TransitioningContentControl.TransitionType transition) + Assert.Equal(window.TransitioningContent.Content, view); + Assert.False(transitioning); + + var view2 = new View2(); + window.TransitioningContent.Content = view2; + Assert.True(transitioning); + while (transitioning) { - window.TransitioningContent.Direction = direction; - window.TransitioningContent.Transition = transition; - Assert.Equal(window.TransitioningContent.Direction, direction); - Assert.Equal(window.TransitioningContent.Transition, transition); - await TestTransiton().ConfigureAwait(true); - await TestTransiton().ConfigureAwait(true); + await Task.Delay(5).ConfigureAwait(true); } - window.Close(); - }); - window!.ShowDialog(); - }).GetAwaiter().GetResult(); + Assert.Equal(window.TransitioningContent.Content, view2); + Assert.False(transitioning); + } + + async Task TestCyle(TransitioningContentControl.TransitionDirection direction, TransitioningContentControl.TransitionType transition) + { + window.TransitioningContent.Direction = direction; + window.TransitioningContent.Transition = transition; + Assert.Equal(window.TransitioningContent.Direction, direction); + Assert.Equal(window.TransitioningContent.Transition, transition); + await TestTransiton().ConfigureAwait(true); + await TestTransiton().ConfigureAwait(true); + } + + window.Close(); + }); + window!.ShowDialog(); } [Fact] public void DummySuspensionDriverTest() { - RunAppBuilderTestAsync(() => - { - var dsd = new DummySuspensionDriver(); - dsd.LoadState().Select(_ => 1).Subscribe(_ => Assert.Equal(1, _)); - dsd.SaveState("Save Me").Select(_ => 2).Subscribe(_ => Assert.Equal(2, _)); - dsd.InvalidateState().Select(_ => 3).Subscribe(_ => Assert.Equal(3, _)); - }).GetAwaiter().GetResult(); + var dsd = new DummySuspensionDriver(); + dsd.LoadState().Select(_ => 1).Subscribe(_ => Assert.Equal(1, _)); + dsd.SaveState("Save Me").Select(_ => 2).Subscribe(_ => Assert.Equal(2, _)); + dsd.InvalidateState().Select(_ => 3).Subscribe(_ => Assert.Equal(3, _)); } [StaFact] public void TransitioninContentControlDpiTest() { - RunAppBuilderTestAsync(() => - { - var window = Fixture?.App?.TCMockWindowFactory(); - const int delay = 2000; + var window = Fixture?.App?.TCMockWindowFactory(); + const int delay = 2000; - window!.WhenActivated(async _ => - { - TransitioningContentControl.OverrideDpi = true; - window!.TransitioningContent.Height = 500; - window.TransitioningContent.Width = 500; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Height = 300; - window.TransitioningContent.Width = 300; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - window.TransitioningContent.Height = 0.25; - window.TransitioningContent.Width = 0.25; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - window.TransitioningContent.Height = 500; - window.TransitioningContent.Width = 500; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Height = 300; - window.TransitioningContent.Width = 300; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - window.TransitioningContent.Height = 0.25; - window.TransitioningContent.Width = 0.25; - window.TransitioningContent.Content = new FirstView(); - await Task.Delay(delay).ConfigureAwait(true); - window.TransitioningContent.Content = new SecondView(); - window.Close(); - }); - window!.ShowDialog(); - }).GetAwaiter().GetResult(); + window!.WhenActivated(async _ => + { + TransitioningContentControl.OverrideDpi = true; + window!.TransitioningContent.Height = 500; + window.TransitioningContent.Width = 500; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Height = 300; + window.TransitioningContent.Width = 300; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + window.TransitioningContent.Height = 0.25; + window.TransitioningContent.Width = 0.25; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + window.TransitioningContent.Height = 500; + window.TransitioningContent.Width = 500; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Height = 300; + window.TransitioningContent.Width = 300; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + window.TransitioningContent.Height = 0.25; + window.TransitioningContent.Width = 0.25; + window.TransitioningContent.Content = new FirstView(); + await Task.Delay(delay).ConfigureAwait(true); + window.TransitioningContent.Content = new SecondView(); + window.Close(); + }); + window!.ShowDialog(); } [StaFact] public void ReactiveCommandRunningOnTaskThreadAllowsCanExecuteAndExecutingToFire() { - RunAppBuilderTestAsync(() => + LiveModeDetector.UseRuntimeThreads(); + var window = Fixture?.App?.MockWindowFactory(); + window!.WhenActivated(async d => { - LiveModeDetector.UseRuntimeThreads(); - var window = Fixture?.App?.MockWindowFactory(); - window!.WhenActivated(async d => + try { - try + using var testSequencer = new TestSequencer(); + window!.TransitioningContent.VerticalContentAlignment = VerticalAlignment.Stretch; + window!.TransitioningContent.HorizontalContentAlignment = HorizontalAlignment.Stretch; + var view = new CanExecuteExecutingView(); + window!.TransitioningContent.Content = view; + await Task.Delay(2000).ConfigureAwait(true); + + var isExecutingExecuted = false; + view!.ViewModel!.Command3.IsExecuting + .ObserveOn(RxApp.MainThreadScheduler) + .Subscribe(value => { - using var testSequencer = new TestSequencer(); - window!.TransitioningContent.VerticalContentAlignment = VerticalAlignment.Stretch; - window!.TransitioningContent.HorizontalContentAlignment = HorizontalAlignment.Stretch; - var view = new CanExecuteExecutingView(); - window!.TransitioningContent.Content = view; - await Task.Delay(2000).ConfigureAwait(true); - - var isExecutingExecuted = false; - view!.ViewModel!.Command3.IsExecuting - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(value => - { - if (value) - { - isExecutingExecuted = true; - } - }).DisposeWith(d); - - int? result = null; - view!.ViewModel!.Command3.Subscribe(async r => + if (value) { - result = r; - await testSequencer.AdvancePhaseAsync(); - }); - await view!.ViewModel!.Command3.Execute(); - await testSequencer.AdvancePhaseAsync(); - Assert.Equal(100, result); - Assert.True(isExecutingExecuted); - } - finally + isExecutingExecuted = true; + } + }).DisposeWith(d); + + int? result = null; + view!.ViewModel!.Command3.Subscribe(async r => { - window?.Close(); - LiveModeDetector.UseDefaultModeDetector(); - } - }); - window!.ShowDialog(); - }).GetAwaiter().GetResult(); + result = r; + await testSequencer.AdvancePhaseAsync(); + }); + await view!.ViewModel!.Command3.Execute(); + await testSequencer.AdvancePhaseAsync(); + Assert.Equal(100, result); + Assert.True(isExecutingExecuted); + } + finally + { + window?.Close(); + LiveModeDetector.UseDefaultModeDetector(); + } + }); + window!.ShowDialog(); } } diff --git a/src/ReactiveUI.Tests/Platforms/wpf/WpfCommandBindingImplementationTests.cs b/src/ReactiveUI.Tests/Platforms/wpf/WpfCommandBindingImplementationTests.cs index 49639725d6..98167d02f9 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/WpfCommandBindingImplementationTests.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/WpfCommandBindingImplementationTests.cs @@ -14,280 +14,270 @@ namespace ReactiveUI.Tests.Wpf; -public class WpfCommandBindingImplementationTests : AppBuilderTestBase +public class WpfCommandBindingImplementationTests { /// /// Commands the bind to explicit event wireup. /// - [FactAttribute] - public async Task CommandBindToExplicitEventWireup() => - await RunAppBuilderTestAsync(() => - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; + [Fact] + public void CommandBindToExplicitEventWireup() + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); - var disp = view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); + var disp = view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - disp.Dispose(); + disp.Dispose(); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(1, invokeCount); - }); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(1, invokeCount); + } /// /// Binds the command to object target is null. /// - [FactAttribute] - public async Task BindCommandToObjectWithEventTargetIsNull() => - await RunAppBuilderTestAsync(() => - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; + [Fact] + public void BindCommandToObjectWithEventTargetIsNull() + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); - var sub = new Subject(); - Assert.Throws(() => - { - var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, true, sub, "MouseUp"); - - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + var sub = new Subject(); + Assert.Throws(() => + { + var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, true, sub, "MouseUp"); - disp.Dispose(); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - }); + disp.Dispose(); - Assert.Equal(0, invokeCount); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); }); + Assert.Equal(0, invokeCount); + } + /// /// Binds the command to object target is null. /// - [FactAttribute] - public async Task BindCommandToObjectTargetIsNull() => - await RunAppBuilderTestAsync(() => - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; - - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); + [Fact] + public void BindCommandToObjectTargetIsNull() + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; - var sub = new Subject(); - Assert.Throws(() => - { - var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, true, sub); + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + var sub = new Subject(); + Assert.Throws(() => + { + var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, true, sub); - disp.Dispose(); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - }); + disp.Dispose(); - Assert.Equal(0, invokeCount); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); }); + Assert.Equal(0, invokeCount); + } + /// /// Binds the command to object target is null. /// - [FactAttribute] - public async Task BindCommandToObjectEventIsNull() => - await RunAppBuilderTestAsync(() => - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; + [Fact] + public void BindCommandToObjectEventIsNull() + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); - var sub = new Subject(); - Assert.Throws(() => - { - var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, vm, sub, "HappyMouseEvent"); - - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + var sub = new Subject(); + Assert.Throws(() => + { + var disp = CreatesCommandBinding.BindCommandToObject(vm.Command2, vm, sub, "HappyMouseEvent"); - disp.Dispose(); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - }); + disp.Dispose(); - Assert.Equal(0, invokeCount); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); }); + Assert.Equal(0, invokeCount); + } + /// /// Binds the command to object command is null. /// - [FactAttribute] - public async Task BindCommandToObjectWithEventCommandIsArgumentNull() => - await RunAppBuilderTestAsync(() => + [Fact] + public void BindCommandToObjectWithEventCommandIsArgumentNull() + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; + + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); + var btn = new Button(); + var cmd = (btn as ICommand)!; + var sub = new Subject(); + Assert.Throws(() => { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; - - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); - var btn = new Button(); - var cmd = (btn as ICommand)!; - var sub = new Subject(); - Assert.Throws(() => - { - var disp = CreatesCommandBinding.BindCommandToObject(cmd, view, sub, "PropertyChanged"); - - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + var disp = CreatesCommandBinding.BindCommandToObject(cmd, view, sub, "PropertyChanged"); - disp.Dispose(); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - }); + disp.Dispose(); - Assert.Equal(0, invokeCount); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); }); + Assert.Equal(0, invokeCount); + } + /// /// Binds the command to object command is null. /// - [FactAttribute] - public async Task BindCommandToObjectCommandIsArgumentNull() => - await RunAppBuilderTestAsync(() => + [Fact] + public void BindCommandToObjectCommandIsArgumentNull() + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; + + var invokeCount = 0; + vm.Command2.Subscribe(_ => invokeCount++); + var btn = new Button(); + var cmd = (btn as ICommand)!; + var sub = new Subject(); + Assert.Throws(() => { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; - - var invokeCount = 0; - vm.Command2.Subscribe(_ => invokeCount++); - var btn = new Button(); - var cmd = (btn as ICommand)!; - var sub = new Subject(); - Assert.Throws(() => - { - var disp = CreatesCommandBinding.BindCommandToObject(cmd, view, sub); - - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + var disp = CreatesCommandBinding.BindCommandToObject(cmd, view, sub); - disp.Dispose(); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - }); + disp.Dispose(); - Assert.Equal(0, invokeCount); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); }); + Assert.Equal(0, invokeCount); + } + /// /// Commands the bind view model to view with observable. /// - [FactAttribute] - public async Task CommandBindViewModelToViewWithObservable() => - await RunAppBuilderTestAsync(() => - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; - - // Create a paramenter feed - vm.Command2.Subscribe(_ => vm.Value++); - view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); - - // Bind the command and the IObservable parameter. - var fixture = new CommandBinderImplementation().BindCommand(vm, view, vm => vm.Command1, v => v.Command3, vm.WhenAnyValue(vm => vm.Value), "MouseUp"); - Assert.Equal(0, vm.Value); - - // Confirm that the values update as expected. - var parameter = 0; - vm.Command1.Subscribe(i => parameter = i); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(1, vm.Value); - Assert.Equal(0, parameter); - - view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(1, parameter); - - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(2, vm.Value); - Assert.Equal(1, parameter); - - view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(2, parameter); - Assert.Equal(2, vm.Value); - }); + [Fact] + public void CommandBindViewModelToViewWithObservable() + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; + + // Create a paramenter feed + vm.Command2.Subscribe(_ => vm.Value++); + view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); + + // Bind the command and the IObservable parameter. + var fixture = new CommandBinderImplementation().BindCommand(vm, view, vm => vm.Command1, v => v.Command3, vm.WhenAnyValue(vm => vm.Value), "MouseUp"); + Assert.Equal(0, vm.Value); + + // Confirm that the values update as expected. + var parameter = 0; + vm.Command1.Subscribe(i => parameter = i); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(1, vm.Value); + Assert.Equal(0, parameter); + + view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(1, parameter); + + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(2, vm.Value); + Assert.Equal(1, parameter); + + view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(2, parameter); + Assert.Equal(2, vm.Value); + } /// /// Commands the bind view model to view with function. /// - [FactAttribute] - public async Task CommandBindViewModelToViewWithFunc() => - await RunAppBuilderTestAsync(() => + [Fact] + public void CommandBindViewModelToViewWithFunc() + { + var vm = new CommandBindingViewModel(); + var view = new CommandBindingView { ViewModel = vm }; + + // Create a paramenter feed + vm.Command2.Subscribe(_ => vm.Value++); + view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); + + // Bind the command and the Func parameter. + var fixture = new CommandBinderImplementation().BindCommand(vm, view, vm => vm.Command1, v => v.Command3, vm => vm.Value, "MouseUp"); + Assert.Equal(0, vm.Value); + + // Confirm that the values update as expected. + var parameter = 0; + vm.Command1.Subscribe(i => parameter = i); + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(1, vm.Value); + Assert.Equal(0, parameter); + + view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(1, parameter); + + view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(2, vm.Value); + Assert.Equal(1, parameter); + + view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); + Assert.Equal(2, parameter); + Assert.Equal(2, vm.Value); + } + + [Fact] + public void BindCommandShouldNotWarnWhenBindingToFieldDeclaredInXaml() + { + var testLogger = new TestLogger(); + Locator.CurrentMutable.RegisterConstant(testLogger); + + var vm = new CommandBindingViewModel(); + var view = new FakeXamlCommandBindingView { ViewModel = vm }; + + testLogger.Messages.Should().NotContain(t => t.message.Contains(nameof(POCOObservableForProperty)) && t.message.Contains(view.NameOfButtonDeclaredInXaml) && t.logLevel == LogLevel.Warn); + } + + [Fact] + public void ViewModelShouldBeGarbageCollectedWhenOverwritten() + { + static (IDisposable, WeakReference) GetWeakReference() { var vm = new CommandBindingViewModel(); var view = new CommandBindingView { ViewModel = vm }; + var weakRef = new WeakReference(vm); + var disp = view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); + view.ViewModel = new CommandBindingViewModel(); - // Create a paramenter feed - vm.Command2.Subscribe(_ => vm.Value++); - view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); - - // Bind the command and the Func parameter. - var fixture = new CommandBinderImplementation().BindCommand(vm, view, vm => vm.Command1, v => v.Command3, vm => vm.Value, "MouseUp"); - Assert.Equal(0, vm.Value); - - // Confirm that the values update as expected. - var parameter = 0; - vm.Command1.Subscribe(i => parameter = i); - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(1, vm.Value); - Assert.Equal(0, parameter); - - view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(1, parameter); - - view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(2, vm.Value); - Assert.Equal(1, parameter); - - view.Command3.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent }); - Assert.Equal(2, parameter); - Assert.Equal(2, vm.Value); - }); - - [FactAttribute] - public async Task BindCommandShouldNotWarnWhenBindingToFieldDeclaredInXaml() => - await RunAppBuilderTestAsync(() => - { - var testLogger = new TestLogger(); - Locator.CurrentMutable.RegisterConstant(testLogger); - - var vm = new CommandBindingViewModel(); - var view = new FakeXamlCommandBindingView { ViewModel = vm }; - - testLogger.Messages.Should().NotContain(t => t.message.Contains(nameof(POCOObservableForProperty)) && t.message.Contains(view.NameOfButtonDeclaredInXaml) && t.logLevel == LogLevel.Warn); - }); - - [FactAttribute] - public async Task ViewModelShouldBeGarbageCollectedWhenOverwritten() => - await RunAppBuilderTestAsync(() => - { - static (IDisposable, WeakReference) GetWeakReference() - { - var vm = new CommandBindingViewModel(); - var view = new CommandBindingView { ViewModel = vm }; - var weakRef = new WeakReference(vm); - var disp = view.BindCommand(vm, x => x.Command2, x => x.Command2, "MouseUp"); - view.ViewModel = new CommandBindingViewModel(); - - return (disp, weakRef); - } + return (disp, weakRef); + } - var (disp, weakRef) = GetWeakReference(); + var (disp, weakRef) = GetWeakReference(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + GC.Collect(); + GC.WaitForPendingFinalizers(); - Assert.False(weakRef.IsAlive); - }); + Assert.False(weakRef.IsAlive); + } } diff --git a/src/ReactiveUI.Tests/Platforms/wpf/WpfViewDependencyResolverTests.cs b/src/ReactiveUI.Tests/Platforms/wpf/WpfViewDependencyResolverTests.cs index d9e5c3fa58..29718d98ed 100644 --- a/src/ReactiveUI.Tests/Platforms/wpf/WpfViewDependencyResolverTests.cs +++ b/src/ReactiveUI.Tests/Platforms/wpf/WpfViewDependencyResolverTests.cs @@ -11,7 +11,7 @@ namespace ReactiveUI.Tests.Wpf; /// Tests for the WPF View Resolver. /// /// -public sealed class WpfViewDependencyResolverTests : AppBuilderTestBase, IDisposable +public sealed class WpfViewDependencyResolverTests : IDisposable { private readonly IDependencyResolver _resolver; @@ -29,15 +29,14 @@ public WpfViewDependencyResolverTests() /// /// Tests that Register views for view model should register all views. /// - [FactAttribute] - public async Task RegisterViewsForViewModelShouldRegisterAllViews() => - await RunAppBuilderTestAsync(() => + [Fact] + public void RegisterViewsForViewModelShouldRegisterAllViews() + { + using (_resolver.WithResolver()) { - using (_resolver.WithResolver()) - { - Assert.Single(_resolver.GetServices>()); - } - }); + Assert.Single(_resolver.GetServices>()); + } + } /// public void Dispose() => _resolver?.Dispose(); diff --git a/src/ReactiveUI.Tests/ReactiveObject/ReactiveObjectTests.cs b/src/ReactiveUI.Tests/ReactiveObject/ReactiveObjectTests.cs index 0dc733ce61..825295fad8 100644 --- a/src/ReactiveUI.Tests/ReactiveObject/ReactiveObjectTests.cs +++ b/src/ReactiveUI.Tests/ReactiveObject/ReactiveObjectTests.cs @@ -12,7 +12,7 @@ namespace ReactiveUI.Tests; /// /// Tests for the reactive object. /// -public class ReactiveObjectTests : AppBuilderTestBase +public class ReactiveObjectTests { /// /// Test that changing values should always arrive before changed. diff --git a/src/ReactiveUI.Tests/ReactiveProperty/ReactivePropertyTest.cs b/src/ReactiveUI.Tests/ReactiveProperty/ReactivePropertyTest.cs index 13006bab93..7fb92d8cad 100644 --- a/src/ReactiveUI.Tests/ReactiveProperty/ReactivePropertyTest.cs +++ b/src/ReactiveUI.Tests/ReactiveProperty/ReactivePropertyTest.cs @@ -6,11 +6,12 @@ using System.Collections; using FluentAssertions; using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; using ReactiveUI.Tests.ReactiveProperty.Mocks; namespace ReactiveUI.Tests.ReactiveProperty; -public class ReactivePropertyTest : AppBuilderTestBase +public class ReactivePropertyTest : ReactiveTest { [Fact] public void DefaultValueIsRaisedOnSubscribe() diff --git a/src/ReactiveUI.Tests/Resolvers/DependencyResolverTests.cs b/src/ReactiveUI.Tests/Resolvers/DependencyResolverTests.cs index f472aa82e7..dd80df12a8 100644 --- a/src/ReactiveUI.Tests/Resolvers/DependencyResolverTests.cs +++ b/src/ReactiveUI.Tests/Resolvers/DependencyResolverTests.cs @@ -7,7 +7,7 @@ namespace ReactiveUI.Tests; -public sealed class DependencyResolverTests : AppBuilderTestBase +public sealed class DependencyResolverTests { /// /// Gets RegistrationNamespaces. diff --git a/src/ReactiveUI.Tests/Resolvers/INPCObservableForPropertyTests.cs b/src/ReactiveUI.Tests/Resolvers/INPCObservableForPropertyTests.cs index d363a1098b..dd7664f87f 100644 --- a/src/ReactiveUI.Tests/Resolvers/INPCObservableForPropertyTests.cs +++ b/src/ReactiveUI.Tests/Resolvers/INPCObservableForPropertyTests.cs @@ -7,7 +7,7 @@ namespace ReactiveUI.Tests; -public class INPCObservableForPropertyTests : AppBuilderTestBase +public class INPCObservableForPropertyTests { [Fact] public void CheckGetAffinityForObjectValues() diff --git a/src/ReactiveUI.Tests/Resolvers/PocoObservableForPropertyTests.cs b/src/ReactiveUI.Tests/Resolvers/PocoObservableForPropertyTests.cs index 7a2c1f5aae..282df06d1c 100644 --- a/src/ReactiveUI.Tests/Resolvers/PocoObservableForPropertyTests.cs +++ b/src/ReactiveUI.Tests/Resolvers/PocoObservableForPropertyTests.cs @@ -5,7 +5,7 @@ namespace ReactiveUI.Tests; -public class PocoObservableForPropertyTests : AppBuilderTestBase +public class PocoObservableForPropertyTests { #pragma warning disable CA1812 // Class is not instantiated diff --git a/src/ReactiveUI.Tests/Routing/RoutableViewModelMixinTests.cs b/src/ReactiveUI.Tests/Routing/RoutableViewModelMixinTests.cs index 8208619300..4abe7940fa 100644 --- a/src/ReactiveUI.Tests/Routing/RoutableViewModelMixinTests.cs +++ b/src/ReactiveUI.Tests/Routing/RoutableViewModelMixinTests.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Routable ViewModel MixinTests. /// -public class RoutableViewModelMixinTests : AppBuilderTestBase +public class RoutableViewModelMixinTests { /// /// Whens the navigated to calls on navigated to when view model is first added. diff --git a/src/ReactiveUI.Tests/Routing/RoutedViewHostTests.cs b/src/ReactiveUI.Tests/Routing/RoutedViewHostTests.cs index 012fd2a97e..c5e611aa6e 100644 --- a/src/ReactiveUI.Tests/Routing/RoutedViewHostTests.cs +++ b/src/ReactiveUI.Tests/Routing/RoutedViewHostTests.cs @@ -11,7 +11,7 @@ namespace ReactiveUI.Tests; -public class RoutedViewHostTests : AppBuilderTestBase +public class RoutedViewHostTests { [StaFact] public void RoutedViewHostDefaultContentNotNull() diff --git a/src/ReactiveUI.Tests/Routing/RoutingStateTests.cs b/src/ReactiveUI.Tests/Routing/RoutingStateTests.cs index 0b22d52d4d..0e4187cb01 100644 --- a/src/ReactiveUI.Tests/Routing/RoutingStateTests.cs +++ b/src/ReactiveUI.Tests/Routing/RoutingStateTests.cs @@ -7,9 +7,11 @@ using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; + namespace ReactiveUI.Tests; -public class RoutingStateTests : AppBuilderTestBase +public class RoutingStateTests { /// /// Navigations the push pop test. diff --git a/src/ReactiveUI.Tests/Routing/ViewModelViewHostTests.cs b/src/ReactiveUI.Tests/Routing/ViewModelViewHostTests.cs index fc02bc8857..c988918ff9 100644 --- a/src/ReactiveUI.Tests/Routing/ViewModelViewHostTests.cs +++ b/src/ReactiveUI.Tests/Routing/ViewModelViewHostTests.cs @@ -11,7 +11,7 @@ namespace ReactiveUI.Tests; -public class ViewModelViewHostTests : AppBuilderTestBase +public class ViewModelViewHostTests { [StaFact] public void ViewModelViewHostDefaultContentNotNull() diff --git a/src/ReactiveUI.Tests/RxAppTest.cs b/src/ReactiveUI.Tests/RxAppTest.cs index f13a5e47b1..3592dc66cb 100644 --- a/src/ReactiveUI.Tests/RxAppTest.cs +++ b/src/ReactiveUI.Tests/RxAppTest.cs @@ -10,18 +10,15 @@ namespace ReactiveUI.Tests; /// /// Tests the RxApp class. /// -public class RxAppTest : AppBuilderTestBase +public class RxAppTest { /// /// Tests that schedulers should be current thread in test runner. /// - /// A representing the asynchronous operation. [Fact] - public async Task SchedulerShouldBeCurrentThreadInTestRunner() => - await RunAppBuilderTestAsync(() => - { - RxApp.MainThreadScheduler = CurrentThreadScheduler.Instance; - Debug.WriteLine(RxApp.MainThreadScheduler.GetType().FullName); - Assert.Equal(CurrentThreadScheduler.Instance, RxApp.MainThreadScheduler); - }); + public void SchedulerShouldBeCurrentThreadInTestRunner() + { + Debug.WriteLine(RxApp.MainThreadScheduler.GetType().FullName); + Assert.Equal(CurrentThreadScheduler.Instance, RxApp.MainThreadScheduler); + } } diff --git a/src/ReactiveUI.Tests/Suspension/SuspensionHostExtensionsTests.cs b/src/ReactiveUI.Tests/Suspension/SuspensionHostExtensionsTests.cs index dc1135dae6..e8a4e1f732 100644 --- a/src/ReactiveUI.Tests/Suspension/SuspensionHostExtensionsTests.cs +++ b/src/ReactiveUI.Tests/Suspension/SuspensionHostExtensionsTests.cs @@ -7,7 +7,7 @@ namespace ReactiveUI.Tests.Suspension; -public class SuspensionHostExtensionsTests : AppBuilderTestBase +public class SuspensionHostExtensionsTests { [Fact] public void GetAppStateReturns() diff --git a/src/ReactiveUI.Tests/Properties/TestConfiguration.cs b/src/ReactiveUI.Tests/TestConfiguration.cs similarity index 100% rename from src/ReactiveUI.Tests/Properties/TestConfiguration.cs rename to src/ReactiveUI.Tests/TestConfiguration.cs diff --git a/src/ReactiveUI.Tests/WaitForDispatcherSchedulerTests.cs b/src/ReactiveUI.Tests/WaitForDispatcherSchedulerTests.cs index a3d5be3656..d6b0431416 100644 --- a/src/ReactiveUI.Tests/WaitForDispatcherSchedulerTests.cs +++ b/src/ReactiveUI.Tests/WaitForDispatcherSchedulerTests.cs @@ -8,7 +8,7 @@ namespace ReactiveUI.Tests; /// /// Tests the WaitForDispatcherSchedulerClass. /// -public class WaitForDispatcherSchedulerTests : AppBuilderTestBase +public class WaitForDispatcherSchedulerTests { /// /// Tests call scheduler factory on creation. diff --git a/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs b/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs index f039855762..3ee51f54a2 100644 --- a/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs +++ b/src/ReactiveUI.Tests/WhenAny/ReactiveNotifyPropertyChangedMixinTest.cs @@ -4,14 +4,17 @@ // See the LICENSE file in the project root for full license information. using DynamicData; + using Microsoft.Reactive.Testing; +using ReactiveUI.Testing; + namespace ReactiveUI.Tests; /// /// Tests the reactive notify property changed. /// -public class ReactiveNotifyPropertyChangedMixinTest : AppBuilderTestBase +public class ReactiveNotifyPropertyChangedMixinTest { /// /// Gets or sets the dummy. @@ -19,42 +22,40 @@ public class ReactiveNotifyPropertyChangedMixinTest : AppBuilderTestBase public string? Dummy { get; set; } [Fact] - public async Task AnyChangeInExpressionListTriggersUpdate() => - await RunAppBuilderTestAsync(() => - { - var obj = new ObjChain1(); - bool obsUpdated; + public void AnyChangeInExpressionListTriggersUpdate() + { + var obj = new ObjChain1(); + bool obsUpdated; - obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(_ => obsUpdated = true); + obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(_ => obsUpdated = true); - obsUpdated = false; - obj.Model.Model.Model.SomeOtherParam = 42; - Assert.True(obsUpdated); + obsUpdated = false; + obj.Model.Model.Model.SomeOtherParam = 42; + Assert.True(obsUpdated); - obsUpdated = false; - obj.Model.Model.Model = new HostTestFixture(); - Assert.True(obsUpdated); + obsUpdated = false; + obj.Model.Model.Model = new HostTestFixture(); + Assert.True(obsUpdated); - obsUpdated = false; - obj.Model.Model = new ObjChain3 + obsUpdated = false; + obj.Model.Model = new ObjChain3 + { + Model = new HostTestFixture { - Model = new HostTestFixture - { - SomeOtherParam = 10 - } - }; - Assert.True(obsUpdated); + SomeOtherParam = 10 + } + }; + Assert.True(obsUpdated); - obsUpdated = false; - obj.Model = new ObjChain2(); - Assert.True(obsUpdated); - }); + obsUpdated = false; + obj.Model = new ObjChain2(); + Assert.True(obsUpdated); + } [Fact] - public async Task MultiPropertyExpressionsShouldBeProperlyResolved() => - await RunAppBuilderTestAsync(() => - { - var data = new Dictionary>, string[]> + public void MultiPropertyExpressionsShouldBeProperlyResolved() + { + var data = new Dictionary>, string[]> { { x => x!.Child!.IsOnlyOneWord!.Length, new[] { "Child", "IsOnlyOneWord", "Length" } }, { x => x.SomeOtherParam, new[] { "SomeOtherParam" } }, @@ -62,7 +63,7 @@ await RunAppBuilderTestAsync(() => { x => x.Child!.Changed, new[] { "Child", "Changed" } }, }; - var dataTypes = new Dictionary>, Type[]> + var dataTypes = new Dictionary>, Type[]> { { x => x.Child!.IsOnlyOneWord!.Length, new[] { typeof(TestFixture), typeof(string), typeof(int) } }, { x => x.SomeOtherParam, new[] { typeof(int) } }, @@ -70,1262 +71,1279 @@ await RunAppBuilderTestAsync(() => { x => x.Child!.Changed, new[] { typeof(TestFixture), typeof(IObservable>) } }, }; - var results = data.Keys.Select( + var results = data.Keys.Select( x => new { input = x, output = Reflection.Rewrite(x.Body).GetExpressionChain() }).ToArray(); - var resultTypes = dataTypes.Keys.Select( + var resultTypes = dataTypes.Keys.Select( x => new { input = x, output = Reflection.Rewrite(x.Body).GetExpressionChain() }).ToArray(); - foreach (var x in results) - { - data[x.input].AssertAreEqual(x.output.Select(y => + foreach (var x in results) + { + data[x.input].AssertAreEqual(x.output.Select(y => { var propertyName = y.GetMemberInfo()?.Name; return propertyName ?? throw new InvalidOperationException("propertyName should not be null."); })); - } + } - foreach (var x in resultTypes) - { - dataTypes[x.input].AssertAreEqual(x.output.Select(y => y.Type)); - } - }); + foreach (var x in resultTypes) + { + dataTypes[x.input].AssertAreEqual(x.output.Select(y => y.Type)); + } + } [Fact] - public async Task OFPChangingTheHostPropertyShouldFireAChildChangeNotificationOnlyIfThePreviousChildIsDifferent() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With(scheduler => + public void OFPChangingTheHostPropertyShouldFireAChildChangeNotificationOnlyIfThePreviousChildIsDifferent() => + new TestScheduler().With(scheduler => + { + var fixture = new HostTestFixture() { - var fixture = new HostTestFixture() - { - Child = new TestFixture() - }; - fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.Child.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); + Child = new TestFixture() + }; + fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); - fixture.Child.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); + fixture.Child.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); - fixture.Child = new TestFixture - { - IsOnlyOneWord = "Bar" - }; - scheduler.Start(); - Assert.Equal(2, changes.Count); - })); + fixture.Child.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); - [Fact] - public async Task OFPNamedPropertyTest() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With(scheduler => + fixture.Child = new TestFixture { - var fixture = new TestFixture(); - fixture.ObservableForProperty(x => x.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - fixture.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); + IsOnlyOneWord = "Bar" + }; + scheduler.Start(); + Assert.Equal(2, changes.Count); + }); - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); - })); + [Fact] + public void OFPNamedPropertyTest() => + new TestScheduler().With(scheduler => + { + var fixture = new TestFixture(); + fixture.ObservableForProperty(x => x.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + fixture.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); + }); [Fact] - public async Task OFPNamedPropertyTestBeforeChange() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With(scheduler => + public void OFPNamedPropertyTestBeforeChange() => + new TestScheduler().With(scheduler => + { + var fixture = new TestFixture() { - var fixture = new TestFixture() - { - IsOnlyOneWord = "Pre" - }; - fixture.ObservableForProperty(x => x.IsOnlyOneWord, beforeChange: true) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); + IsOnlyOneWord = "Pre" + }; + fixture.ObservableForProperty(x => x.IsOnlyOneWord, beforeChange: true) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); - scheduler.Start(); - Assert.Equal(0, changes.Count); + scheduler.Start(); + Assert.Equal(0, changes.Count); - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); - fixture.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); + fixture.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Pre", "Foo" }); - })); + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Pre", "Foo" }); + }); [Fact] - public async Task OFPNamedPropertyTestNoSkipInitial() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With(scheduler => + public void OFPNamedPropertyTestNoSkipInitial() => + new TestScheduler().With(scheduler => + { + var fixture = new TestFixture() { - var fixture = new TestFixture() - { - IsOnlyOneWord = "Pre" - }; - fixture.ObservableForProperty(x => x.IsOnlyOneWord, false, false) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); + IsOnlyOneWord = "Pre" + }; + fixture.ObservableForProperty(x => x.IsOnlyOneWord, false, false) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); - scheduler.Start(); - Assert.Equal(1, changes.Count); + scheduler.Start(); + Assert.Equal(1, changes.Count); - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(2, changes.Count); + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(2, changes.Count); - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Pre", "Foo" }); - })); + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Pre", "Foo" }); + }); [Fact] - public async Task OFPNamedPropertyTestRepeats() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With(scheduler => - { - var fixture = new TestFixture(); - fixture.ObservableForProperty(x => x.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Foo" }); - })); + public void OFPNamedPropertyTestRepeats() => + new TestScheduler().With(scheduler => + { + var fixture = new TestFixture(); + fixture.ObservableForProperty(x => x.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Foo" }); + }); [Fact] - public async Task OFPReplacingTheHostShouldResubscribeTheObservable() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With(scheduler => + public void OFPReplacingTheHostShouldResubscribeTheObservable() => + new TestScheduler().With(scheduler => + { + var fixture = new HostTestFixture() { - var fixture = new HostTestFixture() - { - Child = new TestFixture() - }; - fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.Child.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.Child.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - // Tricky! This is a change too, because from the perspective - // of the binding, we've went from "Bar" to null - fixture.Child = new TestFixture(); - scheduler.Start(); - Assert.Equal(3, changes.Count); - - // Here we've set the value but it shouldn't change - fixture.Child.IsOnlyOneWord = null!; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - fixture.Child.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(4, changes.Count); - - fixture.Child.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(4, changes.Count); - - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", null, "Baz" }); - })); + Child = new TestFixture() + }; + fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixture.Child.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.Child.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + // Tricky! This is a change too, because from the perspective + // of the binding, we've went from "Bar" to null + fixture.Child = new TestFixture(); + scheduler.Start(); + Assert.Equal(3, changes.Count); + + // Here we've set the value but it shouldn't change + fixture.Child.IsOnlyOneWord = null!; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + fixture.Child.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(4, changes.Count); + + fixture.Child.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(4, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", null, "Baz" }); + }); [Fact] - public async Task OFPReplacingTheHostWithNullThenSettingItBackShouldResubscribeTheObservable() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With(scheduler => + public void OFPReplacingTheHostWithNullThenSettingItBackShouldResubscribeTheObservable() => + new TestScheduler().With(scheduler => + { + var fixture = new HostTestFixture() { - var fixture = new HostTestFixture() - { - Child = new TestFixture() - }; - var fixtureProp = fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord); - fixtureProp - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixtureProp.Subscribe(x => Console.WriteLine(x.Value)); - - fixture.Child.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.Child.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - // Oops, now the child is Null, we may now blow up - fixture.Child = null!; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - // Tricky! This is a change too, because from the perspective - // of the binding, we've went from "Bar" to null - fixture.Child = new TestFixture(); - scheduler.Start(); - Assert.Equal(3, changes.Count); - - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", null }); - })); + Child = new TestFixture() + }; + var fixtureProp = fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord); + fixtureProp + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixtureProp.Subscribe(x => Console.WriteLine(x.Value)); + + fixture.Child.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.Child.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + // Oops, now the child is Null, we may now blow up + fixture.Child = null!; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + // Tricky! This is a change too, because from the perspective + // of the binding, we've went from "Bar" to null + fixture.Child = new TestFixture(); + scheduler.Start(); + Assert.Equal(3, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", null }); + }); [Fact] - public async Task OFPShouldWorkWithINPCObjectsToo() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With(scheduler => + public void OFPShouldWorkWithINPCObjectsToo() => + new TestScheduler().With(scheduler => + { + var fixture = new NonReactiveINPCObject() { - var fixture = new NonReactiveINPCObject() - { - InpcProperty = null! - }; - fixture.ObservableForProperty(x => x.InpcProperty.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.InpcProperty = new TestFixture(); - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.InpcProperty.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.InpcProperty.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - })); + InpcProperty = null! + }; + fixture.ObservableForProperty(x => x.InpcProperty.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixture.InpcProperty = new TestFixture(); + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.InpcProperty.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.InpcProperty.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + }); [Fact] - public async Task OFPSimpleChildPropertyTest() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With(scheduler => + public void OFPSimpleChildPropertyTest() => + new TestScheduler().With(scheduler => + { + var fixture = new HostTestFixture() { - var fixture = new HostTestFixture() - { - Child = new TestFixture() - }; - fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.Child.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.Child.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); - - fixture.Child.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - fixture.Child.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); - - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); - })); + Child = new TestFixture() + }; + fixture.ObservableForProperty(x => x.Child!.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixture.Child.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.Child.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.Child.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + fixture.Child.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "Child.IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); + }); [Fact] - public async Task OFPSimplePropertyTest() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With(scheduler => - { - var fixture = new TestFixture(); - fixture.ObservableForProperty(x => x.IsOnlyOneWord) - .ToObservableChangeSet(ImmediateScheduler.Instance) - .Bind(out var changes) - .Subscribe(); - - fixture.IsOnlyOneWord = "Foo"; - scheduler.Start(); - Assert.Equal(1, changes.Count); - - fixture.IsOnlyOneWord = "Bar"; - scheduler.Start(); - Assert.Equal(2, changes.Count); + public void OFPSimplePropertyTest() => + new TestScheduler().With(scheduler => + { + var fixture = new TestFixture(); + fixture.ObservableForProperty(x => x.IsOnlyOneWord) + .ToObservableChangeSet(ImmediateScheduler.Instance) + .Bind(out var changes) + .Subscribe(); + + fixture.IsOnlyOneWord = "Foo"; + scheduler.Start(); + Assert.Equal(1, changes.Count); + + fixture.IsOnlyOneWord = "Bar"; + scheduler.Start(); + Assert.Equal(2, changes.Count); + + fixture.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + fixture.IsOnlyOneWord = "Baz"; + scheduler.Start(); + Assert.Equal(3, changes.Count); + + Assert.True(changes.All(x => x.Sender == fixture)); + Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); + changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); + }); - fixture.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); + [Fact] + public void SubscriptionToWhenAnyShouldReturnCurrentValue() + { + var obj = new HostTestFixture(); + var observedValue = 1; + obj.WhenAnyValue(x => x.SomeOtherParam).Subscribe(x => observedValue = x); - fixture.IsOnlyOneWord = "Baz"; - scheduler.Start(); - Assert.Equal(3, changes.Count); + obj.SomeOtherParam = 42; - Assert.True(changes.All(x => x.Sender == fixture)); - Assert.True(changes.All(x => x.GetPropertyName() == "IsOnlyOneWord")); - changes.Select(x => x.Value).AssertAreEqual(new[] { "Foo", "Bar", "Baz" }); - })); + Assert.True(observedValue == obj.SomeOtherParam); + } [Fact] - public async Task SubscriptionToWhenAnyShouldReturnCurrentValue() => - await RunAppBuilderTestAsync(() => - { - var obj = new HostTestFixture(); - var observedValue = 1; - obj.WhenAnyValue(x => x.SomeOtherParam).Subscribe(x => observedValue = x); + public void WhenAnyShouldRunInContext() + { + var tid = Environment.CurrentManagedThreadId; - obj.SomeOtherParam = 42; + TaskPoolScheduler.Default.With( + _ => + { + var whenAnyTid = 0; + var fixture = new TestFixture + { + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }; - Assert.True(observedValue == obj.SomeOtherParam); - }); + fixture.WhenAnyValue(x => x.IsNotNullString).Subscribe(__ => whenAnyTid = Environment.CurrentManagedThreadId); - [Fact] - public async Task WhenAnyShouldRunInContext() => - await RunAppBuilderTestAsync(() => - { - var tid = Environment.CurrentManagedThreadId; - - TaskPoolScheduler.Default.With( - _ => + var timeout = 10; + fixture.IsNotNullString = "Bar"; + while (--timeout > 0 && whenAnyTid == 0) { - var whenAnyTid = 0; - var fixture = new TestFixture - { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }; - - fixture.WhenAnyValue(x => x.IsNotNullString).Subscribe(__ => whenAnyTid = Environment.CurrentManagedThreadId); - - var timeout = 10; - fixture.IsNotNullString = "Bar"; - while (--timeout > 0 && whenAnyTid == 0) - { - Thread.Sleep(250); - } - - Assert.Equal(tid, whenAnyTid); - }); - }); + Thread.Sleep(250); + } + + Assert.Equal(tid, whenAnyTid); + }); + } [Fact] - public async Task WhenAnyShouldWorkEvenWithNormalProperties() => - await RunAppBuilderTestAsync(() => + public void WhenAnyShouldWorkEvenWithNormalProperties() + { + var fixture = new TestFixture { - var fixture = new TestFixture - { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }; + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }; - var output = new List?>(); - fixture.WhenAny(x => x.PocoProperty, x => x).Subscribe(output.Add); - var output2 = new List(); - fixture.WhenAnyValue(x => x.PocoProperty).Subscribe(output2.Add); - var output3 = new List?>(); - fixture.WhenAny(x => x.NullableInt, x => x).Subscribe(output3.Add); + var output = new List?>(); + fixture.WhenAny(x => x.PocoProperty, x => x).Subscribe(output.Add); + var output2 = new List(); + fixture.WhenAnyValue(x => x.PocoProperty).Subscribe(output2.Add); + var output3 = new List?>(); + fixture.WhenAny(x => x.NullableInt, x => x).Subscribe(output3.Add); - var output4 = new List(); - fixture.WhenAnyValue(x => x.NullableInt).Subscribe(output4.Add); + var output4 = new List(); + fixture.WhenAnyValue(x => x.NullableInt).Subscribe(output4.Add); - Assert.Equal(1, output.Count); - Assert.Equal(fixture, output[0]!.Sender); - Assert.Equal("PocoProperty", output[0]!.GetPropertyName()); - Assert.Equal("Bamf", output[0]!.Value); + Assert.Equal(1, output.Count); + Assert.Equal(fixture, output[0]!.Sender); + Assert.Equal("PocoProperty", output[0]!.GetPropertyName()); + Assert.Equal("Bamf", output[0]!.Value); - Assert.Equal(1, output2.Count); - Assert.Equal("Bamf", output2[0]); + Assert.Equal(1, output2.Count); + Assert.Equal("Bamf", output2[0]); - Assert.Equal(1, output3.Count); - Assert.Equal(fixture, output3[0]!.Sender); - Assert.Equal("NullableInt", output3[0]!.GetPropertyName()); - Assert.Equal(null, output3[0]!.Value); + Assert.Equal(1, output3.Count); + Assert.Equal(fixture, output3[0]!.Sender); + Assert.Equal("NullableInt", output3[0]!.GetPropertyName()); + Assert.Equal(null, output3[0]!.Value); - Assert.Equal(1, output4.Count); - Assert.Equal(null, output4[0]); - }); + Assert.Equal(1, output4.Count); + Assert.Equal(null, output4[0]); + } [Fact] - public async Task ChangedShouldHaveValidData() => - await RunAppBuilderTestAsync(() => + public void ChangedShouldHaveValidData() + { + var fixture = new TestFixture { - var fixture = new TestFixture - { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }; + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }; - object sender = null!; - string? propertyName = null; - fixture.Changed.ObserveOn(ImmediateScheduler.Instance).Subscribe( - x => - { - sender = x.Sender; - propertyName = x.PropertyName; - }); + object sender = null!; + string? propertyName = null; + fixture.Changed.ObserveOn(ImmediateScheduler.Instance).Subscribe( + x => + { + sender = x.Sender; + propertyName = x.PropertyName; + }); - fixture.UsesExprRaiseSet = "abc"; + fixture.UsesExprRaiseSet = "abc"; - Assert.Equal(fixture, sender); - Assert.Equal(nameof(fixture.UsesExprRaiseSet), propertyName); + Assert.Equal(fixture, sender); + Assert.Equal(nameof(fixture.UsesExprRaiseSet), propertyName); - sender = null!; - propertyName = null; - fixture.PocoProperty = "abc"; + sender = null!; + propertyName = null; + fixture.PocoProperty = "abc"; - Assert.Equal(null!, sender); - Assert.Equal(null, propertyName); - }); + Assert.Equal(null!, sender); + Assert.Equal(null, propertyName); + } [Fact] - public async Task ChangingShouldHaveValidData() => - await RunAppBuilderTestAsync(() => + public void ChangingShouldHaveValidData() + { + var fixture = new TestFixture { - var fixture = new TestFixture - { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }; + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }; - object sender = null!; - string? propertyName = null; - fixture.Changing.ObserveOn(ImmediateScheduler.Instance).Subscribe( - x => - { - sender = x.Sender; - propertyName = x.PropertyName; - }); + object sender = null!; + string? propertyName = null; + fixture.Changing.ObserveOn(ImmediateScheduler.Instance).Subscribe( + x => + { + sender = x.Sender; + propertyName = x.PropertyName; + }); - fixture.UsesExprRaiseSet = "abc"; + fixture.UsesExprRaiseSet = "abc"; - Assert.Equal(fixture, sender); - Assert.Equal(nameof(fixture.UsesExprRaiseSet), propertyName); + Assert.Equal(fixture, sender); + Assert.Equal(nameof(fixture.UsesExprRaiseSet), propertyName); - sender = null!; - propertyName = null; - fixture.PocoProperty = "abc"; + sender = null!; + propertyName = null; + fixture.PocoProperty = "abc"; - Assert.Equal(null!, sender); - Assert.Equal(null, propertyName); - }); + Assert.Equal(null!, sender); + Assert.Equal(null, propertyName); + } [Fact] - public async Task WhenAnySmokeTest() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With( - scheduler => + public void WhenAnySmokeTest() => + new TestScheduler().With( + scheduler => + { + var fixture = new HostTestFixture { - var fixture = new HostTestFixture + Child = new TestFixture(), + SomeOtherParam = 5 + }; + fixture.Child.IsNotNullString = "Foo"; + + var output1 = new List>(); + var output2 = new List>(); + fixture.WhenAny( + x => x.SomeOtherParam, + x => x.Child!.IsNotNullString, + (sop, nns) => new + { + sop, + nns + }).Subscribe( + x => { - Child = new TestFixture(), - SomeOtherParam = 5 - }; - fixture.Child.IsNotNullString = "Foo"; - - var output1 = new List>(); - var output2 = new List>(); - fixture.WhenAny( - x => x.SomeOtherParam, - x => x.Child!.IsNotNullString, - (sop, nns) => new - { - sop, - nns - }).Subscribe( - x => - { - output1.Add(x!.sop); - output2.Add(x.nns!); - }); - - scheduler.Start(); - Assert.Equal(1, output1.Count); - Assert.Equal(1, output2.Count); - Assert.Equal(fixture, output1[0].Sender); - Assert.Equal(fixture, output2[0].Sender); - Assert.Equal(5, output1[0].Value); - Assert.Equal("Foo", output2[0].Value); - - fixture.SomeOtherParam = 10; - scheduler.Start(); - Assert.Equal(2, output1.Count); - Assert.Equal(2, output2.Count); - Assert.Equal(fixture, output1[1].Sender); - Assert.Equal(fixture, output2[1].Sender); - Assert.Equal(10, output1[1].Value); - Assert.Equal("Foo", output2[1].Value); - - fixture.Child.IsNotNullString = "Bar"; - scheduler.Start(); - Assert.Equal(3, output1.Count); - Assert.Equal(3, output2.Count); - Assert.Equal(fixture, output1[2].Sender); - Assert.Equal(fixture, output2[2].Sender); - Assert.Equal(10, output1[2].Value); - Assert.Equal("Bar", output2[2].Value); - })); + output1.Add(x!.sop); + output2.Add(x.nns!); + }); + + scheduler.Start(); + Assert.Equal(1, output1.Count); + Assert.Equal(1, output2.Count); + Assert.Equal(fixture, output1[0].Sender); + Assert.Equal(fixture, output2[0].Sender); + Assert.Equal(5, output1[0].Value); + Assert.Equal("Foo", output2[0].Value); + + fixture.SomeOtherParam = 10; + scheduler.Start(); + Assert.Equal(2, output1.Count); + Assert.Equal(2, output2.Count); + Assert.Equal(fixture, output1[1].Sender); + Assert.Equal(fixture, output2[1].Sender); + Assert.Equal(10, output1[1].Value); + Assert.Equal("Foo", output2[1].Value); + + fixture.Child.IsNotNullString = "Bar"; + scheduler.Start(); + Assert.Equal(3, output1.Count); + Assert.Equal(3, output2.Count); + Assert.Equal(fixture, output1[2].Sender); + Assert.Equal(fixture, output2[2].Sender); + Assert.Equal(10, output1[2].Value); + Assert.Equal("Bar", output2[2].Value); + }); [Fact] - public async Task WhenAnyValueShouldWorkEvenWithNormalProperties() => - await RunAppBuilderTestAsync(() => + public void WhenAnyValueShouldWorkEvenWithNormalProperties() + { + var fixture = new TestFixture { - var fixture = new TestFixture - { - IsNotNullString = "Foo", - IsOnlyOneWord = "Baz", - PocoProperty = "Bamf" - }; + IsNotNullString = "Foo", + IsOnlyOneWord = "Baz", + PocoProperty = "Bamf" + }; - var output1 = new List(); - var output2 = new List(); - fixture.WhenAnyValue(x => x.PocoProperty).Subscribe(output1.Add); - fixture.WhenAnyValue(x => x.IsOnlyOneWord, x => x?.Length).Subscribe(output2.Add); + var output1 = new List(); + var output2 = new List(); + fixture.WhenAnyValue(x => x.PocoProperty).Subscribe(output1.Add); + fixture.WhenAnyValue(x => x.IsOnlyOneWord, x => x?.Length).Subscribe(output2.Add); - Assert.Equal(1, output1.Count); - Assert.Equal("Bamf", output1[0]); - Assert.Equal(1, output2.Count); - Assert.Equal(3, output2[0]); - }); + Assert.Equal(1, output1.Count); + Assert.Equal("Bamf", output1[0]); + Assert.Equal(1, output2.Count); + Assert.Equal(3, output2[0]); + } [Fact] - public async Task WhenAnyValueSmokeTest() => - await RunAppBuilderTestAsync(() => - new TestScheduler().With( - scheduler => + public void WhenAnyValueSmokeTest() => + new TestScheduler().With( + scheduler => + { + var fixture = new HostTestFixture { - var fixture = new HostTestFixture + Child = new TestFixture(), + SomeOtherParam = 5 + }; + fixture.Child.IsNotNullString = "Foo"; + + var output1 = new List(); + var output2 = new List(); + fixture.WhenAnyValue( + x => x.SomeOtherParam, + x => x.Child!.IsNotNullString, + (sop, nns) => new { - Child = new TestFixture(), - SomeOtherParam = 5 - }; - fixture.Child.IsNotNullString = "Foo"; - - var output1 = new List(); - var output2 = new List(); - fixture.WhenAnyValue( - x => x.SomeOtherParam, - x => x.Child!.IsNotNullString, - (sop, nns) => new - { - sop, - nns - }).Subscribe( - x => - { - output1.Add(x!.sop); - output2.Add(x.nns!); - }); - - scheduler.Start(); - Assert.Equal(1, output1.Count); - Assert.Equal(1, output2.Count); - Assert.Equal(5, output1[0]); - Assert.Equal("Foo", output2[0]); - - fixture.SomeOtherParam = 10; - scheduler.Start(); - Assert.Equal(2, output1.Count); - Assert.Equal(2, output2.Count); - Assert.Equal(10, output1[1]); - Assert.Equal("Foo", output2[1]); - - fixture.Child.IsNotNullString = "Bar"; - scheduler.Start(); - Assert.Equal(3, output1.Count); - Assert.Equal(3, output2.Count); - Assert.Equal(10, output1[2]); - Assert.Equal("Bar", output2[2]); - })); + sop, + nns + }).Subscribe( + x => + { + output1.Add(x!.sop); + output2.Add(x.nns!); + }); + + scheduler.Start(); + Assert.Equal(1, output1.Count); + Assert.Equal(1, output2.Count); + Assert.Equal(5, output1[0]); + Assert.Equal("Foo", output2[0]); + + fixture.SomeOtherParam = 10; + scheduler.Start(); + Assert.Equal(2, output1.Count); + Assert.Equal(2, output2.Count); + Assert.Equal(10, output1[1]); + Assert.Equal("Foo", output2[1]); + + fixture.Child.IsNotNullString = "Bar"; + scheduler.Start(); + Assert.Equal(3, output1.Count); + Assert.Equal(3, output2.Count); + Assert.Equal(10, output1[2]); + Assert.Equal("Bar", output2[2]); + }); [Fact] - public async Task ObjectShouldBeGarbageCollectedWhenPropertyValueChanges() => - await RunAppBuilderTestAsync(() => + public void ObjectShouldBeGarbageCollectedWhenPropertyValueChanges() + { + static (ObjChain1, WeakReference) GetWeakReference1() { - static (ObjChain1, WeakReference) GetWeakReference1() - { - var obj = new ObjChain1(); - var weakRef = new WeakReference(obj.Model); - obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); - obj.Model = new ObjChain2(); + var obj = new ObjChain1(); + var weakRef = new WeakReference(obj.Model); + obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); + obj.Model = new ObjChain2(); - return (obj, weakRef); - } + return (obj, weakRef); + } - static (ObjChain1, WeakReference) GetWeakReference2() - { - var obj = new ObjChain1(); - var weakRef = new WeakReference(obj.Model.Model); - obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); - obj.Model.Model = new ObjChain3(); + static (ObjChain1, WeakReference) GetWeakReference2() + { + var obj = new ObjChain1(); + var weakRef = new WeakReference(obj.Model.Model); + obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); + obj.Model.Model = new ObjChain3(); - return (obj, weakRef); - } + return (obj, weakRef); + } - static (ObjChain1, WeakReference) GetWeakReference3() - { - var obj = new ObjChain1(); - var weakRef = new WeakReference(obj.Model.Model.Model); - obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); - obj.Model.Model.Model = new HostTestFixture(); + static (ObjChain1, WeakReference) GetWeakReference3() + { + var obj = new ObjChain1(); + var weakRef = new WeakReference(obj.Model.Model.Model); + obj.ObservableForProperty(x => x.Model.Model.Model.SomeOtherParam).Subscribe(); + obj.Model.Model.Model = new HostTestFixture(); - return (obj, weakRef); - } + return (obj, weakRef); + } - var (obj1, weakRef1) = GetWeakReference1(); - var (obj2, weakRef2) = GetWeakReference2(); - var (obj3, weakRef3) = GetWeakReference3(); + var (obj1, weakRef1) = GetWeakReference1(); + var (obj2, weakRef2) = GetWeakReference2(); + var (obj3, weakRef3) = GetWeakReference3(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + GC.Collect(); + GC.WaitForPendingFinalizers(); - Assert.False(weakRef1.IsAlive); - Assert.False(weakRef2.IsAlive); - Assert.False(weakRef3.IsAlive); - }); + Assert.False(weakRef1.IsAlive); + Assert.False(weakRef2.IsAlive); + Assert.False(weakRef3.IsAlive); + } [Fact] - public async Task WhenAnyValueUnsupportedExpressionType_Equal() => - await RunAppBuilderTestAsync(() => - { - var fixture = new TestFixture(); - var exception = Assert.Throws( - () => fixture.WhenAnyValue(x => x.IsNotNullString == x.IsOnlyOneWord).Subscribe()); + public void WhenAnyValueUnsupportedExpressionType_Equal() + { + var fixture = new TestFixture(); + var exception = Assert.Throws( + () => fixture.WhenAnyValue(x => x.IsNotNullString == x.IsOnlyOneWord).Subscribe()); - Assert.Equal("Unsupported expression of type 'Equal' (x.IsNotNullString == x.IsOnlyOneWord). Did you meant to use expressions 'x.IsNotNullString' and 'x.IsOnlyOneWord'?", exception.Message); - }); + Assert.Equal("Unsupported expression of type 'Equal' (x.IsNotNullString == x.IsOnlyOneWord). Did you meant to use expressions 'x.IsNotNullString' and 'x.IsOnlyOneWord'?", exception.Message); + } [Fact] - public async Task WhenAnyValueUnsupportedExpressionType_Constant() => - await RunAppBuilderTestAsync(() => - { - var fixture = new TestFixture(); - var exception = Assert.Throws( - () => fixture.WhenAnyValue(_ => Dummy).Subscribe()); + public void WhenAnyValueUnsupportedExpressionType_Constant() + { + var fixture = new TestFixture(); + var exception = Assert.Throws( + () => fixture.WhenAnyValue(_ => Dummy).Subscribe()); - Assert.Equal("Unsupported expression of type 'Constant'. Did you miss the member access prefix in the expression?", exception.Message); - }); + Assert.Equal("Unsupported expression of type 'Constant'. Did you miss the member access prefix in the expression?", exception.Message); + } [Fact] - public async Task NullableTypesTestShouldntNeedDecorators() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - IEnumerable? result = null; - fixture.WhenAnyValue(x => x.AccountService.AccountUsersNullable) - .Where(users => users.Count > 0) - .Select(users => users.Values.Where(x => !string.IsNullOrWhiteSpace(x?.LastName))) - .Subscribe(dict => result = dict); - - Assert.Equal(result!.Count(), 3); - }); + public void NullableTypesTestShouldntNeedDecorators() + { + var fixture = new WhenAnyTestFixture(); + IEnumerable? result = null; + fixture.WhenAnyValue(x => x.AccountService.AccountUsersNullable) + .Where(users => users.Count > 0) + .Select(users => users.Values.Where(x => !string.IsNullOrWhiteSpace(x?.LastName))) + .Subscribe(dict => result = dict); + + Assert.Equal(result!.Count(), 3); + } + /// + /// Nullables the types test shouldnt need decorators2. + /// [Fact] - public async Task NullableTypesTestShouldntNeedDecorators2() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - IEnumerable? result = null; - fixture.WhenAnyValue( - x => x.ProjectService.ProjectsNullable, - x => x.AccountService.AccountUsersNullable) - .Where(tuple => tuple.Item1?.Count > 0 && tuple.Item2?.Count > 0) - .Select(tuple => - { - var (projects, users) = tuple; - return users?.Values.Where(x => !string.IsNullOrWhiteSpace(x?.LastName)); - }) - .Subscribe(dict => result = dict); - - Assert.Equal(result!.Count(), 3); - }); + public void NullableTypesTestShouldntNeedDecorators2() + { + var fixture = new WhenAnyTestFixture(); + IEnumerable? result = null; + fixture.WhenAnyValue( + x => x.ProjectService.ProjectsNullable, + x => x.AccountService.AccountUsersNullable) + .Where(tuple => tuple.Item1?.Count > 0 && tuple.Item2?.Count > 0) + .Select(tuple => + { + var (projects, users) = tuple; + return users?.Values.Where(x => !string.IsNullOrWhiteSpace(x?.LastName)); + }) + .Subscribe(dict => result = dict); + + Assert.Equal(result!.Count(), 3); + } + /// + /// Nons the nullable types test shouldnt need decorators. + /// [Fact] - public async Task NonNullableTypesTestShouldntNeedDecorators() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - IEnumerable? result = null; - fixture.WhenAnyValue(x => x.AccountService.AccountUsers) - .Where(users => users.Count > 0) - .Select(users => users.Values.Where(x => !string.IsNullOrWhiteSpace(x.LastName))) - .Subscribe(dict => result = dict); - - Assert.Equal(result!.Count(), 3); - }); + public void NonNullableTypesTestShouldntNeedDecorators() + { + var fixture = new WhenAnyTestFixture(); + IEnumerable? result = null; + fixture.WhenAnyValue(x => x.AccountService.AccountUsers) + .Where(users => users.Count > 0) + .Select(users => users.Values.Where(x => !string.IsNullOrWhiteSpace(x.LastName))) + .Subscribe(dict => result = dict); + + Assert.Equal(result!.Count(), 3); + } + /// + /// Nons the nullable types test shouldnt need decorators2. + /// [Fact] - public async Task NonNullableTypesTestShouldntNeedDecorators2() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - IEnumerable? result = null; - fixture.WhenAnyValue( - x => x.ProjectService.Projects, - x => x.AccountService.AccountUsers) - .Where(tuple => tuple.Item1?.Count > 0 && tuple.Item2?.Count > 0) - .Select(tuple => - { - var (projects, users) = tuple; - return users!.Values.Where(x => !string.IsNullOrWhiteSpace(x.LastName)); - }) - .Subscribe(dict => result = dict); - - Assert.Equal(result!.Count(), 3); - }); + public void NonNullableTypesTestShouldntNeedDecorators2() + { + var fixture = new WhenAnyTestFixture(); + IEnumerable? result = null; + fixture.WhenAnyValue( + x => x.ProjectService.Projects, + x => x.AccountService.AccountUsers) + .Where(tuple => tuple.Item1?.Count > 0 && tuple.Item2?.Count > 0) + .Select(tuple => + { + var (projects, users) = tuple; + return users!.Values.Where(x => !string.IsNullOrWhiteSpace(x.LastName)); + }) + .Subscribe(dict => result = dict); + + Assert.Equal(result!.Count(), 3); + } + /// + /// Whens any value with1 paramerters. + /// [Fact] - public async Task WhenAnyValueWith1Paramerters() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1).Subscribe(value => result = value); + public void WhenAnyValueWith1Paramerters() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1).Subscribe(value => result = value); - Assert.Equal(result, "1"); - }); + Assert.Equal(result, "1"); + } [Fact] - public async Task WhenAnyValueWith1ParamertersSequentialCheck() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - var result = string.Empty; - fixture.Value1 = null!; - fixture.WhenAnyValue( - x => x.Value1).Subscribe(value => result = value); + public void WhenAnyValueWith1ParamertersSequentialCheck() + { + var fixture = new WhenAnyTestFixture(); + var result = string.Empty; + fixture.Value1 = null!; + fixture.WhenAnyValue( + x => x.Value1).Subscribe(value => result = value); - Assert.Equal(result, null); + Assert.Equal(result, null); - fixture.Value1 = "A"; - Assert.Equal(result, "A"); + fixture.Value1 = "A"; + Assert.Equal(result, "A"); - fixture.Value1 = "B"; - Assert.Equal(result, "B"); + fixture.Value1 = "B"; + Assert.Equal(result, "B"); - fixture.Value1 = null!; - Assert.Equal(result, null); - }); + fixture.Value1 = null!; + Assert.Equal(result, null); + } [Fact] - public async Task WhenAnyValueWith1ParamertersSequentialCheckNullable() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - var result = string.Empty; - fixture.WhenAnyValue( - x => x.Value2).Subscribe(value => result = value); + public void WhenAnyValueWith1ParamertersSequentialCheckNullable() + { + var fixture = new WhenAnyTestFixture(); + var result = string.Empty; + fixture.WhenAnyValue( + x => x.Value2).Subscribe(value => result = value); - Assert.Equal(result, null); + Assert.Equal(result, null); - fixture.Value2 = "A"; - Assert.Equal(result, "A"); + fixture.Value2 = "A"; + Assert.Equal(result, "A"); - fixture.Value2 = "B"; - Assert.Equal(result, "B"); + fixture.Value2 = "B"; + Assert.Equal(result, "B"); - fixture.Value2 = null; - Assert.Equal(result, null); - }); + fixture.Value2 = null; + Assert.Equal(result, null); + } + /// + /// Whens any value with2 paramerters returns tuple. + /// [Fact] - public async Task WhenAnyValueWith2ParamertersReturnsTuple() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2) - .Select(tuple => - { - var (value1, value2) = tuple; - return value1 + value2; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1"); - }); + public void WhenAnyValueWith2ParamertersReturnsTuple() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2) + .Select(tuple => + { + var (value1, value2) = tuple; + return value1 + value2; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1"); + } + /// + /// Whens any value with2 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith2ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - (v1, v2) => (v1, v2)) - .Select(tuple => - { - var (value1, value2) = tuple; - return value1 + value2; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1"); - }); + public void WhenAnyValueWith2ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + (v1, v2) => (v1, v2)) + .Select(tuple => + { + var (value1, value2) = tuple; + return value1 + value2; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1"); + } + /// + /// Whens any value with3 paramerters returns tuple. + /// [Fact] - public async Task WhenAnyValueWith3ParamertersReturnsTuple() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3) - .Select(tuple => - { - var (value1, value2, value3) = tuple; - return value1 + value2 + value3; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13"); - }); + public void WhenAnyValueWith3ParamertersReturnsTuple() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3) + .Select(tuple => + { + var (value1, value2, value3) = tuple; + return value1 + value2 + value3; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13"); + } + /// + /// Whens any value with3 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith3ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - (v1, v2, v3) => (v1, v2, v3)) - .Select(tuple => - { - var (value1, value2, value3) = tuple; - return value1 + value2 + value3; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13"); - }); + public void WhenAnyValueWith3ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + (v1, v2, v3) => (v1, v2, v3)) + .Select(tuple => + { + var (value1, value2, value3) = tuple; + return value1 + value2 + value3; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13"); + } + /// + /// Whens any value with4 paramerters returns tuple. + /// [Fact] - public async Task WhenAnyValueWith4ParamertersReturnsTuple() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4) - .Select(tuple => - { - var (value1, value2, value3, value4) = tuple; - return value1 + value2 + value3 + value4; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13"); - }); + public void WhenAnyValueWith4ParamertersReturnsTuple() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4) + .Select(tuple => + { + var (value1, value2, value3, value4) = tuple; + return value1 + value2 + value3 + value4; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13"); + } + /// + /// Whens any value with4 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith4ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - (v1, v2, v3, v4) => (v1, v2, v3, v4)) - .Select(tuple => - { - var (value1, value2, value3, value4) = tuple; - return value1 + value2 + value3 + value4; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13"); - }); + public void WhenAnyValueWith4ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + (v1, v2, v3, v4) => (v1, v2, v3, v4)) + .Select(tuple => + { + var (value1, value2, value3, value4) = tuple; + return value1 + value2 + value3 + value4; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13"); + } + /// + /// Whens any value with5 paramerters returns tuple. + /// [Fact] - public async Task WhenAnyValueWith5ParamertersReturnsTuple() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5) - .Select(tuple => - { - var (value1, value2, value3, value4, value5) = tuple; - return value1 + value2 + value3 + value4 + value5; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "135"); - }); + public void WhenAnyValueWith5ParamertersReturnsTuple() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5) + .Select(tuple => + { + var (value1, value2, value3, value4, value5) = tuple; + return value1 + value2 + value3 + value4 + value5; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "135"); + } + /// + /// Whens any value with5 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith5ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - (v1, v2, v3, v4, v5) => (v1, v2, v3, v4, v5)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5) = tuple; - return value1 + value2 + value3 + value4 + value5; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "135"); - }); + public void WhenAnyValueWith5ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + (v1, v2, v3, v4, v5) => (v1, v2, v3, v4, v5)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5) = tuple; + return value1 + value2 + value3 + value4 + value5; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "135"); + } + /// + /// Whens any value with6 paramerters returns tuple. + /// [Fact] - public async Task WhenAnyValueWith6ParamertersReturnsTuple() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "135"); - }); + public void WhenAnyValueWith6ParamertersReturnsTuple() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "135"); + } + /// + /// Whens any value with6 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith6ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - (v1, v2, v3, v4, v5, v6) => (v1, v2, v3, v4, v5, v6)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "135"); - }); + public void WhenAnyValueWith6ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + (v1, v2, v3, v4, v5, v6) => (v1, v2, v3, v4, v5, v6)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "135"); + } + /// + /// Whens any value with7 paramerters returns tuple. + /// [Fact] - public async Task WhenAnyValueWith7ParamertersReturnsTuple() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1357"); - }); + public void WhenAnyValueWith7ParamertersReturnsTuple() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1357"); + } + /// + /// Whens any value with7 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith7ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - (v1, v2, v3, v4, v5, v6, v7) => (v1, v2, v3, v4, v5, v6, v7)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1357"); - }); + public void WhenAnyValueWith7ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + (v1, v2, v3, v4, v5, v6, v7) => (v1, v2, v3, v4, v5, v6, v7)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1357"); + } + /// + /// Whens any value with8 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith8ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - x => x.Value8, - (v1, v2, v3, v4, v5, v6, v7, v8) => (v1, v2, v3, v4, v5, v6, v7, v8)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7, value8) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1357"); - }); + public void WhenAnyValueWith8ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + x => x.Value8, + (v1, v2, v3, v4, v5, v6, v7, v8) => (v1, v2, v3, v4, v5, v6, v7, v8)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7, value8) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1357"); + } + /// + /// Whens any value with8 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith9ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - x => x.Value8, - x => x.Value9, - (v1, v2, v3, v4, v5, v6, v7, v8, v9) => (v1, v2, v3, v4, v5, v6, v7, v8, v9)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7, value8, value9) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13579"); - }); + public void WhenAnyValueWith9ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + x => x.Value8, + x => x.Value9, + (v1, v2, v3, v4, v5, v6, v7, v8, v9) => (v1, v2, v3, v4, v5, v6, v7, v8, v9)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7, value8, value9) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13579"); + } + /// + /// Whens any value with8 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith10ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - x => x.Value8, - x => x.Value9, - x => x.Value10, - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "13579"); - }); + public void WhenAnyValueWith10ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + x => x.Value8, + x => x.Value9, + x => x.Value10, + (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "13579"); + } + /// + /// Whens any value with8 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith11ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - x => x.Value8, - x => x.Value9, - x => x.Value10, - x => x.Value11, - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10 + value11; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1357911"); - }); + public void WhenAnyValueWith11ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + x => x.Value8, + x => x.Value9, + x => x.Value10, + x => x.Value11, + (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10 + value11; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1357911"); + } + /// + /// Whens any value with8 paramerters returns values. + /// [Fact] - public async Task WhenAnyValueWith12ParamertersReturnsValues() => - await RunAppBuilderTestAsync(() => - { - var fixture = new WhenAnyTestFixture(); - string? result = null; - fixture.WhenAnyValue( - x => x.Value1, - x => x.Value2, - x => x.Value3, - x => x.Value4, - x => x.Value5, - x => x.Value6, - x => x.Value7, - x => x.Value8, - x => x.Value9, - x => x.Value10, - x => x.Value11, - x => x.Value12, - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)) - .Select(tuple => - { - var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11, value12) = tuple; - return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10 + value11 + value12; - }) - .Subscribe(value => result = value); - - Assert.Equal(result, "1357911"); - }); + public void WhenAnyValueWith12ParamertersReturnsValues() + { + var fixture = new WhenAnyTestFixture(); + string? result = null; + fixture.WhenAnyValue( + x => x.Value1, + x => x.Value2, + x => x.Value3, + x => x.Value4, + x => x.Value5, + x => x.Value6, + x => x.Value7, + x => x.Value8, + x => x.Value9, + x => x.Value10, + x => x.Value11, + x => x.Value12, + (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)) + .Select(tuple => + { + var (value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11, value12) = tuple; + return value1 + value2 + value3 + value4 + value5 + value6 + value7 + value8 + value9 + value10 + value11 + value12; + }) + .Subscribe(value => result = value); + + Assert.Equal(result, "1357911"); + } [Fact] - public async Task WhenAnyValueWithToProperty() => - await RunAppBuilderTestAsync(() => - { - var fixture = new HostTestFixture(); + public void WhenAnyValueWithToProperty() + { + var fixture = new HostTestFixture(); - Assert.Equal(null, fixture.Owner); - Assert.Equal(null, fixture.OwnerName); + Assert.Equal(null, fixture.Owner); + Assert.Equal(null, fixture.OwnerName); - fixture.Owner = new() - { - Name = "Fred" - }; - Assert.NotNull(fixture.Owner); - Assert.Equal("Fred", fixture.OwnerName); + fixture.Owner = new() + { + Name = "Fred" + }; + Assert.NotNull(fixture.Owner); + Assert.Equal("Fred", fixture.OwnerName); - fixture.Owner.Name = "Wilma"; - Assert.Equal("Wilma", fixture.OwnerName); + fixture.Owner.Name = "Wilma"; + Assert.Equal("Wilma", fixture.OwnerName); - fixture.Owner.Name = null; - Assert.Equal(null, fixture.OwnerName); + fixture.Owner.Name = null; + Assert.Equal(null, fixture.OwnerName); - fixture.Owner.Name = "Barney"; - Assert.Equal("Barney", fixture.OwnerName); + fixture.Owner.Name = "Barney"; + Assert.Equal("Barney", fixture.OwnerName); - fixture.Owner.Name = "Betty"; - Assert.Equal("Betty", fixture.OwnerName); - }); + fixture.Owner.Name = "Betty"; + Assert.Equal("Betty", fixture.OwnerName); + } } diff --git a/src/ReactiveUI.Tests/WhenAny/WhenAnyObservableTests.cs b/src/ReactiveUI.Tests/WhenAny/WhenAnyObservableTests.cs index 3533efec0d..7cc84b06e5 100644 --- a/src/ReactiveUI.Tests/WhenAny/WhenAnyObservableTests.cs +++ b/src/ReactiveUI.Tests/WhenAny/WhenAnyObservableTests.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.Tests; /// /// Tests WhenAnyObservable. /// -public class WhenAnyObservableTests : AppBuilderTestBase +public class WhenAnyObservableTests { /// /// Tests that null observables do not cause exceptions. diff --git a/src/ReactiveUI.Tests/xunit.runner.json b/src/ReactiveUI.Tests/xunit.runner.json index d29baba233..503b7481f6 100644 --- a/src/ReactiveUI.Tests/xunit.runner.json +++ b/src/ReactiveUI.Tests/xunit.runner.json @@ -1,6 +1,4 @@ { "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", - "parallelizeAssembly": false, - "parallelizeTestCollections": false, - "maxParallelThreads": 1 + "parallelAlgorithm": "aggressive" } From 60989f1c8251c18c6f934fbc7f736686b731941c Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Thu, 28 Aug 2025 23:12:13 +0100 Subject: [PATCH 11/11] DisableTestParallelization in all tests --- src/Directory.Packages.props | 10 +++++----- src/ReactiveUI.AOTTests/TestConfiguration.cs | 6 ++++++ src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs | 6 ++++++ src/ReactiveUI.Builder.Tests/TestConfiguration.cs | 6 ++++++ src/ReactiveUI.Splat.Tests/TestConfiguration.cs | 8 ++++++++ src/ReactiveUI.Testing.Tests/TestConfiguration.cs | 8 ++++++++ 6 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 src/ReactiveUI.AOTTests/TestConfiguration.cs create mode 100644 src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs create mode 100644 src/ReactiveUI.Builder.Tests/TestConfiguration.cs create mode 100644 src/ReactiveUI.Splat.Tests/TestConfiguration.cs create mode 100644 src/ReactiveUI.Testing.Tests/TestConfiguration.cs diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 4dc4254862..c2542f28fa 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -18,7 +18,7 @@ - + @@ -35,10 +35,10 @@ - + - + @@ -58,8 +58,8 @@ - - + + diff --git a/src/ReactiveUI.AOTTests/TestConfiguration.cs b/src/ReactiveUI.AOTTests/TestConfiguration.cs new file mode 100644 index 0000000000..75129f413a --- /dev/null +++ b/src/ReactiveUI.AOTTests/TestConfiguration.cs @@ -0,0 +1,6 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs b/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs new file mode 100644 index 0000000000..75129f413a --- /dev/null +++ b/src/ReactiveUI.Builder.Maui.Tests/TestConfiguration.cs @@ -0,0 +1,6 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Builder.Tests/TestConfiguration.cs b/src/ReactiveUI.Builder.Tests/TestConfiguration.cs new file mode 100644 index 0000000000..75129f413a --- /dev/null +++ b/src/ReactiveUI.Builder.Tests/TestConfiguration.cs @@ -0,0 +1,6 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Splat.Tests/TestConfiguration.cs b/src/ReactiveUI.Splat.Tests/TestConfiguration.cs new file mode 100644 index 0000000000..cb03654b65 --- /dev/null +++ b/src/ReactiveUI.Splat.Tests/TestConfiguration.cs @@ -0,0 +1,8 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] diff --git a/src/ReactiveUI.Testing.Tests/TestConfiguration.cs b/src/ReactiveUI.Testing.Tests/TestConfiguration.cs new file mode 100644 index 0000000000..cb03654b65 --- /dev/null +++ b/src/ReactiveUI.Testing.Tests/TestConfiguration.cs @@ -0,0 +1,8 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)]