diff --git a/src/Controls/tests/Core.UnitTests/BindableLayoutTests.cs b/src/Controls/tests/Core.UnitTests/BindableLayoutTests.cs index 650b190333ea..6621947e5018 100644 --- a/src/Controls/tests/Core.UnitTests/BindableLayoutTests.cs +++ b/src/Controls/tests/Core.UnitTests/BindableLayoutTests.cs @@ -625,17 +625,8 @@ public async Task DoesNotLeak() proxyRef = new WeakReference(proxy); } - // First GC - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - Assert.False(controllerRef.IsAlive, "BindableLayoutController should not be alive!"); - - // Second GC - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - Assert.False(proxyRef.IsAlive, "WeakCollectionChangedProxy should not be alive!"); + Assert.False(await controllerRef.WaitForCollect(), "BindableLayoutController should not be alive!"); + Assert.False(await proxyRef.WaitForCollect(), "WeakCollectionChangedProxy should not be alive!"); } [Fact("BindableLayout Still Updates after a GC")] @@ -648,9 +639,7 @@ public async Task UpdatesAfterGC() Assert.Equal(2, layout.Children.Count); - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + await TestHelpers.Collect(); list.Add("Baz"); Assert.Equal(3, layout.Children.Count); diff --git a/src/Controls/tests/Core.UnitTests/BindingUnitTests.cs b/src/Controls/tests/Core.UnitTests/BindingUnitTests.cs index 42eb82cacb8c..f505eec996df 100644 --- a/src/Controls/tests/Core.UnitTests/BindingUnitTests.cs +++ b/src/Controls/tests/Core.UnitTests/BindingUnitTests.cs @@ -1245,24 +1245,15 @@ void create() ; create(); - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - if (mode == BindingMode.TwoWay || mode == BindingMode.OneWay) - Assert.False(weakViewModel.IsAlive, "ViewModel wasn't collected"); + Assert.False(await weakViewModel.WaitForCollect(), "ViewModel wasn't collected"); if (mode == BindingMode.TwoWay || mode == BindingMode.OneWayToSource) - Assert.False(weakBindable.IsAlive, "Bindable wasn't collected"); - - // WeakPropertyChangedProxy won't go away until the second GC, BindingExpressionPart unsubscribes in its finalizer - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + Assert.False(await weakBindable.WaitForCollect(), "Bindable wasn't collected"); foreach (var proxy in proxies) { - Assert.False(proxy.IsAlive, "WeakPropertyChangedProxy wasn't collected"); + Assert.False(await proxy.WaitForCollect(), "WeakPropertyChangedProxy wasn't collected"); } } diff --git a/src/Controls/tests/Core.UnitTests/SetterSpecificityListTests.cs b/src/Controls/tests/Core.UnitTests/SetterSpecificityListTests.cs index 3ba8a3e4f80c..d54cde3f52aa 100644 --- a/src/Controls/tests/Core.UnitTests/SetterSpecificityListTests.cs +++ b/src/Controls/tests/Core.UnitTests/SetterSpecificityListTests.cs @@ -36,42 +36,34 @@ public async Task RemovingValueDoesNotLeak() var list = new SetterSpecificityList(); list[SetterSpecificity.DefaultValue] = nameof(SetterSpecificity.DefaultValue); list[SetterSpecificity.FromHandler] = nameof(SetterSpecificity.FromHandler); - WeakReference weakReference; + WeakReference weakReference; { var o = new object(); - weakReference = new WeakReference(o); + weakReference = new WeakReference(o); list[SetterSpecificity.FromBinding] = o; } list.Remove(SetterSpecificity.FromBinding); - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - - Assert.False(weakReference.TryGetTarget(out _)); + Assert.False(await weakReference.WaitForCollect()); } [Fact] public async Task RemovingLastValueDoesNotLeak() { var list = new SetterSpecificityList(); - WeakReference weakReference; + WeakReference weakReference; { var o = new object(); - weakReference = new WeakReference(o); + weakReference = new WeakReference(o); list[SetterSpecificity.ManualValueSetter] = o; } list.Remove(SetterSpecificity.ManualValueSetter); - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - - Assert.False(weakReference.TryGetTarget(out _)); + Assert.False(await weakReference.WaitForCollect()); } [Fact] diff --git a/src/Controls/tests/Core.UnitTests/TestHelpers.cs b/src/Controls/tests/Core.UnitTests/TestHelpers.cs index 7bfc4b1c7c9d..aa8a2b1efa53 100644 --- a/src/Controls/tests/Core.UnitTests/TestHelpers.cs +++ b/src/Controls/tests/Core.UnitTests/TestHelpers.cs @@ -10,6 +10,10 @@ public static async Task Collect() await Task.Yield(); GC.Collect(); GC.WaitForPendingFinalizers(); + GC.Collect(2, GCCollectionMode.Forced, true); + GC.WaitForPendingFinalizers(); + GC.Collect(2, GCCollectionMode.Forced, true); + await Task.Yield(); } @@ -17,12 +21,10 @@ public static async Task WaitForCollect(this WeakReference reference) { for (int i = 0; i < 40 && reference.IsAlive; i++) { - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + await Collect(); } return reference.IsAlive; } } -} +} \ No newline at end of file diff --git a/src/Controls/tests/Core.UnitTests/TypedBindingUnitTests.cs b/src/Controls/tests/Core.UnitTests/TypedBindingUnitTests.cs index b8ab5768bd2f..5fbf2f11f096 100644 --- a/src/Controls/tests/Core.UnitTests/TypedBindingUnitTests.cs +++ b/src/Controls/tests/Core.UnitTests/TypedBindingUnitTests.cs @@ -1437,16 +1437,12 @@ public async Task BindingUnsubscribesForDeadTarget() Assert.Equal(1, viewmodel.InvocationListSize()); - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + Assert.False(await bindingRef.WaitForCollect(), "Binding should not be alive!"); + Assert.False(await buttonRef.WaitForCollect(), "Button should not be alive!"); viewmodel.OnPropertyChanged("Foo"); Assert.Equal(0, viewmodel.InvocationListSize()); - - Assert.False(bindingRef.IsAlive, "Binding should not be alive!"); - Assert.False(buttonRef.IsAlive, "Button should not be alive!"); } [Fact] @@ -1491,18 +1487,11 @@ public async Task BindingDoesNotStayAliveForDeadTarget() Assert.Equal(1, viewModel.InvocationListSize()); - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - - Assert.False(bindingRef.IsAlive, "Binding should not be alive!"); - Assert.False(buttonRef.IsAlive, "Button should not be alive!"); + Assert.False(await bindingRef.WaitForCollect(), "Binding should not be alive!"); + Assert.False(await buttonRef.WaitForCollect(), "Button should not be alive!"); // WeakPropertyChangedProxy won't go away until the second GC, PropertyChangedProxy unsubscribes in its finalizer - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - Assert.False(proxyRef.IsAlive, "WeakPropertyChangedProxy should not be alive!"); + Assert.False(await proxyRef.WaitForCollect(), "WeakPropertyChangedProxy should not be alive!"); } [Fact] diff --git a/src/Controls/tests/Core.UnitTests/VisualElementTests.cs b/src/Controls/tests/Core.UnitTests/VisualElementTests.cs index 8ddabfbc1d12..73ccf71b8fd2 100644 --- a/src/Controls/tests/Core.UnitTests/VisualElementTests.cs +++ b/src/Controls/tests/Core.UnitTests/VisualElementTests.cs @@ -154,9 +154,7 @@ public async Task GradientBrushSubscribed() fired = true; }; - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + await TestHelpers.Collect(); GC.KeepAlive(visual); gradient.GradientStops.Add(new GradientStop(Colors.CornflowerBlue, 1)); @@ -187,9 +185,7 @@ public async Task RectangleGeometrySubscribed() fired = true; }; - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + await TestHelpers.Collect(); GC.KeepAlive(visual); geometry.Rect = new Rect(1, 2, 3, 4); @@ -209,9 +205,7 @@ public async Task ShadowSubscribed() fired = true; }; - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + await TestHelpers.Collect(); GC.KeepAlive(visualElement); shadow.Brush = new SolidColorBrush(Colors.Green); @@ -230,11 +224,7 @@ public async Task ShadowDoesNotLeak() var reference = new WeakReference(new VisualElement { Shadow = shadow }); - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - - Assert.False(reference.IsAlive, "VisualElement should not be alive!"); + Assert.False(await reference.WaitForCollect(), "VisualElement should not be alive!"); } [Fact] diff --git a/src/Controls/tests/Core.UnitTests/WeakEventProxyTests.cs b/src/Controls/tests/Core.UnitTests/WeakEventProxyTests.cs index a4eb25eca416..c14e846af76f 100644 --- a/src/Controls/tests/Core.UnitTests/WeakEventProxyTests.cs +++ b/src/Controls/tests/Core.UnitTests/WeakEventProxyTests.cs @@ -22,11 +22,7 @@ public async Task DoesNotLeak() reference = new WeakReference(subscriber); } - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - - Assert.False(reference.IsAlive, "Subscriber should not be alive!"); + Assert.False(await reference.WaitForCollect(), "Subscriber should not be alive!"); } [Fact] @@ -40,9 +36,7 @@ public async Task EventFires() NotifyCollectionChangedEventHandler handler = (s, e) => fired = true; proxy.Subscribe(list, handler); - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + await TestHelpers.Collect(); GC.KeepAlive(handler); list.Add("a"); diff --git a/src/Controls/tests/Core.UnitTests/WindowsTests.cs b/src/Controls/tests/Core.UnitTests/WindowsTests.cs index 5d7f16b843ca..3f9599e00ec4 100644 --- a/src/Controls/tests/Core.UnitTests/WindowsTests.cs +++ b/src/Controls/tests/Core.UnitTests/WindowsTests.cs @@ -756,9 +756,7 @@ public async Task TwoKeysSameWindow() } // GC collect the original key - await Task.Yield(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + await TestHelpers.Collect(); // Same window, doesn't create a new one var actual = ((IApplication)application).CreateWindow(new ActivationState(new MockMauiContext(), new PersistedState