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
pull/1038/head
Steven Kirk 9 years ago
parent
commit
7baa7dc0dd
  1. 40
      tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs
  2. 9
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_DataValidation.cs
  3. 44
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Indexer.cs
  4. 12
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Observable.cs
  5. 59
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Property.cs
  6. 12
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Task.cs

40
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
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
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
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
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
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);
}
}

Loading…
Cancel
Save