Browse Source

Added GC.KeepAlive to tests.

Lots of `Avalonia.Markup.UnitTests` were failing intermittently. This is because in release mode, in a method like this:

```
[Fact]
public void SetValue_Should_Return_False_For_Missing_Object()
{
	var data = new Class1();
	var target = new ExpressionObserver(data, "Next.Bar");

	using (target.Subscribe(_ => { }))
	{
		Assert.False(target.SetValue("baz"));
	}
}
```

`data` can get GC'ed at any point after creating target. Added `GC.KeepAlive()` calls to prevent this.

Fixes #1035
Fixes #1036
Fixes #1037
Steven Kirk 8 years ago
parent
commit
7baa7dc0dd

+ 40 - 0
tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs

@@ -25,6 +25,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal("foo", result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -36,6 +38,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.OnNext("bar");
 
             Assert.Equal("bar", data.StringValue);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -47,6 +51,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.OnNext("bar");
 
             Assert.Equal("bar", data.Foo[0]);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -57,6 +63,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(5.6, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -67,6 +75,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.IsType<BindingNotification>(result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -77,6 +87,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -88,6 +100,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.OnNext(6.7);
 
             Assert.Equal((6.7).ToString(), data.StringValue);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -98,6 +112,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal((5.6).ToString(), result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -109,6 +125,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.OnNext("6.7");
 
             Assert.Equal(6.7, data.DoubleValue);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -128,6 +146,8 @@ namespace Avalonia.Markup.UnitTests.Data
                     BindingErrorType.Error,
                     42),
                 result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -147,6 +167,8 @@ namespace Avalonia.Markup.UnitTests.Data
                     BindingErrorType.Error,
                     42),
                 result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact(Skip="Result is not always AggregateException.")]
@@ -167,6 +189,8 @@ namespace Avalonia.Markup.UnitTests.Data
                         new InvalidCastException("Could not convert FallbackValue 'bar' to 'System.Int32'")),
                     BindingErrorType.Error),
                 result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact(Skip="Result is not always AggregateException.")]
@@ -187,6 +211,8 @@ namespace Avalonia.Markup.UnitTests.Data
                         new InvalidCastException("Could not convert FallbackValue 'bar' to 'System.Int32'")),
                     BindingErrorType.Error),
                 result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -198,6 +224,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.OnNext("foo");
 
             Assert.Equal(5.6, data.DoubleValue);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -213,6 +241,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.OnNext("foo");
 
             Assert.Equal(9.8, data.DoubleValue);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -224,6 +254,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.OnNext(null);
 
             Assert.Equal(0, data.DoubleValue);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -235,6 +267,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.OnNext(AvaloniaProperty.UnsetValue);
 
             Assert.Equal(0, data.DoubleValue);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -252,6 +286,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.Subscribe(_ => { });
 
             converter.Verify(x => x.Convert(5.6, typeof(string), "foo", CultureInfo.CurrentCulture));
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -268,6 +304,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.OnNext("bar");
 
             converter.Verify(x => x.ConvertBack("bar", typeof(double), "foo", CultureInfo.CurrentCulture));
+
+            GC.KeepAlive(data);
         }
 
         [Fact(Skip="Moq.MockException")]
@@ -294,6 +332,8 @@ namespace Avalonia.Markup.UnitTests.Data
                         BindingErrorType.Error)
                 },
                 result);
+
+            GC.KeepAlive(data);
         }
 
         private class Class1 : NotifyingBase

+ 9 - 0
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_DataValidation.cs

@@ -28,6 +28,8 @@ namespace Avalonia.Markup.UnitTests.Data
             observer.SetValue(-5);
 
             Assert.False(validationMessageFound);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -43,6 +45,8 @@ namespace Avalonia.Markup.UnitTests.Data
             observer.SetValue(-5);
 
             Assert.True(validationMessageFound);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -102,6 +106,8 @@ namespace Avalonia.Markup.UnitTests.Data
                 new BindingNotification(new Exception("Must be positive"), BindingErrorType.DataValidationError, 5),
                 new BindingNotification(5),
             }, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -147,6 +153,9 @@ namespace Avalonia.Markup.UnitTests.Data
                     BindingErrorType.Error,
                     AvaloniaProperty.UnsetValue),
             }, result);
+
+            GC.KeepAlive(container);
+            GC.KeepAlive(inner);
         }
 
         public class ExceptionTest : NotifyingBase

+ 44 - 0
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Indexer.cs

@@ -24,6 +24,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal("bar", result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -34,6 +36,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -44,6 +48,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -54,6 +60,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -64,6 +72,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal("qux", result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -74,6 +84,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal("bar", result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -84,6 +96,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal("bar", result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -94,6 +108,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -104,6 +120,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -114,6 +132,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -124,6 +144,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal("bar", result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -140,6 +162,8 @@ namespace Avalonia.Markup.UnitTests.Data
 
             Assert.Equal(new[] { AvaloniaProperty.UnsetValue, "baz" }, result);
             Assert.Null(((INotifyCollectionChangedDebug)data.Foo).GetCollectionChangedSubscribers());
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -156,6 +180,8 @@ namespace Avalonia.Markup.UnitTests.Data
 
             Assert.Equal(new[] { "foo", "bar" }, result);
             Assert.Null(((INotifyCollectionChangedDebug)data.Foo).GetCollectionChangedSubscribers());
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -172,6 +198,8 @@ namespace Avalonia.Markup.UnitTests.Data
 
             Assert.Equal(new[] { "bar", "baz" }, result);
             Assert.Null(((INotifyCollectionChangedDebug)data.Foo).GetCollectionChangedSubscribers());
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -188,6 +216,9 @@ namespace Avalonia.Markup.UnitTests.Data
             data.Foo.Move(0, 1);
 
             Assert.Equal(new[] { "bar", "foo" }, result);
+
+            GC.KeepAlive(sub);
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -201,6 +232,9 @@ namespace Avalonia.Markup.UnitTests.Data
             data.Foo.Clear();
 
             Assert.Equal(new[] { "bar", AvaloniaProperty.UnsetValue }, result);
+
+            GC.KeepAlive(sub);
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -221,6 +255,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var expected = new[] { "bar", "bar2" };
             Assert.Equal(expected, result);
             Assert.Equal(0, data.Foo.PropertyChangedSubscriptionCount);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -235,6 +271,8 @@ namespace Avalonia.Markup.UnitTests.Data
             }
 
             Assert.Equal("baz", data.Foo[1]);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -255,6 +293,8 @@ namespace Avalonia.Markup.UnitTests.Data
             }
 
             Assert.Equal(4, data.Foo["foo"]);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -275,6 +315,8 @@ namespace Avalonia.Markup.UnitTests.Data
             }
 
             Assert.Equal(4, data.Foo["bar"]);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -292,6 +334,8 @@ namespace Avalonia.Markup.UnitTests.Data
             }
             
             Assert.Equal("bar2", data.Foo["foo"]);
+
+            GC.KeepAlive(data);
         }
 
         private class NonIntegerIndexer : NotifyingBase

+ 12 - 0
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Observable.cs

@@ -29,6 +29,8 @@ namespace Avalonia.Markup.UnitTests.Data
                 sync.ExecutePostedCallbacks();
 
                 Assert.Equal(new[] { source }, result);
+
+                GC.KeepAlive(data);
             }
         }
 
@@ -47,6 +49,8 @@ namespace Avalonia.Markup.UnitTests.Data
                 sync.ExecutePostedCallbacks();
 
                 Assert.Equal(new[] { "foo", "bar" }, result);
+
+                GC.KeepAlive(data);
             }
         }
 
@@ -67,6 +71,8 @@ namespace Avalonia.Markup.UnitTests.Data
 
                 sub.Dispose();
                 Assert.Equal(0, data.PropertyChangedSubscriptionCount);
+
+                GC.KeepAlive(data);
             }
         }
 
@@ -87,6 +93,8 @@ namespace Avalonia.Markup.UnitTests.Data
                 // What does it mean to have data validation on an observable? Without a use-case
                 // it's hard to know what to do here so for the moment the value is returned.
                 Assert.Equal(new[] { "foo", "bar" }, result);
+
+                GC.KeepAlive(data);
             }
         }
 
@@ -107,6 +115,8 @@ namespace Avalonia.Markup.UnitTests.Data
 
                 sub.Dispose();
                 Assert.Equal(0, data.PropertyChangedSubscriptionCount);
+
+                GC.KeepAlive(data);
             }
         }
 
@@ -132,6 +142,8 @@ namespace Avalonia.Markup.UnitTests.Data
                     result);
 
                 sub.Dispose();
+
+                GC.KeepAlive(data);
             }
         }
 

+ 59 - 0
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Property.cs

