10 changed files with 903 additions and 699 deletions
@ -1,698 +0,0 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PerspexObjectTests.cs" company="Steven Kirk">
|
|||
// Copyright 2013 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Base.UnitTests |
|||
{ |
|||
using System; |
|||
using System.Linq; |
|||
using System.Reactive.Linq; |
|||
using System.Reactive.Subjects; |
|||
using Xunit; |
|||
|
|||
public class PerspexObjectTests |
|||
{ |
|||
public PerspexObjectTests() |
|||
{ |
|||
// Ensure properties are registered.
|
|||
PerspexProperty p; |
|||
p = Class1.FooProperty; |
|||
p = Class2.BarProperty; |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetProperties_Returns_Registered_Properties() |
|||
{ |
|||
string[] names = PerspexObject.GetProperties(typeof(Class1)).Select(x => x.Name).ToArray(); |
|||
|
|||
Assert.Equal(new[] { "Foo", "Baz", "Qux" }, names); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetProperties_Returns_Registered_Properties_For_Base_Types() |
|||
{ |
|||
string[] names = PerspexObject.GetProperties(typeof(Class2)).Select(x => x.Name).ToArray(); |
|||
|
|||
Assert.Equal(new[] { "Bar", "Flob", "Fred", "Foo", "Baz", "Qux" }, names); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetValue_Returns_Default_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Equal("foodefault", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetValue_Returns_Overridden_Default_Value() |
|||
{ |
|||
Class2 target = new Class2(); |
|||
|
|||
Assert.Equal("foooverride", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetValue_Returns_Set_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.Equal("newvalue", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetValue_Returns_Inherited_Value() |
|||
{ |
|||
Class1 parent = new Class1(); |
|||
Class2 child = new Class2 { Parent = parent }; |
|||
|
|||
parent.SetValue(Class1.BazProperty, "changed"); |
|||
|
|||
Assert.Equal("changed", child.GetValue(Class1.BazProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ClearValue_Clears_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
target.ClearValue(Class1.FooProperty); |
|||
|
|||
Assert.Equal("foodefault", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Sets_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.Equal("newvalue", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Raises_PropertyChanged() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
bool raised = false; |
|||
|
|||
target.PropertyChanged += (s, e) => |
|||
{ |
|||
raised = s == target && |
|||
e.Property == Class1.FooProperty && |
|||
(string)e.OldValue == "foodefault" && |
|||
(string)e.NewValue == "newvalue"; |
|||
}; |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.True(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Doesnt_Raise_PropertyChanged_If_Value_Not_Changed() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
bool raised = false; |
|||
|
|||
target.SetValue(Class1.FooProperty, "bar"); |
|||
|
|||
target.PropertyChanged += (s, e) => |
|||
{ |
|||
raised = true; |
|||
}; |
|||
|
|||
target.SetValue(Class1.FooProperty, "bar"); |
|||
|
|||
Assert.False(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Doesnt_Raise_PropertyChanged_If_Value_Not_Changed_From_Default() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
bool raised = false; |
|||
|
|||
target.PropertyChanged += (s, e) => |
|||
{ |
|||
raised = true; |
|||
}; |
|||
|
|||
target.SetValue(Class1.FooProperty, "foodefault"); |
|||
|
|||
Assert.False(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Throws_Exception_For_Unregistered_Property() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => |
|||
{ |
|||
target.SetValue(Class2.BarProperty, "invalid"); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Throws_Exception_For_Invalid_Value_Type() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => |
|||
{ |
|||
target.SetValue(Class1.FooProperty, 123); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Of_Integer_On_Double_Property_Works() |
|||
{ |
|||
Class2 target = new Class2(); |
|||
|
|||
target.SetValue((PerspexProperty)Class2.FlobProperty, 4); |
|||
|
|||
var value = target.GetValue(Class2.FlobProperty); |
|||
Assert.IsType<double>(value); |
|||
Assert.Equal(4, value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Respects_Implicit_Conversions() |
|||
{ |
|||
Class2 target = new Class2(); |
|||
|
|||
target.SetValue((PerspexProperty)Class2.FlobProperty, new ImplictDouble(4)); |
|||
|
|||
var value = target.GetValue(Class2.FlobProperty); |
|||
Assert.IsType<double>(value); |
|||
Assert.Equal(4, value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Can_Convert_To_Nullable() |
|||
{ |
|||
Class2 target = new Class2(); |
|||
|
|||
target.SetValue((PerspexProperty)Class2.FredProperty, 4.0); |
|||
|
|||
var value = target.GetValue(Class2.FredProperty); |
|||
Assert.IsType<double>(value); |
|||
Assert.Equal(4, value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Causes_Coercion() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.QuxProperty, 5); |
|||
Assert.Equal(5, target.GetValue(Class1.QuxProperty)); |
|||
target.SetValue(Class1.QuxProperty, -5); |
|||
Assert.Equal(0, target.GetValue(Class1.QuxProperty)); |
|||
target.SetValue(Class1.QuxProperty, 15); |
|||
Assert.Equal(10, target.GetValue(Class1.QuxProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Respects_Priority() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "one", BindingPriority.TemplatedParent); |
|||
Assert.Equal("one", target.GetValue(Class1.FooProperty)); |
|||
target.SetValue(Class1.FooProperty, "two", BindingPriority.Style); |
|||
Assert.Equal("one", target.GetValue(Class1.FooProperty)); |
|||
target.SetValue(Class1.FooProperty, "three", BindingPriority.StyleTrigger); |
|||
Assert.Equal("three", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void CoerceValue_Causes_Recoercion() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.QuxProperty, 7); |
|||
Assert.Equal(7, target.GetValue(Class1.QuxProperty)); |
|||
target.MaxQux = 5; |
|||
target.CoerceValue(Class1.QuxProperty); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetObservable_Returns_Initial_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
int raised = 0; |
|||
|
|||
target.GetObservable(Class1.FooProperty).Subscribe(x => |
|||
{ |
|||
if (x == "foodefault") |
|||
{ |
|||
++raised; |
|||
} |
|||
}); |
|||
|
|||
Assert.Equal(1, raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetObservable_Returns_Property_Change() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
bool raised = false; |
|||
|
|||
target.GetObservable(Class1.FooProperty).Subscribe(x => raised = x == "newvalue"); |
|||
raised = false; |
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.True(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetObservable_Returns_Property_Change_Only_For_Correct_Property() |
|||
{ |
|||
Class2 target = new Class2(); |
|||
bool raised = false; |
|||
|
|||
target.GetObservable(Class1.FooProperty).Subscribe(x => raised = true); |
|||
raised = false; |
|||
target.SetValue(Class2.BarProperty, "newvalue"); |
|||
|
|||
Assert.False(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetObservable_Dispose_Stops_Property_Changes() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
bool raised = false; |
|||
|
|||
target.GetObservable(Class1.FooProperty) |
|||
.Subscribe(x => raised = true) |
|||
.Dispose(); |
|||
raised = false; |
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.False(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Setting_InheritanceParent_Raises_PropertyChanged_When_Value_Changed_In_Parent() |
|||
{ |
|||
bool raised = false; |
|||
|
|||
Class1 parent = new Class1(); |
|||
parent.SetValue(Class1.BazProperty, "changed"); |
|||
|
|||
Class2 child = new Class2(); |
|||
child.PropertyChanged += (s, e) => |
|||
raised = s == child && |
|||
e.Property == Class1.BazProperty && |
|||
(string)e.OldValue == "bazdefault" && |
|||
(string)e.NewValue == "changed"; |
|||
|
|||
child.Parent = parent; |
|||
|
|||
Assert.True(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Setting_InheritanceParent_Doesnt_Raise_PropertyChanged_When_Local_Value_Set() |
|||
{ |
|||
bool raised = false; |
|||
|
|||
Class1 parent = new Class1(); |
|||
parent.SetValue(Class1.BazProperty, "changed"); |
|||
|
|||
Class2 child = new Class2(); |
|||
child.SetValue(Class1.BazProperty, "localvalue"); |
|||
child.PropertyChanged += (s, e) => raised = true; |
|||
|
|||
child.Parent = parent; |
|||
|
|||
Assert.False(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Setting_Value_In_InheritanceParent_Raises_PropertyChanged() |
|||
{ |
|||
bool raised = false; |
|||
|
|||
Class1 parent = new Class1(); |
|||
|
|||
Class2 child = new Class2(); |
|||
child.PropertyChanged += (s, e) => |
|||
raised = s == child && |
|||
e.Property == Class1.BazProperty && |
|||
(string)e.OldValue == "bazdefault" && |
|||
(string)e.NewValue == "changed"; |
|||
child.Parent = parent; |
|||
|
|||
parent.SetValue(Class1.BazProperty, "changed"); |
|||
|
|||
Assert.True(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bind_Sets_Current_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
Class1 source = new Class1(); |
|||
|
|||
source.SetValue(Class1.FooProperty, "initial"); |
|||
target.Bind(Class1.FooProperty, source.GetObservable(Class1.FooProperty)); |
|||
|
|||
Assert.Equal("initial", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bind_NonGeneric_Sets_Current_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
Class1 source = new Class1(); |
|||
|
|||
source.SetValue(Class1.FooProperty, "initial"); |
|||
target.Bind((PerspexProperty)Class1.FooProperty, source.GetObservable(Class1.FooProperty)); |
|||
|
|||
Assert.Equal("initial", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bind_Throws_Exception_For_Unregistered_Property() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => |
|||
{ |
|||
target.Bind(Class2.BarProperty, Observable.Return("foo")); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bind_Sets_Subsequent_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
Class1 source = new Class1(); |
|||
|
|||
source.SetValue(Class1.FooProperty, "initial"); |
|||
target.Bind(Class1.FooProperty, source.GetObservable(Class1.FooProperty)); |
|||
source.SetValue(Class1.FooProperty, "subsequent"); |
|||
|
|||
Assert.Equal("subsequent", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bind_Throws_Exception_For_Invalid_Value_Type() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => |
|||
{ |
|||
target.Bind((PerspexProperty)Class1.FooProperty, Observable.Return((object)123)); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Two_Way_Binding_Works() |
|||
{ |
|||
Class1 obj1 = new Class1(); |
|||
Class1 obj2 = new Class1(); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "initial1"); |
|||
obj2.SetValue(Class1.FooProperty, "initial2"); |
|||
|
|||
obj1.Bind(Class1.FooProperty, obj2.GetObservable(Class1.FooProperty)); |
|||
obj2.Bind(Class1.FooProperty, obj1.GetObservable(Class1.FooProperty)); |
|||
|
|||
Assert.Equal("initial2", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("initial2", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "first"); |
|||
|
|||
Assert.Equal("first", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("first", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj2.SetValue(Class1.FooProperty, "second"); |
|||
|
|||
Assert.Equal("second", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("second", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "third"); |
|||
|
|||
Assert.Equal("third", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("third", obj2.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Two_Way_Binding_With_Priority_Works() |
|||
{ |
|||
Class1 obj1 = new Class1(); |
|||
Class1 obj2 = new Class1(); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "initial1", BindingPriority.Style); |
|||
obj2.SetValue(Class1.FooProperty, "initial2", BindingPriority.Style); |
|||
|
|||
obj1.Bind(Class1.FooProperty, obj2.GetObservable(Class1.FooProperty), BindingPriority.Style); |
|||
obj2.Bind(Class1.FooProperty, obj1.GetObservable(Class1.FooProperty), BindingPriority.Style); |
|||
|
|||
Assert.Equal("initial2", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("initial2", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "first", BindingPriority.Style); |
|||
|
|||
Assert.Equal("first", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("first", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj2.SetValue(Class1.FooProperty, "second", BindingPriority.Style); |
|||
|
|||
Assert.Equal("second", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("second", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "third", BindingPriority.Style); |
|||
|
|||
Assert.Equal("third", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("third", obj2.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void BindTwoWay_Gets_Initial_Value_From_Source() |
|||
{ |
|||
Class1 source = new Class1(); |
|||
Class1 target = new Class1(); |
|||
|
|||
source.SetValue(Class1.FooProperty, "initial"); |
|||
target.BindTwoWay(Class1.FooProperty, source, Class1.FooProperty); |
|||
|
|||
Assert.Equal("initial", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void BindTwoWay_Updates_Values() |
|||
{ |
|||
Class1 source = new Class1(); |
|||
Class1 target = new Class1(); |
|||
|
|||
source.SetValue(Class1.FooProperty, "first"); |
|||
target.BindTwoWay(Class1.FooProperty, source, Class1.FooProperty); |
|||
|
|||
Assert.Equal("first", target.GetValue(Class1.FooProperty)); |
|||
source.SetValue(Class1.FooProperty, "second"); |
|||
Assert.Equal("second", target.GetValue(Class1.FooProperty)); |
|||
target.SetValue(Class1.FooProperty, "third"); |
|||
Assert.Equal("third", source.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Setting_UnsetValue_Reverts_To_Default_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
target.SetValue(Class1.FooProperty, PerspexProperty.UnsetValue); |
|||
|
|||
Assert.Equal("foodefault", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Local_Binding_Overwrites_Local_Value() |
|||
{ |
|||
var target = new Class1(); |
|||
var binding = new Subject<string>(); |
|||
|
|||
target.Bind(Class1.FooProperty, binding); |
|||
|
|||
binding.OnNext("first"); |
|||
Assert.Equal("first", target.GetValue(Class1.FooProperty)); |
|||
|
|||
target.SetValue(Class1.FooProperty, "second"); |
|||
Assert.Equal("second", target.GetValue(Class1.FooProperty)); |
|||
|
|||
binding.OnNext("third"); |
|||
Assert.Equal("third", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void StyleBinding_Overrides_Default_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.Bind(Class1.FooProperty, this.Single("stylevalue"), BindingPriority.Style); |
|||
|
|||
Assert.Equal("stylevalue", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Returns_Value_Property() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.Equal("newvalue", target[Class1.FooProperty]); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Sets_Value_Property() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target[Class1.FooProperty] = "newvalue"; |
|||
|
|||
Assert.Equal("newvalue", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Doesnt_Accept_Observable() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => |
|||
{ |
|||
target[Class1.FooProperty] = Observable.Return("newvalue"); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Binds_One_Way() |
|||
{ |
|||
Class1 target1 = new Class1(); |
|||
Class1 target2 = new Class1(); |
|||
Binding binding = Class1.FooProperty.Bind().WithMode(BindingMode.OneWay); |
|||
|
|||
target1.SetValue(Class1.FooProperty, "first"); |
|||
target2[binding] = target1[!Class1.FooProperty]; |
|||
target1.SetValue(Class1.FooProperty, "second"); |
|||
|
|||
Assert.Equal("second", target2.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Binds_Two_Way() |
|||
{ |
|||
Class1 target1 = new Class1(); |
|||
Class1 target2 = new Class1(); |
|||
Binding binding = Class1.FooProperty.Bind().WithMode(BindingMode.TwoWay); |
|||
|
|||
target1.SetValue(Class1.FooProperty, "first"); |
|||
target2[binding] = target1[!Class1.FooProperty]; |
|||
Assert.Equal("first", target2.GetValue(Class1.FooProperty)); |
|||
target1.SetValue(Class1.FooProperty, "second"); |
|||
Assert.Equal("second", target2.GetValue(Class1.FooProperty)); |
|||
target2.SetValue(Class1.FooProperty, "third"); |
|||
Assert.Equal("third", target1.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Binds_One_Time() |
|||
{ |
|||
Class1 target1 = new Class1(); |
|||
Class1 target2 = new Class1(); |
|||
Binding binding = Class1.FooProperty.Bind().WithMode(BindingMode.OneTime); |
|||
|
|||
target1.SetValue(Class1.FooProperty, "first"); |
|||
target2[binding] = target1[!Class1.FooProperty]; |
|||
target1.SetValue(Class1.FooProperty, "second"); |
|||
|
|||
Assert.Equal("first", target2.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an observable that returns a single value but does not complete.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the observable.</typeparam>
|
|||
/// <param name="value">The value.</param>
|
|||
/// <returns>The observable.</returns>
|
|||
private IObservable<T> Single<T>(T value) |
|||
{ |
|||
return Observable.Never<T>().StartWith(value); |
|||
} |
|||
|
|||
private class Class1 : PerspexObject |
|||
{ |
|||
public static readonly PerspexProperty<string> FooProperty = |
|||
PerspexProperty.Register<Class1, string>("Foo", "foodefault"); |
|||
|
|||
public static readonly PerspexProperty<string> BazProperty = |
|||
PerspexProperty.Register<Class1, string>("Baz", "bazdefault", true); |
|||
|
|||
public static readonly PerspexProperty<int> QuxProperty = |
|||
PerspexProperty.Register<Class1, int>("Qux", coerce: Coerce); |
|||
|
|||
public Class1() |
|||
{ |
|||
this.MaxQux = 10; |
|||
} |
|||
|
|||
public int MaxQux { get; set; } |
|||
|
|||
private static int Coerce(PerspexObject instance, int value) |
|||
{ |
|||
return Math.Min(Math.Max(value, 0), ((Class1)instance).MaxQux); |
|||
} |
|||
} |
|||
|
|||
private class Class2 : Class1 |
|||
{ |
|||
public static readonly PerspexProperty<string> BarProperty = |
|||
PerspexProperty.Register<Class2, string>("Bar", "bardefault"); |
|||
|
|||
public static readonly PerspexProperty<double> FlobProperty = |
|||
PerspexProperty.Register<Class2, double>("Flob"); |
|||
|
|||
public static readonly PerspexProperty<double?> FredProperty = |
|||
PerspexProperty.Register<Class2, double?>("Fred"); |
|||
|
|||
static Class2() |
|||
{ |
|||
FooProperty.OverrideDefaultValue(typeof(Class2), "foooverride"); |
|||
} |
|||
|
|||
public Class1 Parent |
|||
{ |
|||
get { return (Class1)this.InheritanceParent; } |
|||
set { this.InheritanceParent = value; } |
|||
} |
|||
} |
|||
|
|||
private class ImplictDouble |
|||
{ |
|||
public ImplictDouble(double value) |
|||
{ |
|||
this.Value = value; |
|||
} |
|||
|
|||
public double Value { get; } |
|||
|
|||
public static implicit operator double(ImplictDouble v) |
|||
{ |
|||
return v.Value; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,294 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PerspexObjectTests_Binding.cs" company="Steven Kirk">
|
|||
// Copyright 2015 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Base.UnitTests |
|||
{ |
|||
using System; |
|||
using System.Reactive.Linq; |
|||
using System.Reactive.Subjects; |
|||
using Xunit; |
|||
|
|||
public class PerspexObjectTests_Binding |
|||
{ |
|||
[Fact] |
|||
public void Bind_Sets_Current_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
Class1 source = new Class1(); |
|||
|
|||
source.SetValue(Class1.FooProperty, "initial"); |
|||
target.Bind(Class1.FooProperty, source.GetObservable(Class1.FooProperty)); |
|||
|
|||
Assert.Equal("initial", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bind_NonGeneric_Sets_Current_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
Class1 source = new Class1(); |
|||
|
|||
source.SetValue(Class1.FooProperty, "initial"); |
|||
target.Bind((PerspexProperty)Class1.FooProperty, source.GetObservable(Class1.FooProperty)); |
|||
|
|||
Assert.Equal("initial", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bind_Throws_Exception_For_Unregistered_Property() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => |
|||
{ |
|||
target.Bind(Class2.BarProperty, Observable.Return("foo")); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bind_Sets_Subsequent_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
Class1 source = new Class1(); |
|||
|
|||
source.SetValue(Class1.FooProperty, "initial"); |
|||
target.Bind(Class1.FooProperty, source.GetObservable(Class1.FooProperty)); |
|||
source.SetValue(Class1.FooProperty, "subsequent"); |
|||
|
|||
Assert.Equal("subsequent", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bind_Throws_Exception_For_Invalid_Value_Type() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => |
|||
{ |
|||
target.Bind((PerspexProperty)Class1.FooProperty, Observable.Return((object)123)); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Two_Way_Binding_Works() |
|||
{ |
|||
Class1 obj1 = new Class1(); |
|||
Class1 obj2 = new Class1(); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "initial1"); |
|||
obj2.SetValue(Class1.FooProperty, "initial2"); |
|||
|
|||
obj1.Bind(Class1.FooProperty, obj2.GetObservable(Class1.FooProperty)); |
|||
obj2.Bind(Class1.FooProperty, obj1.GetObservable(Class1.FooProperty)); |
|||
|
|||
Assert.Equal("initial2", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("initial2", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "first"); |
|||
|
|||
Assert.Equal("first", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("first", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj2.SetValue(Class1.FooProperty, "second"); |
|||
|
|||
Assert.Equal("second", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("second", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "third"); |
|||
|
|||
Assert.Equal("third", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("third", obj2.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Two_Way_Binding_With_Priority_Works() |
|||
{ |
|||
Class1 obj1 = new Class1(); |
|||
Class1 obj2 = new Class1(); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "initial1", BindingPriority.Style); |
|||
obj2.SetValue(Class1.FooProperty, "initial2", BindingPriority.Style); |
|||
|
|||
obj1.Bind(Class1.FooProperty, obj2.GetObservable(Class1.FooProperty), BindingPriority.Style); |
|||
obj2.Bind(Class1.FooProperty, obj1.GetObservable(Class1.FooProperty), BindingPriority.Style); |
|||
|
|||
Assert.Equal("initial2", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("initial2", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "first", BindingPriority.Style); |
|||
|
|||
Assert.Equal("first", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("first", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj2.SetValue(Class1.FooProperty, "second", BindingPriority.Style); |
|||
|
|||
Assert.Equal("second", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("second", obj2.GetValue(Class1.FooProperty)); |
|||
|
|||
obj1.SetValue(Class1.FooProperty, "third", BindingPriority.Style); |
|||
|
|||
Assert.Equal("third", obj1.GetValue(Class1.FooProperty)); |
|||
Assert.Equal("third", obj2.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void BindTwoWay_Gets_Initial_Value_From_Source() |
|||
{ |
|||
Class1 source = new Class1(); |
|||
Class1 target = new Class1(); |
|||
|
|||
source.SetValue(Class1.FooProperty, "initial"); |
|||
target.BindTwoWay(Class1.FooProperty, source, Class1.FooProperty); |
|||
|
|||
Assert.Equal("initial", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void BindTwoWay_Updates_Values() |
|||
{ |
|||
Class1 source = new Class1(); |
|||
Class1 target = new Class1(); |
|||
|
|||
source.SetValue(Class1.FooProperty, "first"); |
|||
target.BindTwoWay(Class1.FooProperty, source, Class1.FooProperty); |
|||
|
|||
Assert.Equal("first", target.GetValue(Class1.FooProperty)); |
|||
source.SetValue(Class1.FooProperty, "second"); |
|||
Assert.Equal("second", target.GetValue(Class1.FooProperty)); |
|||
target.SetValue(Class1.FooProperty, "third"); |
|||
Assert.Equal("third", source.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Local_Binding_Overwrites_Local_Value() |
|||
{ |
|||
var target = new Class1(); |
|||
var binding = new Subject<string>(); |
|||
|
|||
target.Bind(Class1.FooProperty, binding); |
|||
|
|||
binding.OnNext("first"); |
|||
Assert.Equal("first", target.GetValue(Class1.FooProperty)); |
|||
|
|||
target.SetValue(Class1.FooProperty, "second"); |
|||
Assert.Equal("second", target.GetValue(Class1.FooProperty)); |
|||
|
|||
binding.OnNext("third"); |
|||
Assert.Equal("third", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void StyleBinding_Overrides_Default_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.Bind(Class1.FooProperty, this.Single("stylevalue"), BindingPriority.Style); |
|||
|
|||
Assert.Equal("stylevalue", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Returns_Value_Property() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.Equal("newvalue", target[Class1.FooProperty]); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Sets_Value_Property() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target[Class1.FooProperty] = "newvalue"; |
|||
|
|||
Assert.Equal("newvalue", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Doesnt_Accept_Observable() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => |
|||
{ |
|||
target[Class1.FooProperty] = Observable.Return("newvalue"); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Binds_One_Way() |
|||
{ |
|||
Class1 target1 = new Class1(); |
|||
Class1 target2 = new Class1(); |
|||
Binding binding = Class1.FooProperty.Bind().WithMode(BindingMode.OneWay); |
|||
|
|||
target1.SetValue(Class1.FooProperty, "first"); |
|||
target2[binding] = target1[!Class1.FooProperty]; |
|||
target1.SetValue(Class1.FooProperty, "second"); |
|||
|
|||
Assert.Equal("second", target2.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Binds_Two_Way() |
|||
{ |
|||
Class1 target1 = new Class1(); |
|||
Class1 target2 = new Class1(); |
|||
Binding binding = Class1.FooProperty.Bind().WithMode(BindingMode.TwoWay); |
|||
|
|||
target1.SetValue(Class1.FooProperty, "first"); |
|||
target2[binding] = target1[!Class1.FooProperty]; |
|||
Assert.Equal("first", target2.GetValue(Class1.FooProperty)); |
|||
target1.SetValue(Class1.FooProperty, "second"); |
|||
Assert.Equal("second", target2.GetValue(Class1.FooProperty)); |
|||
target2.SetValue(Class1.FooProperty, "third"); |
|||
Assert.Equal("third", target1.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void this_Operator_Binds_One_Time() |
|||
{ |
|||
Class1 target1 = new Class1(); |
|||
Class1 target2 = new Class1(); |
|||
Binding binding = Class1.FooProperty.Bind().WithMode(BindingMode.OneTime); |
|||
|
|||
target1.SetValue(Class1.FooProperty, "first"); |
|||
target2[binding] = target1[!Class1.FooProperty]; |
|||
target1.SetValue(Class1.FooProperty, "second"); |
|||
|
|||
Assert.Equal("first", target2.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an observable that returns a single value but does not complete.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the observable.</typeparam>
|
|||
/// <param name="value">The value.</param>
|
|||
/// <returns>The observable.</returns>
|
|||
private IObservable<T> Single<T>(T value) |
|||
{ |
|||
return Observable.Never<T>().StartWith(value); |
|||
} |
|||
|
|||
private class Class1 : PerspexObject |
|||
{ |
|||
public static readonly PerspexProperty<string> FooProperty = |
|||
PerspexProperty.Register<Class1, string>("Foo", "foodefault"); |
|||
|
|||
public static readonly PerspexProperty<string> BazProperty = |
|||
PerspexProperty.Register<Class1, string>("Baz", "bazdefault", true); |
|||
} |
|||
|
|||
private class Class2 : Class1 |
|||
{ |
|||
public static readonly PerspexProperty<string> BarProperty = |
|||
PerspexProperty.Register<Class2, string>("Bar", "bardefault"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PerspexObjectTests_Coercion.cs" company="Steven Kirk">
|
|||
// Copyright 2015 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Base.UnitTests |
|||
{ |
|||
using System; |
|||
using System.Linq; |
|||
using System.Reactive.Linq; |
|||
using System.Reactive.Subjects; |
|||
using Xunit; |
|||
|
|||
public class PerspexObjectTests_Coercion |
|||
{ |
|||
[Fact] |
|||
public void CoerceValue_Causes_Recoercion() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.QuxProperty, 7); |
|||
Assert.Equal(7, target.GetValue(Class1.QuxProperty)); |
|||
target.MaxQux = 5; |
|||
target.CoerceValue(Class1.QuxProperty); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Causes_Coercion() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.QuxProperty, 5); |
|||
Assert.Equal(5, target.GetValue(Class1.QuxProperty)); |
|||
target.SetValue(Class1.QuxProperty, -5); |
|||
Assert.Equal(0, target.GetValue(Class1.QuxProperty)); |
|||
target.SetValue(Class1.QuxProperty, 15); |
|||
Assert.Equal(10, target.GetValue(Class1.QuxProperty)); |
|||
} |
|||
|
|||
private class Class1 : PerspexObject |
|||
{ |
|||
public static readonly PerspexProperty<int> QuxProperty = |
|||
PerspexProperty.Register<Class1, int>("Qux", coerce: Coerce); |
|||
|
|||
public Class1() |
|||
{ |
|||
this.MaxQux = 10; |
|||
} |
|||
|
|||
public int MaxQux { get; set; } |
|||
|
|||
private static int Coerce(PerspexObject instance, int value) |
|||
{ |
|||
return Math.Min(Math.Max(value, 0), ((Class1)instance).MaxQux); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PerspexObjectTests_GetObservable.cs" company="Steven Kirk">
|
|||
// Copyright 2015 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Base.UnitTests |
|||
{ |
|||
using System; |
|||
using System.Reactive.Linq; |
|||
using Xunit; |
|||
|
|||
public class PerspexObjectTests_GetObservable |
|||
{ |
|||
[Fact] |
|||
public void GetObservable_Returns_Initial_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
int raised = 0; |
|||
|
|||
target.GetObservable(Class1.FooProperty).Subscribe(x => |
|||
{ |
|||
if (x == "foodefault") |
|||
{ |
|||
++raised; |
|||
} |
|||
}); |
|||
|
|||
Assert.Equal(1, raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetObservable_Returns_Property_Change() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
bool raised = false; |
|||
|
|||
target.GetObservable(Class1.FooProperty).Subscribe(x => raised = x == "newvalue"); |
|||
raised = false; |
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.True(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetObservable_Returns_Property_Change_Only_For_Correct_Property() |
|||
{ |
|||
Class2 target = new Class2(); |
|||
bool raised = false; |
|||
|
|||
target.GetObservable(Class1.FooProperty).Subscribe(x => raised = true); |
|||
raised = false; |
|||
target.SetValue(Class2.BarProperty, "newvalue"); |
|||
|
|||
Assert.False(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetObservable_Dispose_Stops_Property_Changes() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
bool raised = false; |
|||
|
|||
target.GetObservable(Class1.FooProperty) |
|||
.Subscribe(x => raised = true) |
|||
.Dispose(); |
|||
raised = false; |
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.False(raised); |
|||
} |
|||
|
|||
private class Class1 : PerspexObject |
|||
{ |
|||
public static readonly PerspexProperty<string> FooProperty = |
|||
PerspexProperty.Register<Class1, string>("Foo", "foodefault"); |
|||
} |
|||
|
|||
private class Class2 : Class1 |
|||
{ |
|||
public static readonly PerspexProperty<string> BarProperty = |
|||
PerspexProperty.Register<Class2, string>("Bar", "bardefault"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PerspexObjectTests_GetValue.cs" company="Steven Kirk">
|
|||
// Copyright 2015 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Base.UnitTests |
|||
{ |
|||
using Xunit; |
|||
|
|||
public class PerspexObjectTests_GetValue |
|||
{ |
|||
[Fact] |
|||
public void GetValue_Returns_Default_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Equal("foodefault", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetValue_Returns_Overridden_Default_Value() |
|||
{ |
|||
Class2 target = new Class2(); |
|||
|
|||
Assert.Equal("foooverride", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetValue_Returns_Set_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.Equal("newvalue", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetValue_Returns_Inherited_Value() |
|||
{ |
|||
Class1 parent = new Class1(); |
|||
Class2 child = new Class2 { Parent = parent }; |
|||
|
|||
parent.SetValue(Class1.BazProperty, "changed"); |
|||
|
|||
Assert.Equal("changed", child.GetValue(Class1.BazProperty)); |
|||
} |
|||
|
|||
private class Class1 : PerspexObject |
|||
{ |
|||
public static readonly PerspexProperty<string> FooProperty = |
|||
PerspexProperty.Register<Class1, string>("Foo", "foodefault"); |
|||
|
|||
public static readonly PerspexProperty<string> BazProperty = |
|||
PerspexProperty.Register<Class1, string>("Baz", "bazdefault", true); |
|||
} |
|||
|
|||
private class Class2 : Class1 |
|||
{ |
|||
static Class2() |
|||
{ |
|||
FooProperty.OverrideDefaultValue(typeof(Class2), "foooverride"); |
|||
} |
|||
|
|||
public Class1 Parent |
|||
{ |
|||
get { return (Class1)this.InheritanceParent; } |
|||
set { this.InheritanceParent = value; } |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,104 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PerspexObjectTests_Inheritance.cs" company="Steven Kirk">
|
|||
// Copyright 2015 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Base.UnitTests |
|||
{ |
|||
using Xunit; |
|||
|
|||
public class PerspexObjectTests_Inheritance |
|||
{ |
|||
[Fact] |
|||
public void GetValue_Returns_Inherited_Value() |
|||
{ |
|||
Class1 parent = new Class1(); |
|||
Class2 child = new Class2 { Parent = parent }; |
|||
|
|||
parent.SetValue(Class1.BazProperty, "changed"); |
|||
|
|||
Assert.Equal("changed", child.GetValue(Class1.BazProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Setting_InheritanceParent_Raises_PropertyChanged_When_Value_Changed_In_Parent() |
|||
{ |
|||
bool raised = false; |
|||
|
|||
Class1 parent = new Class1(); |
|||
parent.SetValue(Class1.BazProperty, "changed"); |
|||
|
|||
Class2 child = new Class2(); |
|||
child.PropertyChanged += (s, e) => |
|||
raised = s == child && |
|||
e.Property == Class1.BazProperty && |
|||
(string)e.OldValue == "bazdefault" && |
|||
(string)e.NewValue == "changed"; |
|||
|
|||
child.Parent = parent; |
|||
|
|||
Assert.True(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Setting_InheritanceParent_Doesnt_Raise_PropertyChanged_When_Local_Value_Set() |
|||
{ |
|||
bool raised = false; |
|||
|
|||
Class1 parent = new Class1(); |
|||
parent.SetValue(Class1.BazProperty, "changed"); |
|||
|
|||
Class2 child = new Class2(); |
|||
child.SetValue(Class1.BazProperty, "localvalue"); |
|||
child.PropertyChanged += (s, e) => raised = true; |
|||
|
|||
child.Parent = parent; |
|||
|
|||
Assert.False(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Setting_Value_In_InheritanceParent_Raises_PropertyChanged() |
|||
{ |
|||
bool raised = false; |
|||
|
|||
Class1 parent = new Class1(); |
|||
|
|||
Class2 child = new Class2(); |
|||
child.PropertyChanged += (s, e) => |
|||
raised = s == child && |
|||
e.Property == Class1.BazProperty && |
|||
(string)e.OldValue == "bazdefault" && |
|||
(string)e.NewValue == "changed"; |
|||
child.Parent = parent; |
|||
|
|||
parent.SetValue(Class1.BazProperty, "changed"); |
|||
|
|||
Assert.True(raised); |
|||
} |
|||
|
|||
private class Class1 : PerspexObject |
|||
{ |
|||
public static readonly PerspexProperty<string> FooProperty = |
|||
PerspexProperty.Register<Class1, string>("Foo", "foodefault"); |
|||
|
|||
public static readonly PerspexProperty<string> BazProperty = |
|||
PerspexProperty.Register<Class1, string>("Baz", "bazdefault", true); |
|||
} |
|||
|
|||
private class Class2 : Class1 |
|||
{ |
|||
static Class2() |
|||
{ |
|||
FooProperty.OverrideDefaultValue(typeof(Class2), "foooverride"); |
|||
} |
|||
|
|||
public Class1 Parent |
|||
{ |
|||
get { return (Class1)this.InheritanceParent; } |
|||
set { this.InheritanceParent = value; } |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PerspexObjectTests_Metadata.cs" company="Steven Kirk">
|
|||
// Copyright 2015 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Base.UnitTests |
|||
{ |
|||
using System; |
|||
using System.Linq; |
|||
using System.Reactive.Linq; |
|||
using System.Reactive.Subjects; |
|||
using Xunit; |
|||
|
|||
public class PerspexObjectTests_Metadata |
|||
{ |
|||
public PerspexObjectTests_Metadata() |
|||
{ |
|||
// Ensure properties are registered.
|
|||
PerspexProperty p; |
|||
p = Class1.FooProperty; |
|||
p = Class2.BarProperty; |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetProperties_Returns_Registered_Properties() |
|||
{ |
|||
string[] names = PerspexObject.GetProperties(typeof(Class1)).Select(x => x.Name).ToArray(); |
|||
|
|||
Assert.Equal(new[] { "Foo", "Baz", "Qux" }, names); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetProperties_Returns_Registered_Properties_For_Base_Types() |
|||
{ |
|||
string[] names = PerspexObject.GetProperties(typeof(Class2)).Select(x => x.Name).ToArray(); |
|||
|
|||
Assert.Equal(new[] { "Bar", "Flob", "Fred", "Foo", "Baz", "Qux" }, names); |
|||
} |
|||
|
|||
private class Class1 : PerspexObject |
|||
{ |
|||
public static readonly PerspexProperty<string> FooProperty = |
|||
PerspexProperty.Register<Class1, string>("Foo"); |
|||
|
|||
public static readonly PerspexProperty<string> BazProperty = |
|||
PerspexProperty.Register<Class1, string>("Baz"); |
|||
|
|||
public static readonly PerspexProperty<int> QuxProperty = |
|||
PerspexProperty.Register<Class1, int>("Qux"); |
|||
} |
|||
|
|||
private class Class2 : Class1 |
|||
{ |
|||
public static readonly PerspexProperty<string> BarProperty = |
|||
PerspexProperty.Register<Class2, string>("Bar"); |
|||
|
|||
public static readonly PerspexProperty<double> FlobProperty = |
|||
PerspexProperty.Register<Class2, double>("Flob"); |
|||
|
|||
public static readonly PerspexProperty<double?> FredProperty = |
|||
PerspexProperty.Register<Class2, double?>("Fred"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,212 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PerspexObjectTests_SetValue.cs" company="Steven Kirk">
|
|||
// Copyright 2015 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Base.UnitTests |
|||
{ |
|||
using System; |
|||
using System.Linq; |
|||
using System.Reactive.Linq; |
|||
using System.Reactive.Subjects; |
|||
using Xunit; |
|||
|
|||
public class PerspexObjectTests_SetValue |
|||
{ |
|||
[Fact] |
|||
public void ClearValue_Clears_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
target.ClearValue(Class1.FooProperty); |
|||
|
|||
Assert.Equal("foodefault", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Sets_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.Equal("newvalue", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Raises_PropertyChanged() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
bool raised = false; |
|||
|
|||
target.PropertyChanged += (s, e) => |
|||
{ |
|||
raised = s == target && |
|||
e.Property == Class1.FooProperty && |
|||
(string)e.OldValue == "foodefault" && |
|||
(string)e.NewValue == "newvalue"; |
|||
}; |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
|
|||
Assert.True(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Doesnt_Raise_PropertyChanged_If_Value_Not_Changed() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
bool raised = false; |
|||
|
|||
target.SetValue(Class1.FooProperty, "bar"); |
|||
|
|||
target.PropertyChanged += (s, e) => |
|||
{ |
|||
raised = true; |
|||
}; |
|||
|
|||
target.SetValue(Class1.FooProperty, "bar"); |
|||
|
|||
Assert.False(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Doesnt_Raise_PropertyChanged_If_Value_Not_Changed_From_Default() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
bool raised = false; |
|||
|
|||
target.PropertyChanged += (s, e) => |
|||
{ |
|||
raised = true; |
|||
}; |
|||
|
|||
target.SetValue(Class1.FooProperty, "foodefault"); |
|||
|
|||
Assert.False(raised); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Throws_Exception_For_Unregistered_Property() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => |
|||
{ |
|||
target.SetValue(Class2.BarProperty, "invalid"); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Throws_Exception_For_Invalid_Value_Type() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => |
|||
{ |
|||
target.SetValue(Class1.FooProperty, 123); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Of_Integer_On_Double_Property_Works() |
|||
{ |
|||
Class2 target = new Class2(); |
|||
|
|||
target.SetValue((PerspexProperty)Class2.FlobProperty, 4); |
|||
|
|||
var value = target.GetValue(Class2.FlobProperty); |
|||
Assert.IsType<double>(value); |
|||
Assert.Equal(4, value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Respects_Implicit_Conversions() |
|||
{ |
|||
Class2 target = new Class2(); |
|||
|
|||
target.SetValue((PerspexProperty)Class2.FlobProperty, new ImplictDouble(4)); |
|||
|
|||
var value = target.GetValue(Class2.FlobProperty); |
|||
Assert.IsType<double>(value); |
|||
Assert.Equal(4, value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Can_Convert_To_Nullable() |
|||
{ |
|||
Class2 target = new Class2(); |
|||
|
|||
target.SetValue((PerspexProperty)Class2.FredProperty, 4.0); |
|||
|
|||
var value = target.GetValue(Class2.FredProperty); |
|||
Assert.IsType<double>(value); |
|||
Assert.Equal(4, value); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SetValue_Respects_Priority() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "one", BindingPriority.TemplatedParent); |
|||
Assert.Equal("one", target.GetValue(Class1.FooProperty)); |
|||
target.SetValue(Class1.FooProperty, "two", BindingPriority.Style); |
|||
Assert.Equal("one", target.GetValue(Class1.FooProperty)); |
|||
target.SetValue(Class1.FooProperty, "three", BindingPriority.StyleTrigger); |
|||
Assert.Equal("three", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Setting_UnsetValue_Reverts_To_Default_Value() |
|||
{ |
|||
Class1 target = new Class1(); |
|||
|
|||
target.SetValue(Class1.FooProperty, "newvalue"); |
|||
target.SetValue(Class1.FooProperty, PerspexProperty.UnsetValue); |
|||
|
|||
Assert.Equal("foodefault", target.GetValue(Class1.FooProperty)); |
|||
} |
|||
|
|||
private class Class1 : PerspexObject |
|||
{ |
|||
public static readonly PerspexProperty<string> FooProperty = |
|||
PerspexProperty.Register<Class1, string>("Foo", "foodefault"); |
|||
} |
|||
|
|||
private class Class2 : Class1 |
|||
{ |
|||
public static readonly PerspexProperty<string> BarProperty = |
|||
PerspexProperty.Register<Class2, string>("Bar", "bardefault"); |
|||
|
|||
public static readonly PerspexProperty<double> FlobProperty = |
|||
PerspexProperty.Register<Class2, double>("Flob"); |
|||
|
|||
public static readonly PerspexProperty<double?> FredProperty = |
|||
PerspexProperty.Register<Class2, double?>("Fred"); |
|||
|
|||
public Class1 Parent |
|||
{ |
|||
get { return (Class1)this.InheritanceParent; } |
|||
set { this.InheritanceParent = value; } |
|||
} |
|||
} |
|||
|
|||
private class ImplictDouble |
|||
{ |
|||
public ImplictDouble(double value) |
|||
{ |
|||
this.Value = value; |
|||
} |
|||
|
|||
public double Value { get; } |
|||
|
|||
public static implicit operator double (ImplictDouble v) |
|||
{ |
|||
return v.Value; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue