Browse Source

another simple unit tests for issue #855 for direct and styled properties

pull/856/head
donandren 10 years ago
parent
commit
ef81c55960
  1. 4
      tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj
  2. 103
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
  3. 106
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs

4
tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj

@ -124,6 +124,10 @@
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Avalonia.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
<Project>{3E53A01A-B331-47F3-B828-4A5717E77A24}</Project>
<Name>Avalonia.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\Avalonia.UnitTests\Avalonia.UnitTests.csproj">
<Project>{88060192-33d5-4932-b0f9-8bd2763e857d}</Project>
<Name>Avalonia.UnitTests</Name>

103
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs

@ -2,22 +2,21 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Microsoft.Reactive.Testing;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Data;
using Avalonia.Logging;
using Avalonia.UnitTests;
using Xunit;
using System.Threading.Tasks;
using Avalonia.Markup.Xaml.Data;
using Avalonia.Platform;
using System.Threading;
using Moq;
using System.Reactive.Disposables;
using System.Reactive.Concurrency;
using Avalonia.Threading;
using Avalonia.UnitTests;
using Microsoft.Reactive.Testing;
using Moq;
using Xunit;
namespace Avalonia.Base.UnitTests
{
@ -363,7 +362,7 @@ namespace Avalonia.Base.UnitTests
Assert.True(called);
}
}
[Fact]
public async void Bind_With_Scheduler_Executes_On_Scheduler()
{
@ -384,7 +383,43 @@ namespace Avalonia.Base.UnitTests
await Task.Run(() => source.OnNext(6.7));
}
}
[Fact]
public void SetValue_Should_Not_Cause_StackOverflow_And_Have_Correct_Values()
{
var viewModel = new TestStackOverflowViewModel()
{
Value = 50
};
var target = new Class1();
//note: if the initialization of the child binding is here target/child binding work fine!!!
//var child = new Class1()
//{
// [~~Class1.DoubleValueProperty] = target[~~Class1.DoubleValueProperty]
//};
target.Bind(Class1.DoubleValueProperty, new Binding("Value") { Mode = BindingMode.TwoWay, Source = viewModel });
var child = new Class1()
{
[~~Class1.DoubleValueProperty] = target[~~Class1.DoubleValueProperty]
};
Assert.Equal(1, viewModel.SetterInvokedCount);
//here in real life stack overflow exception is thrown issue #855 and #824
target.DoubleValue = 51.001;
Assert.Equal(2, viewModel.SetterInvokedCount);
double expected = 51;
Assert.Equal(expected, viewModel.Value);
Assert.Equal(expected, target.DoubleValue);
Assert.Equal(expected, child.DoubleValue);
}
/// <summary>
@ -405,6 +440,15 @@ namespace Avalonia.Base.UnitTests
public static readonly StyledProperty<double> QuxProperty =
AvaloniaProperty.Register<Class1, double>("Qux", 5.6);
public static readonly StyledProperty<double> DoubleValueProperty =
AvaloniaProperty.Register<Class1, double>(nameof(DoubleValue));
public double DoubleValue
{
get { return GetValue(DoubleValueProperty); }
set { SetValue(DoubleValueProperty, value); }
}
}
private class Class2 : Class1
@ -431,5 +475,40 @@ namespace Avalonia.Base.UnitTests
return new InstancedBinding(_source, BindingMode.OneTime);
}
}
private class TestStackOverflowViewModel : INotifyPropertyChanged
{
public int SetterInvokedCount { get; private set; }
public const int MaxInvokedCount = 1000;
private double _value;
public event PropertyChangedEventHandler PropertyChanged;
public double Value
{
get { return _value; }
set
{
if (_value != value)
{
SetterInvokedCount++;
if (SetterInvokedCount < MaxInvokedCount)
{
_value = (int)value;
if (_value > 75) _value = 75;
if (_value < 25) _value = 25;
}
else
{
_value = value;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
}
}
}
}
}
}
}

106
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs

@ -3,10 +3,11 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reactive.Subjects;
using Avalonia;
using Avalonia.Data;
using Avalonia.Logging;
using Avalonia.Markup.Xaml.Data;
using Avalonia.UnitTests;
using Xunit;
@ -208,7 +209,7 @@ namespace Avalonia.Base.UnitTests
{
var target = new Class1();
Assert.Throws<ArgumentException>(() =>
Assert.Throws<ArgumentException>(() =>
target.SetValue(Class1.BarProperty, "newvalue"));
}
@ -217,7 +218,7 @@ namespace Avalonia.Base.UnitTests
{
var target = new Class1();
Assert.Throws<ArgumentException>(() =>
Assert.Throws<ArgumentException>(() =>
target.SetValue((AvaloniaProperty)Class1.BarProperty, "newvalue"));
}
@ -227,7 +228,7 @@ namespace Avalonia.Base.UnitTests
var target = new Class1();
var source = new Subject<string>();
Assert.Throws<ArgumentException>(() =>
Assert.Throws<ArgumentException>(() =>
target.Bind(Class1.BarProperty, source));
}
@ -439,12 +440,49 @@ namespace Avalonia.Base.UnitTests
Assert.Equal(BindingMode.OneWayToSource, bar.GetMetadata<Class2>().DefaultBindingMode);
}
[Fact]
public void SetValue_Should_Not_Cause_StackOverflow_And_Have_Correct_Values()
{
var viewModel = new TestStackOverflowViewModel()
{
Value = 50
};
var target = new Class1();
//note: if the initialization of the child binding is here there is no stackoverflow!!!
//var child = new Class1()
//{
// [~~Class1.DoubleValueProperty] = target[~~Class1.DoubleValueProperty]
//};
target.Bind(Class1.DoubleValueProperty, new Binding("Value") { Mode = BindingMode.TwoWay, Source = viewModel });
var child = new Class1()
{
[~~Class1.DoubleValueProperty] = target[~~Class1.DoubleValueProperty]
};
Assert.Equal(1, viewModel.SetterInvokedCount);
//here in real life stack overflow exception is thrown issue #855 and #824
target.DoubleValue = 51.001;
Assert.Equal(2, viewModel.SetterInvokedCount);
double expected = 51;
Assert.Equal(expected, viewModel.Value);
Assert.Equal(expected, target.DoubleValue);
Assert.Equal(expected, child.DoubleValue);
}
private class Class1 : AvaloniaObject
{
public static readonly DirectProperty<Class1, string> FooProperty =
AvaloniaProperty.RegisterDirect<Class1, string>(
"Foo",
o => o.Foo,
"Foo",
o => o.Foo,
(o, v) => o.Foo = v,
unsetValue: "unset");
@ -453,14 +491,21 @@ namespace Avalonia.Base.UnitTests
public static readonly DirectProperty<Class1, int> BazProperty =
AvaloniaProperty.RegisterDirect<Class1, int>(
"Bar",
o => o.Baz,
(o,v) => o.Baz = v,
"Bar",
o => o.Baz,
(o, v) => o.Baz = v,
unsetValue: -1);
public static readonly DirectProperty<Class1, double> DoubleValueProperty =
AvaloniaProperty.RegisterDirect<Class1, double>(
nameof(DoubleValue),
o => o.DoubleValue,
(o, v) => o.DoubleValue = v);
private string _foo = "initial";
private readonly string _bar = "bar";
private int _baz = 5;
private double _doubleValue;
public string Foo
{
@ -478,6 +523,12 @@ namespace Avalonia.Base.UnitTests
get { return _baz; }
set { SetAndRaise(BazProperty, ref _baz, value); }
}
public double DoubleValue
{
get { return _doubleValue; }
set { SetAndRaise(DoubleValueProperty, ref _doubleValue, value); }
}
}
private class Class2 : AvaloniaObject
@ -497,5 +548,40 @@ namespace Avalonia.Base.UnitTests
set { SetAndRaise(FooProperty, ref _foo, value); }
}
}
private class TestStackOverflowViewModel : INotifyPropertyChanged
{
public int SetterInvokedCount { get; private set; }
public const int MaxInvokedCount = 1000;
private double _value;
public event PropertyChangedEventHandler PropertyChanged;
public double Value
{
get { return _value; }
set
{
if (_value != value)
{
SetterInvokedCount++;
if (SetterInvokedCount < MaxInvokedCount)
{
_value = (int)value;
if (_value > 75) _value = 75;
if (_value < 25) _value = 25;
}
else
{
_value = value;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
}
}
}
}
}
}
}
Loading…
Cancel
Save