@@ -25,6 +25,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal("foo", result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -36,6 +38,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.Subscribe(_ => { });
 
             Assert.Equal(typeof(string), target.ResultType);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -46,6 +50,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Null(result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -56,6 +62,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal("foo", result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -66,6 +74,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -76,6 +86,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -86,6 +98,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -96,6 +110,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal(AvaloniaProperty.UnsetValue, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -106,6 +122,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var result = await target.Take(1);
 
             Assert.Equal("baz", result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -117,6 +135,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.Subscribe(_ => { });
 
             Assert.Equal(typeof(string), target.ResultType);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -132,6 +152,8 @@ namespace Avalonia.Markup.UnitTests.Data
                 new BindingNotification(
                     new MissingMemberException("Could not find CLR property 'Baz' on '1'"), BindingErrorType.Error),
                 result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -152,6 +174,8 @@ namespace Avalonia.Markup.UnitTests.Data
                         AvaloniaProperty.UnsetValue),
                 },
                 result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -161,6 +185,8 @@ namespace Avalonia.Markup.UnitTests.Data
             var target = new ExpressionObserver(data, "Foo.Bar.Baz");
 
             Assert.Null(target.ResultType);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -178,6 +204,8 @@ namespace Avalonia.Markup.UnitTests.Data
             sub.Dispose();
 
             Assert.Equal(0, data.PropertyChangedSubscriptionCount);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -206,6 +234,8 @@ namespace Avalonia.Markup.UnitTests.Data
             sub.Dispose();
 
             Assert.Equal(0, data.PropertyChangedSubscriptionCount);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -225,6 +255,8 @@ namespace Avalonia.Markup.UnitTests.Data
 
             Assert.Equal(0, data.PropertyChangedSubscriptionCount);
             Assert.Equal(0, data.Next.PropertyChangedSubscriptionCount);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -246,6 +278,8 @@ namespace Avalonia.Markup.UnitTests.Data
             Assert.Equal(0, data.PropertyChangedSubscriptionCount);
             Assert.Equal(0, data.Next.PropertyChangedSubscriptionCount);
             Assert.Equal(0, old.PropertyChangedSubscriptionCount);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -287,6 +321,8 @@ namespace Avalonia.Markup.UnitTests.Data
             Assert.Equal(0, data.PropertyChangedSubscriptionCount);
             Assert.Equal(0, data.Next.PropertyChangedSubscriptionCount);
             Assert.Equal(0, old.PropertyChangedSubscriptionCount);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -319,6 +355,8 @@ namespace Avalonia.Markup.UnitTests.Data
             Assert.Equal(0, data.Next.PropertyChangedSubscriptionCount);
             Assert.Equal(0, breaking.PropertyChangedSubscriptionCount);
             Assert.Equal(0, old.PropertyChangedSubscriptionCount);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -335,6 +373,8 @@ namespace Avalonia.Markup.UnitTests.Data
             update.OnNext(Unit.Default);
 
             Assert.Equal(new[] { "foo", "bar" }, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -375,6 +415,8 @@ namespace Avalonia.Markup.UnitTests.Data
             Assert.Equal(new[] { "foo", "bar" }, result1);
             Assert.Equal(new[] { "foo", "bar" }, result2);
             Assert.Equal(new[] { "bar" }, result3);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -392,6 +434,8 @@ namespace Avalonia.Markup.UnitTests.Data
             sub2.Dispose();
 
             Assert.Equal(0, data.PropertyChangedSubscriptionCount);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -406,6 +450,8 @@ namespace Avalonia.Markup.UnitTests.Data
             }
 
             Assert.Equal("bar", data.Foo);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -420,6 +466,8 @@ namespace Avalonia.Markup.UnitTests.Data
             }
 
             Assert.Equal("baz", ((Class2)data.Next).Bar);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -432,6 +480,8 @@ namespace Avalonia.Markup.UnitTests.Data
             {
                 Assert.False(target.SetValue("baz"));
             }
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -445,6 +495,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.SetValue("bar");
 
             Assert.Equal(new[] { null, "bar" }, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -458,6 +510,8 @@ namespace Avalonia.Markup.UnitTests.Data
             target.SetValue("bar");
 
             Assert.Equal(new[] { null, "bar" }, result);
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -470,6 +524,8 @@ namespace Avalonia.Markup.UnitTests.Data
             {
                 Assert.False(target.SetValue("baz"));
             }
+
+            GC.KeepAlive(data);
         }
 
         [Fact]
@@ -499,6 +555,9 @@ namespace Avalonia.Markup.UnitTests.Data
 
             Assert.Equal(0, first.PropertyChangedSubscriptionCount);
             Assert.Equal(0, second.PropertyChangedSubscriptionCount);
+
+            GC.KeepAlive(first);
+            GC.KeepAlive(second);
         }
 
         [Fact]

+ 12 - 0
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Task.cs

@@ -30,6 +30,8 @@ namespace Avalonia.Markup.UnitTests.Data
 
                 Assert.Equal(1, result.Count);
                 Assert.IsType<Task<string>>(result[0]);
+
+                GC.KeepAlive(data);
             }
         }
 
@@ -45,6 +47,8 @@ namespace Avalonia.Markup.UnitTests.Data
                 var sub = target.Subscribe(x => result.Add(x));
 
                 Assert.Equal(new[] { "foo" }, result);
+
+                GC.KeepAlive(data);
             }
         }
 
@@ -63,6 +67,8 @@ namespace Avalonia.Markup.UnitTests.Data
                 sync.ExecutePostedCallbacks();
 
                 Assert.Equal(new[] { "foo" }, result);
+
+                GC.KeepAlive(data);
             }
         }
 
@@ -88,6 +94,8 @@ namespace Avalonia.Markup.UnitTests.Data
                             BindingErrorType.Error)
                     }, 
                     result);
+
+                GC.KeepAlive(data);
             }
         }
 
@@ -110,6 +118,8 @@ namespace Avalonia.Markup.UnitTests.Data
                             BindingErrorType.Error)
                     },
                     result);
+
+                GC.KeepAlive(data);
             }
         }
 
@@ -130,6 +140,8 @@ namespace Avalonia.Markup.UnitTests.Data
                 // What does it mean to have data validation on a Task? Without a use-case it's
                 // hard to know what to do here so for the moment the value is returned.
                 Assert.Equal(new [] { "foo" }, result);
+
+                GC.KeepAlive(data);
             }
         }