// ----------------------------------------------------------------------- // // Copyright 2013 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Perspex.UnitTests { using System; using System.Linq; using System.Reactive.Linq; using System.Reactive.Subjects; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] public class PerspexObjectTests { [TestInitialize] public void Initialize() { // Ensure properties are registered. PerspexProperty p; p = Class1.FooProperty; p = Class2.BarProperty; } [TestMethod] public void GetProperties_Returns_Registered_Properties() { string[] names = PerspexObject.GetProperties(typeof(Class1)).Select(x => x.Name).ToArray(); CollectionAssert.AreEqual(new[] { "Foo", "Baz" }, names); } [TestMethod] public void GetProperties_Returns_Registered_Properties_For_Base_Types() { string[] names = PerspexObject.GetProperties(typeof(Class2)).Select(x => x.Name).ToArray(); CollectionAssert.AreEqual(new[] { "Bar", "Foo", "Baz" }, names); } [TestMethod] public void GetValue_Returns_Default_Value() { Class1 target = new Class1(); Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty)); } [TestMethod] public void GetValue_Returns_Overridden_Default_Value() { Class2 target = new Class2(); Assert.AreEqual("foooverride", target.GetValue(Class1.FooProperty)); } [TestMethod] public void GetValue_Returns_Set_Value() { Class1 target = new Class1(); target.SetValue(Class1.FooProperty, "newvalue"); Assert.AreEqual("newvalue", target.GetValue(Class1.FooProperty)); } [TestMethod] public void GetValue_Returns_Inherited_Value() { Class1 parent = new Class1(); Class2 child = new Class2 { Parent = parent }; parent.SetValue(Class1.BazProperty, "changed"); Assert.AreEqual("changed", child.GetValue(Class1.BazProperty)); } [TestMethod] public void ClearValue_Clears_Value() { Class1 target = new Class1(); target.SetValue(Class1.FooProperty, "newvalue"); target.ClearValue(Class1.FooProperty); Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty)); } [TestMethod] public void SetValue_Sets_Value() { Class1 target = new Class1(); target.SetValue(Class1.FooProperty, "newvalue"); Assert.AreEqual("newvalue", target.GetValue(Class1.FooProperty)); } [TestMethod] 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.IsTrue(raised); } [TestMethod] 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.IsFalse(raised); } [TestMethod] 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.IsFalse(raised); } [TestMethod] [ExpectedException(typeof(InvalidOperationException))] public void SetValue_Throws_Exception_For_Unregistered_Property() { Class1 target = new Class1(); target.SetValue(Class2.BarProperty, "invalid"); } [TestMethod] [ExpectedException(typeof(InvalidOperationException))] public void SetValue_Throws_Exception_For_Invalid_Value_Type() { Class1 target = new Class1(); target.SetValue(Class1.FooProperty, 123); } [TestMethod] public void GetObservable_Returns_Initial_Value() { Class1 target = new Class1(); bool raised = false; target.GetObservable(Class1.FooProperty).Subscribe(x => raised = x == "foodefault"); Assert.IsTrue(raised); } [TestMethod] 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.IsTrue(raised); } [TestMethod] 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.IsFalse(raised); } [TestMethod] 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.IsFalse(raised); } [TestMethod] 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.IsTrue(raised); } [TestMethod] 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.IsFalse(raised); } [TestMethod] 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.IsTrue(raised); } [TestMethod] 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.AreEqual("initial", target.GetValue(Class1.FooProperty)); } [TestMethod] 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.AreEqual("initial", target.GetValue(Class1.FooProperty)); } [TestMethod] 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.AreEqual("subsequent", target.GetValue(Class1.FooProperty)); } [TestMethod] public void Binding_Doesnt_Set_Value_After_Clear() { Class1 target = new Class1(); Class1 source = new Class1(); source.SetValue(Class1.FooProperty, "initial"); target.Bind(Class1.FooProperty, source.GetObservable(Class1.FooProperty)); target.ClearValue(Class1.FooProperty); source.SetValue(Class1.FooProperty, "newvalue"); Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty)); } [TestMethod] public void Bind_Doesnt_Set_Value_After_Reset() { Class1 target = new Class1(); Class1 source = new Class1(); source.SetValue(Class1.FooProperty, "initial"); target.Bind(Class1.FooProperty, source.GetObservable(Class1.FooProperty)); target.SetValue(Class1.FooProperty, "reset"); source.SetValue(Class1.FooProperty, "newvalue"); Assert.AreEqual("reset", target.GetValue(Class1.FooProperty)); } [TestMethod] [ExpectedException(typeof(InvalidOperationException))] public void Bind_Throws_Exception_For_Invalid_Value_Type() { Class1 target = new Class1(); target.Bind((PerspexProperty)Class1.FooProperty, Observable.Return((object)123)); } [TestMethod] public void Setting_UnsetValue_Reverts_To_Default_Value() { Class1 target = new Class1(); target.SetValue(Class1.FooProperty, "newvalue"); target.SetValue(Class1.FooProperty, PerspexProperty.UnsetValue); Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty)); } [TestMethod] public void StyleBinding_Overrides_Default_Value() { Class1 target = new Class1(); target.Bind(Class1.FooProperty, this.Single("stylevalue"), BindingPriority.Style); Assert.AreEqual("stylevalue", target.GetValue(Class1.FooProperty)); } [TestMethod] public void StyleBinding_Doesnt_Override_Local_Value() { Class1 target = new Class1(); target.SetValue(Class1.FooProperty, "newvalue"); target.Bind(Class1.FooProperty, this.Single("stylevalue"), BindingPriority.Style); Assert.AreEqual("newvalue", target.GetValue(Class1.FooProperty)); } /// /// Returns an observable that returns a single value but does not complete. /// /// The type of the observable. /// The value. /// The observable. private IObservable Single(T value) { return Observable.Never().StartWith(value); } private class Class1 : PerspexObject { public static readonly PerspexProperty FooProperty = PerspexProperty.Register("Foo", "foodefault"); public static readonly PerspexProperty BazProperty = PerspexProperty.Register("Baz", "bazdefault", true); } private class Class2 : Class1 { public static readonly PerspexProperty BarProperty = PerspexProperty.Register("Bar", "bardefault"); static Class2() { FooProperty.OverrideDefaultValue(typeof(Class2), "foooverride"); } public Class1 Parent { get { return (Class1)this.InheritanceParent; } set { this.InheritanceParent = value; } } } } }