diff options
Diffstat (limited to 'Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs')
-rw-r--r-- | Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs | 1326 |
1 files changed, 1326 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs b/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs new file mode 100644 index 00000000..7c4bac7a --- /dev/null +++ b/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs @@ -0,0 +1,1326 @@ +using System; +using System.Globalization; +using NUnit.Framework; + +namespace Xamarin.Forms.Core.UnitTests +{ + [TypeConverter (typeof(ToBarConverter))] + internal class Bar + { + + } + + internal class Baz + { + + } + + internal class MockBindable + : VisualElement + { + public static readonly BindableProperty TextProperty = BindableProperty.Create<MockBindable, string> ( + b => b.Text, "default", BindingMode.TwoWay); + + public string Text + { + get { return (string)GetValue (TextProperty); } + set { SetValue (TextProperty, value); } + } + + public string Foo { get; set; } + + public int TargetInt { get; set; } + + public static readonly BindableProperty BarProperty = + BindableProperty.Create<MockBindable, Bar> (w => w.Bar, default(Bar)); + + public Bar Bar { + get { return (Bar)GetValue (BarProperty); } + set { SetValue (BarProperty, value); } + } + + public static readonly BindableProperty BazProperty = + BindableProperty.Create<MockBindable, Baz> (w => w.Baz, default(Baz)); + + [TypeConverter (typeof (ToBazConverter))] + public Baz Baz { + get { return (Baz)GetValue (BazProperty); } + set { SetValue (BazProperty, value); } + } + + public static readonly BindableProperty QuxProperty = + BindableProperty.Create<MockBindable, Baz> (w => w.Qux, default(Baz)); + + public Baz Qux { + get { return (Baz)GetValue (QuxProperty); } + set { SetValue (QuxProperty, value); } + } + } + + internal class ToBarConverter : TypeConverter + { + public override object ConvertFrom (System.Globalization.CultureInfo culture, object value) + { + return new Bar (); + } + } + + internal class ToBazConverter : TypeConverter + { + public override object ConvertFrom (System.Globalization.CultureInfo culture, object value) + { + return new Baz (); + } + } + + [TestFixture] + public class BindableObjectUnitTests : BaseTestFixture + { + [SetUp] + public void Setup() + { + Device.PlatformServices = new MockPlatformServices (); + } + + [TearDown] + public void TearDown() + { + Device.PlatformServices = null; + } + + [Test] + public void BindingContext() + { + var mock = new MockBindable(); + Assert.IsNull (mock.BindingContext); + + object obj = new object(); + mock.BindingContext = obj; + Assert.AreSame (obj, mock.BindingContext); + } + + [Test] + public void BindingContextChangedEvent() + { + var mock = new MockBindable(); + mock.BindingContextChanged += (sender, args) => Assert.Pass(); + + mock.BindingContext = new object(); + + Assert.Fail ("The BindingContextChanged event was not fired."); + } + + [Test] + [Description ("When the BindingContext changes, any bindings should be immediately applied.")] + public void BindingContextChangedBindingsApplied() + { + var mock = new MockBindable(); + mock.SetBinding (MockBindable.TextProperty, new Binding (".")); + mock.BindingContext = "Test"; + + Assert.AreEqual ("Test", mock.GetValue (MockBindable.TextProperty)); + + mock.BindingContext = "Testing"; + + Assert.AreEqual ("Testing", mock.GetValue (MockBindable.TextProperty), + "Bindings were not reapplied to the new binding context"); + } + + [Test] + [Description ("When the BindingContext changes, the new context needs to listen for updates.")] + public void BindingContextChangedBindingsListening() + { + var mock = new MockBindable(); + mock.SetBinding (MockBindable.TextProperty, new Binding ("Text")); + + var vm = new MockViewModel(); + mock.BindingContext = vm; + + mock.BindingContext = (vm = new MockViewModel()); + + vm.Text = "test"; + + Assert.AreEqual ("test", mock.GetValue (MockBindable.TextProperty), + "The new ViewModel was not being listened to after being set"); + } + + [Test] + [Description ("When an INPC implementer is unset as the BindingContext, its changes shouldn't be listened to any further.")] + public void BindingContextUnsetStopsListening() + { + var mock = new MockBindable(); + mock.SetBinding (MockBindable.TextProperty, new Binding ("Text")); + + var vm = new MockViewModel(); + mock.BindingContext = vm; + + mock.BindingContext = null; + + vm.Text = "test"; + + Assert.IsNull (mock.GetValue (Entry.TextProperty), "ViewModel was still being listened to after set to null"); + } + + [Test] + public void PropertyChanging() + { + var mock = new MockBindable(); + mock.PropertyChanging += (sender, args) => { + Assert.AreEqual (MockBindable.TextProperty.PropertyName, args.PropertyName); + Assert.AreEqual (MockBindable.TextProperty.DefaultValue, mock.GetValue (MockBindable.TextProperty)); + Assert.Pass(); + }; + + mock.SetValue (MockBindable.TextProperty, "foo"); + + Assert.Fail ("The PropertyChanging event was not fired."); + } + + [Test] + public void PropertyChangingSameValue() + { + const string value = "foo"; + + var mock = new MockBindable(); + mock.SetValue (MockBindable.TextProperty, value); + mock.PropertyChanging += (s,e) => Assert.Fail(); + + mock.SetValue (MockBindable.TextProperty, value); + + Assert.Pass(); + } + + [Test] + public void PropertyChangingDefaultValue() + { + var prop = BindableProperty.Create<MockBindable, string> (w => w.Foo, "DefaultValue"); + + var mock = new MockBindable(); + mock.PropertyChanging += (s,e) => Assert.Fail(); + mock.SetValue (prop, prop.DefaultValue); + + Assert.Pass(); + } + + [Test] + public void PropertyChanged() + { + const string value = "foo"; + + var mock = new MockBindable(); + mock.PropertyChanged += (sender, args) => { + Assert.AreEqual (MockBindable.TextProperty.PropertyName, args.PropertyName); + Assert.AreEqual (value, mock.GetValue (MockBindable.TextProperty)); + Assert.Pass(); + }; + + mock.SetValue (MockBindable.TextProperty, value); + + Assert.Fail ("The PropertyChanged event was not fired."); + } + + [Test] + public void PropertyChangedSameValue() + { + const string value = "foo"; + + var mock = new MockBindable(); + mock.SetValue (MockBindable.TextProperty, value); + mock.PropertyChanged += (s,e) => Assert.Fail(); + + mock.SetValue (MockBindable.TextProperty, value); + + Assert.Pass(); + } + + [Test] + public void PropertyChangedDefaultValue() + { + var prop = BindableProperty.Create<MockBindable, string> (w => w.Foo, "DefaultValue"); + + var mock = new MockBindable(); + mock.PropertyChanged += (s,e) => Assert.Fail(); + + mock.SetValue (prop, prop.DefaultValue); + + Assert.Pass(); + } + + [Test] + public void GetSetValue() + { + const string value = "foo"; + var mock = new MockBindable(); + mock.SetValue (MockBindable.TextProperty, value); + + Assert.AreEqual (value, mock.GetValue (MockBindable.TextProperty)); + } + + [Test] + public void GetValueDefault() + { + var nulldefault = BindableProperty.Create<MockBindable, string> (w => w.Foo, null); + TestGetValueDefault (nulldefault); + + var foodefault = BindableProperty.Create<MockBindable, string> (w => w.Foo, "Foo"); + TestGetValueDefault (foodefault); + } + + void TestGetValueDefault (BindableProperty property) + { + var mock = new MockBindable(); + object value = mock.GetValue (property); + Assert.AreEqual (property.DefaultValue, value); + } + + [Test] + public void SetValueInvalid() + { + var mock = new MockBindable(); + Assert.Throws<ArgumentNullException> (() => mock.SetValue ((BindableProperty)null, "null")); + } + + [Test] + public void GetValueInvalid() + { + var mock = new MockBindable(); + Assert.Throws<ArgumentNullException> (() => mock.GetValue (null)); + } + + [Test] + public void ClearValueInvalid() + { + var mock = new MockBindable(); + Assert.Throws<ArgumentNullException> (() => mock.ClearValue ((BindableProperty)null)); + } + + [Test] + public void ClearValue() + { + const string value = "foo"; + var mock = new MockBindable(); + mock.SetValue (MockBindable.TextProperty, value); + Assert.AreEqual (value, mock.GetValue (MockBindable.TextProperty)); + + mock.ClearValue (MockBindable.TextProperty); + TestGetValueDefault (MockBindable.TextProperty); + } + + [Test] + public void ClearValueTriggersINPC () + { + var bindable = new MockBindable (); + bool changingfired = false; + bool changedfired = false; + bool changingdelegatefired = false; + bool changeddelegatefired = false; + var property = BindableProperty.Create ("Foo", typeof(string), typeof(MockBindable), "foo", + propertyChanged: (b, o, n) => changeddelegatefired = true, + propertyChanging: (b, o, n) => changingdelegatefired = true + ); + bindable.PropertyChanged += (sender, e) => { changedfired |= e.PropertyName == "Foo"; }; + bindable.PropertyChanging += (sender, e) => { changingfired |= e.PropertyName == "Foo"; }; + + bindable.SetValue (property, "foobar"); + changingfired = changedfired = changeddelegatefired = changingdelegatefired = false; + + bindable.ClearValue (property); + Assert.True (changingfired); + Assert.True (changedfired); + Assert.True (changingdelegatefired); + Assert.True (changeddelegatefired); + } + + [Test] + public void ClearValueDoesNotTriggersINPCOnSameValues () + { + var bindable = new MockBindable (); + bool changingfired = false; + bool changedfired = false; + bool changingdelegatefired = false; + bool changeddelegatefired = false; + var property = BindableProperty.Create ("Foo", typeof(string), typeof(MockBindable), "foo", + propertyChanged: (b, o, n) => changeddelegatefired = true, + propertyChanging: (b, o, n) => changingdelegatefired = true + ); + bindable.PropertyChanged += (sender, e) => { changedfired |= e.PropertyName == "Foo"; }; + bindable.PropertyChanging += (sender, e) => { changingfired |= e.PropertyName == "Foo"; }; + + bindable.SetValue (property, "foobar"); + bindable.SetValue (property, "foo"); + changingfired = changedfired = changeddelegatefired = changingdelegatefired = false; + + bindable.ClearValue (property); + Assert.False (changingfired); + Assert.False (changedfired); + Assert.False (changingdelegatefired); + Assert.False (changeddelegatefired); + } + + [Test] + public void SetBindingInvalid() + { + var mock = new MockBindable(); + Assert.Throws<ArgumentNullException> (() => mock.SetBinding (null, new Binding ("."))); + Assert.Throws<ArgumentNullException> (() => mock.SetBinding (MockBindable.TextProperty, null)); + } + + [Test] + public void RemoveUnaddedBinding() + { + var mock = new MockBindable(); + Assert.That (() => mock.RemoveBinding (MockBindable.TextProperty), Throws.Nothing); + } + + [Test] + public void RemoveBindingInvalid() + { + var mock = new MockBindable(); + Assert.Throws<ArgumentNullException> (() => mock.RemoveBinding (null)); + } + + [Test] + public void RemovedBindingDoesNotUpdate() + { + const string newvalue = "New Value"; + var viewmodel = new MockViewModel { + Text = "Foo" + }; + + var binding = new Binding ("Text"); + + var bindable = new MockBindable(); + bindable.BindingContext = viewmodel; + bindable.SetBinding (MockBindable.TextProperty, binding); + + string original = (string)bindable.GetValue (MockBindable.TextProperty); + + bindable.RemoveBinding (MockBindable.TextProperty); + + viewmodel.Text = newvalue; + Assert.AreEqual (original, bindable.GetValue (MockBindable.TextProperty), + "Property updated from a removed binding"); + } + + [Test] + public void CoerceValue() + { + var property = BindableProperty.Create<MockBindable, string> (w => w.Foo, null, + coerceValue: (bo, o) => o.ToUpper()); + + const string value = "value"; + var mock = new MockBindable(); + mock.SetValue (property, value); + Assert.AreEqual (value.ToUpper(), mock.GetValue (property)); + } + + [Test] + public void ValidateValue() + { + var property = BindableProperty.Create<MockBindable, string> (w => w.Foo, null, + validateValue: (b, v) => false); + + var mock = new MockBindable(); + Assert.Throws<ArgumentException> (() => mock.SetValue (property, null)); + } + + [Test] + public void BindablePropertyChanged() + { + bool changed = false; + + string oldv = "bar"; + string newv = "foo"; + + var property = BindableProperty.Create<MockBindable, string> (w => w.Foo, oldv, + propertyChanged: (b, ov, nv) => { + Assert.AreSame (oldv, ov); + Assert.AreSame (newv, nv); + changed = true; + }); + + var mock = new MockBindable(); + mock.SetValue (property, newv); + + Assert.IsTrue (changed, "PropertyChanged was not called"); + } + + [Test] + public void RecursiveChange () + { + bool changedA1 = false, changedA2 = false, changedB1 = false, changedB2 = false; + + var mock = new MockBindable (); + mock.PropertyChanged += (sender, args) => { + if (!changedA1) { + Assert.AreEqual ("1", mock.GetValue (MockBindable.TextProperty)); + Assert.IsFalse (changedA2); + Assert.IsFalse (changedB1); + Assert.IsFalse (changedB2); + mock.SetValue (MockBindable.TextProperty, "2"); + changedA1 = true; + } else { + Assert.AreEqual ("2", mock.GetValue (MockBindable.TextProperty)); + Assert.IsFalse (changedA2); + Assert.IsTrue (changedB1); + Assert.IsFalse (changedB2); + changedA2 = true; + } + }; + mock.PropertyChanged += (sender, args) => { + if (!changedB1) { + Assert.AreEqual ("1", mock.GetValue (MockBindable.TextProperty)); + Assert.IsTrue (changedA1); + Assert.IsFalse (changedA2); + Assert.IsFalse (changedB2); + changedB1 = true; + } else { + Assert.AreEqual ("2", mock.GetValue (MockBindable.TextProperty)); + Assert.IsTrue (changedA1); + Assert.IsTrue (changedA2); + Assert.IsFalse (changedB2); + changedB2 = true; + } + }; + mock.SetValue (MockBindable.TextProperty, "1"); + Assert.AreEqual ("2", mock.GetValue (MockBindable.TextProperty)); + Assert.IsTrue (changedA1); + Assert.IsTrue (changedA2); + Assert.IsTrue (changedB1); + Assert.IsTrue (changedB2); + } + + [Test] + public void RaiseOnEqual() + { + string foo = "foo"; + var mock = new MockBindable(); + mock.SetValue (MockBindable.TextProperty, foo); + + bool changing = false; + mock.PropertyChanging += (o, e) => { + Assert.That (e.PropertyName, Is.EqualTo (MockBindable.TextProperty.PropertyName)); + changing = true; + }; + + bool changed = true; + mock.PropertyChanged += (o, e) => { + Assert.That (e.PropertyName, Is.EqualTo (MockBindable.TextProperty.PropertyName)); + changed = true; + }; + + mock.SetValueCore (MockBindable.TextProperty, foo, + BindableObject.SetValueFlags.ClearOneWayBindings | BindableObject.SetValueFlags.ClearDynamicResource | BindableObject.SetValueFlags.RaiseOnEqual); + + Assert.That (changing, Is.True, "PropertyChanging event did not fire"); + Assert.That (changed, Is.True, "PropertyChanged event did not fire"); + } + + [Test] + public void BindingContextGetter () + { + var label = new Label (); + var view = new StackLayout { Children = {label} }; + + view.BindingContext = new {item0 = "Foo", item1 = "Bar"}; + label.SetBinding (BindableObject.BindingContextProperty, "item0"); + label.SetBinding (Label.TextProperty, Binding.SelfPath); + + Assert.AreSame (label.BindingContext, label.GetValue (BindableObject.BindingContextProperty)); + } + + [Test] + public void BoundBindingContextUpdate () + { + var label = new Label (); + var view = new StackLayout { Children = {label} }; + var vm = new MockViewModel { Text = "FooBar" }; + + view.BindingContext = vm; + label.SetBinding (BindableObject.BindingContextProperty, "Text"); + label.SetBinding (Label.TextProperty, Binding.SelfPath); + + Assert.AreEqual ("FooBar", label.BindingContext); + + vm.Text = "Baz"; + Assert.AreEqual ("Baz", label.BindingContext); + } + + [Test] + public void BoundBindingContextChange () + { + var label = new Label (); + var view = new StackLayout { Children = {label} }; + + view.BindingContext = new MockViewModel { Text = "FooBar" };; + label.SetBinding (BindableObject.BindingContextProperty, "Text"); + label.SetBinding (Label.TextProperty, Binding.SelfPath); + + Assert.AreEqual ("FooBar", label.BindingContext); + + view.BindingContext = new MockViewModel { Text = "Baz" };; + Assert.AreEqual ("Baz", label.BindingContext); + } + + [Test] + public void TestReadOnly () + { + var bindablePropertyKey = BindableProperty.CreateReadOnly<MockBindable, string> (w => w.Foo, "DefaultValue"); + var bindableProperty = bindablePropertyKey.BindableProperty; + + var bindable = new MockBindable (); + Assert.AreEqual ("DefaultValue", bindable.GetValue (bindableProperty)); + + bindable.SetValue (bindablePropertyKey, "Bar"); + Assert.AreEqual ("Bar", bindable.GetValue (bindableProperty)); + + Assert.Throws<InvalidOperationException> (() => bindable.SetValue (bindableProperty, "Baz")); + Assert.AreEqual ("Bar", bindable.GetValue (bindableProperty)); + + Assert.Throws<InvalidOperationException> (() => bindable.ClearValue (bindableProperty)); + + bindable.ClearValue (bindablePropertyKey); + Assert.AreEqual ("DefaultValue", bindable.GetValue (bindableProperty)); + } + + [Test] + public void TestBindingTwoWayOnReadOnly () + { + var bindablePropertyKey = BindableProperty.CreateReadOnly<MockBindable, string> (w => w.Foo, "DefaultValue", BindingMode.OneWayToSource); + var bindableProperty = bindablePropertyKey.BindableProperty; + + var bindable = new MockBindable (); + var vm = new MockViewModel (); + + bindable.SetBinding (bindableProperty, new Binding ("Text", BindingMode.TwoWay)); + Assert.DoesNotThrow (() => bindable.BindingContext = vm); + + Assert.AreEqual ("DefaultValue", bindable.GetValue (bindableProperty)); + } + + [Test] + public void DefaultValueCreator () + { + int invoked = 0; + object defaultValue = new object (); + var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), defaultValue, defaultValueCreator: o => { + invoked++; + return new object (); + }); + var bindable = new MockBindable (); + + Assert.AreSame (defaultValue, bindableProperty.DefaultValue); + var newvalue = bindable.GetValue (bindableProperty); + Assert.AreNotSame (defaultValue, newvalue); + Assert.NotNull (newvalue); + Assert.AreEqual (1, invoked); + } + + [Test] + public void DefaultValueCreatorIsInvokedOnlyAtFirstTime () + { + int invoked = 0; + var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), null, defaultValueCreator: o => { + invoked++; + return new object (); + }); + var bindable = new MockBindable (); + + var value0 = bindable.GetValue (bindableProperty); + var value1 = bindable.GetValue (bindableProperty); + Assert.NotNull (value0); + Assert.NotNull (value1); + Assert.AreSame (value0, value1); + Assert.AreEqual (1, invoked); + } + + [Test] + public void DefaultValueCreatorNotSharedAccrossInstances () + { + int invoked = 0; + var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), null, defaultValueCreator: o=> { + invoked++; + return new object (); + }); + var bindable0 = new MockBindable (); + var bindable1 = new MockBindable (); + var value0 = bindable0.GetValue (bindableProperty); + var value1 = bindable1.GetValue (bindableProperty); + + Assert.AreNotSame (value0, value1); + Assert.AreEqual (2, invoked); + } + + [Test] + public void DefaultValueCreatorInvokedAfterClearValue () + { + int invoked = 0; + var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), null, defaultValueCreator: o => { + invoked++; + return new object (); + }); + var bindable = new MockBindable (); + + Assert.AreEqual (0, invoked); + + var value0 = bindable.GetValue (bindableProperty); + Assert.NotNull (value0); + Assert.AreEqual (1, invoked); + bindable.ClearValue (bindableProperty); + + var value1 = bindable.GetValue (bindableProperty); + Assert.NotNull (value1); + Assert.AreEqual (2, invoked); + Assert.AreNotSame (value0, value1); + } + + [Test] + public void DefaultValueCreatorOnlyInvokedOnGetValue () + { + int invoked = 0; + var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), null, defaultValueCreator: o => { + invoked++; + return new object (); + }); + var bindable = new MockBindable (); + + Assert.AreEqual (0, invoked); + + var newvalue = bindable.GetValue (bindableProperty); + Assert.NotNull (newvalue); + Assert.AreEqual (1, invoked); + } + + [Test] + public void DefaultValueCreatorDoesNotTriggerINPC () + { + int invoked = 0; + int propertychanged = 0; + int changedfired = 0; + var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), null, + propertyChanged: (bindable,oldvalue,newvalue) =>{ + propertychanged ++; + }, + defaultValueCreator: o => { + invoked++; + return new object (); + }); + + var bp = new MockBindable (); + bp.PropertyChanged += (sender, e) => { + if (e.PropertyName == "Foo") + changedfired++; + }; + var value0 = bp.GetValue (bindableProperty); + Assert.NotNull (value0); + Assert.AreEqual (1, invoked); + Assert.AreEqual (0, propertychanged); + Assert.AreEqual (0, changedfired); + + } + + [Test] + public void StyleValueIsOverridenByValue () + { + var label = new Label (); + label.SetValue (Label.TextProperty, "Foo", true); + Assert.AreEqual ("Foo", label.Text); + + label.SetValue (Label.TextProperty, "Bar"); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleBindingIsOverridenByValue () + { + var label = new Label (); + label.SetBinding (Label.TextProperty, new Binding ("foo"), true); + label.BindingContext = new {foo = "Foo"}; + Assert.AreEqual ("Foo", label.Text); + + label.SetValue (Label.TextProperty, "Bar"); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleDynResourceIsOverridenByValue () + { + var label = new Label (); + label.SetDynamicResource (Label.TextProperty, "foo", true); + label.Resources = new ResourceDictionary { + {"foo", "Foo"} + }; + Assert.AreEqual ("Foo", label.Text); + + label.SetValue (Label.TextProperty, "Bar"); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleValueIsOverridenByBinding () + { + var label = new Label (); + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetValue (Label.TextProperty, "Foo", true); + Assert.AreEqual ("Foo", label.Text); + + label.SetBinding (Label.TextProperty, "bar"); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleBindingIsOverridenByBinding () + { + var label = new Label (); + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetBinding (Label.TextProperty, new Binding ("foo"), true); + Assert.AreEqual ("Foo", label.Text); + + label.SetBinding (Label.TextProperty, "bar"); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleDynResourceIsOverridenByBinding () + { + var label = new Label (); + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetDynamicResource (Label.TextProperty, "foo", true); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + }; + Assert.AreEqual ("Foo", label.Text); + + label.SetBinding (Label.TextProperty, "bar"); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleValueIsOverridenByDynResource () + { + var label = new Label (); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + {"bar", "Bar"} + }; + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetValue (Label.TextProperty, "Foo", true); + Assert.AreEqual ("Foo", label.Text); + + label.SetDynamicResource (Label.TextProperty, "bar"); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleBindingIsOverridenByDynResource () + { + var label = new Label (); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + {"bar", "Bar"} + }; + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetBinding (Label.TextProperty, new Binding ("foo"), true); + Assert.AreEqual ("Foo", label.Text); + + label.SetDynamicResource (Label.TextProperty, "bar"); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleDynResourceIsOverridenByDynResource () + { + var label = new Label (); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + {"bar", "Bar"} + }; + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetDynamicResource (Label.TextProperty, "foo", true); + + Assert.AreEqual ("Foo", label.Text); + + label.SetDynamicResource (Label.TextProperty, "bar"); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void ValueIsPreservedOnStyleValue () + { + var label = new Label (); + label.SetValue (Label.TextProperty, "Foo"); + Assert.AreEqual ("Foo", label.Text); + + label.SetValue (Label.TextProperty, "Bar", true); + Assert.AreEqual ("Foo", label.Text); + } + [Test] + public void BindingIsPreservedOnStyleValue () + { + var label = new Label (); + label.SetBinding (Label.TextProperty, new Binding ("foo")); + label.BindingContext = new {foo = "Foo"}; + Assert.AreEqual ("Foo", label.Text); + + label.SetValue (Label.TextProperty, "Bar", true); + Assert.AreEqual ("Foo", label.Text); + } + [Test] + public void DynResourceIsPreservedOnStyleValue () + { + var label = new Label (); + label.SetDynamicResource (Label.TextProperty, "foo"); + label.Resources = new ResourceDictionary { + {"foo", "Foo"} + }; + Assert.AreEqual ("Foo", label.Text); + + label.SetValue (Label.TextProperty, "Bar", true); + Assert.AreEqual ("Foo", label.Text); + } + + [Test] + public void ValueIsPreservedOnStyleBinding () + { + var label = new Label (); + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetValue (Label.TextProperty, "Foo"); + Assert.AreEqual ("Foo", label.Text); + + label.SetBinding (Label.TextProperty, new Binding ("bar"), true); + Assert.AreEqual ("Foo", label.Text); + } + + [Test] + public void BindingIsPreservedOnStyleBinding () + { + var label = new Label (); + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetBinding (Label.TextProperty, new Binding ("foo")); + Assert.AreEqual ("Foo", label.Text); + + label.SetBinding (Label.TextProperty, new Binding ("bar"), true); + Assert.AreEqual ("Foo", label.Text); + } + + [Test] + public void DynResourceIsPreservedOnStyleBinding () + { + var label = new Label (); + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetDynamicResource (Label.TextProperty, "foo"); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + }; + Assert.AreEqual ("Foo", label.Text); + + label.SetBinding (Label.TextProperty, new Binding ("bar"), true); + Assert.AreEqual ("Foo", label.Text); + } + + [Test] + public void ValueIsPreservedOnStyleDynResource () + { + var label = new Label (); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + {"bar", "Bar"} + }; + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetValue (Label.TextProperty, "Foo"); + Assert.AreEqual ("Foo", label.Text); + + label.SetDynamicResource (Label.TextProperty, "bar", true); + Assert.AreEqual ("Foo", label.Text); + } + + [Test] + public void BindingIsPreservedOnStyleDynResource () + { + var label = new Label (); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + {"bar", "Bar"} + }; + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetBinding (Label.TextProperty, new Binding ("foo")); + Assert.AreEqual ("Foo", label.Text); + + label.SetDynamicResource (Label.TextProperty, "bar", true); + Assert.AreEqual ("Foo", label.Text); + } + + [Test] + public void DynResourceIsPreservedOnStyleDynResource () + { + var label = new Label (); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + {"bar", "Bar"} + }; + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetDynamicResource (Label.TextProperty, "foo"); + + Assert.AreEqual ("Foo", label.Text); + + label.SetDynamicResource (Label.TextProperty, "bar", true); + Assert.AreEqual ("Foo", label.Text); + } + + [Test] + public void StyleValueIsOverridenByStyleValue () + { + var label = new Label (); + label.SetValue (Label.TextProperty, "Foo", true); + Assert.AreEqual ("Foo", label.Text); + + label.SetValue (Label.TextProperty, "Bar", true); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleBindingIsOverridenByStyleValue () + { + var label = new Label (); + label.SetBinding (Label.TextProperty, new Binding ("foo"), true); + label.BindingContext = new {foo = "Foo"}; + Assert.AreEqual ("Foo", label.Text); + + label.SetValue (Label.TextProperty, "Bar", true); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleDynResourceIsOverridenByStyleValue () + { + var label = new Label (); + label.SetDynamicResource (Label.TextProperty, "foo", true); + label.Resources = new ResourceDictionary { + {"foo", "Foo"} + }; + Assert.AreEqual ("Foo", label.Text); + + label.SetValue (Label.TextProperty, "Bar", true); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleValueIsOverridenByStyleBinding () + { + var label = new Label (); + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetValue (Label.TextProperty, "Foo", true); + Assert.AreEqual ("Foo", label.Text); + + label.SetBinding (Label.TextProperty, new Binding("bar"), true); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleBindingIsOverridenByStyleBinding () + { + var label = new Label (); + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetBinding (Label.TextProperty, new Binding ("foo"), true); + Assert.AreEqual ("Foo", label.Text); + + label.SetBinding (Label.TextProperty, new Binding("bar"), true); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleDynResourceIsOverridenByStyleBinding () + { + var label = new Label (); + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetDynamicResource (Label.TextProperty, "foo", true); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + }; + Assert.AreEqual ("Foo", label.Text); + + label.SetBinding (Label.TextProperty, new Binding("bar"), true); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleValueIsOverridenByStyleDynResource () + { + var label = new Label (); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + {"bar", "Bar"} + }; + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetValue (Label.TextProperty, "Foo", true); + Assert.AreEqual ("Foo", label.Text); + + label.SetDynamicResource (Label.TextProperty, "bar", true); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleBindingIsOverridenByStyleDynResource () + { + var label = new Label (); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + {"bar", "Bar"} + }; + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetBinding (Label.TextProperty, new Binding ("foo"), true); + Assert.AreEqual ("Foo", label.Text); + + label.SetDynamicResource (Label.TextProperty, "bar", true); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void StyleDynResourceIsOverridenByStyleDynResource () + { + var label = new Label (); + label.Resources = new ResourceDictionary { + {"foo", "Foo"}, + {"bar", "Bar"} + }; + label.BindingContext = new {foo = "Foo", bar = "Bar"}; + label.SetDynamicResource (Label.TextProperty, "foo", true); + + Assert.AreEqual ("Foo", label.Text); + + label.SetDynamicResource (Label.TextProperty, "bar", true); + Assert.AreEqual ("Bar", label.Text); + } + + [Test] + public void SetValueCoreImplicitelyCastBasicType () + { + var prop = BindableProperty.Create ("Foo", typeof(int), typeof(MockBindable), 0); + var bindable = new MockBindable (); + + Assert.DoesNotThrow (() => bindable.SetValue (prop, (object)(short)42)); + Assert.AreEqual (42, bindable.GetValue (prop)); + + bindable.SetValue (prop, (object)(long)-42); + Assert.AreNotEqual (-42, bindable.GetValue (prop)); + } + + class CastFromString + { + public string Result { get; private set; } + public static implicit operator CastFromString (string source) + { + var o = new CastFromString (); + o.Result = source; + return o; + } + } + + [Test] + public void SetValueCoreInvokesOpImplicitOnPropertyType () + { + var prop = BindableProperty.Create ("Foo", typeof(CastFromString), typeof(MockBindable), null); + var bindable = new MockBindable (); + + Assert.Null (bindable.GetValue (prop)); + bindable.SetValue (prop, "foo"); + + Assert.AreEqual ("foo", ((CastFromString)bindable.GetValue (prop)).Result); + } + + class CastToString + { + string Result { get; set; } + + public CastToString (string result) + { + Result = result; + } + + public static implicit operator string (CastToString source) + { + return source.Result; + } + + public override string ToString () + { + throw new InvalidOperationException (); + } + } + + [Test] + public void SetValueCoreInvokesOpImplicitOnValue () + { + var prop = BindableProperty.Create ("Foo", typeof(string), typeof(MockBindable), null); + var bindable = new MockBindable (); + + Assert.Null (bindable.GetValue (prop)); + bindable.SetValue (prop, new CastToString ("foo")); + + Assert.AreEqual ("foo", bindable.GetValue (prop)); + } + + [Test] + public void DefaultValueCreatorCalledForChangeDelegates () + { + int changedOld = -1; + int changedNew = -1; + + int changingOld = -1; + int changingNew = -1; + var prop = BindableProperty.Create ("Foo", typeof (int), typeof (MockBindable), 0, defaultValueCreator: b => 10, + propertyChanged: (b, value, newValue) => { + changedOld = (int) value; + changedNew = (int) newValue; + }, + propertyChanging: (b, value, newValue) => { + changingOld = (int) value; + changingNew = (int) newValue; + }); + + var bindable = new MockBindable (); + + + var defaultValue = (int) bindable.GetValue (prop); + + Assert.AreEqual (10, defaultValue); + + bindable.SetValue (prop, 5); + + bindable.ClearValue (prop); + + Assert.AreEqual (5, changedOld); + Assert.AreEqual (5, changingOld); + Assert.AreEqual (10, changedNew); + Assert.AreEqual (10, changingNew); + } + + [Test] + public void GetValuesDefaults() + { + var prop = BindableProperty.Create ("Foo", typeof(int), typeof(MockBindable), 0); + var prop1 = BindableProperty.Create ("Foo1", typeof(int), typeof(MockBindable), 1); + var prop2 = BindableProperty.Create ("Foo2", typeof(int), typeof(MockBindable), 2); + var bindable = new MockBindable (); + + + object[] values = bindable.GetValues (prop, prop1, prop2); + Assert.That (values.Length == 3); + Assert.That (values[0], Is.EqualTo (0)); + Assert.That (values[1], Is.EqualTo (1)); + Assert.That (values[2], Is.EqualTo (2)); + } + + [Test] + public void GetValues() + { + var prop = BindableProperty.Create ("Foo", typeof(int), typeof(MockBindable), 0); + var prop1 = BindableProperty.Create ("Foo1", typeof(int), typeof(MockBindable), 1); + var prop2 = BindableProperty.Create ("Foo2", typeof(int), typeof(MockBindable), 2); + var bindable = new MockBindable (); + bindable.SetValue (prop, 3); + bindable.SetValue (prop2, 5); + + + object[] values = bindable.GetValues (prop, prop1, prop2); + Assert.That (values.Length == 3); + Assert.That (values[0], Is.EqualTo (3)); + Assert.That (values[1], Is.EqualTo (1)); + Assert.That (values[2], Is.EqualTo (5)); + } + + class BindingContextConverter + : IValueConverter + { + public object Convert (object value, Type targetType, object parameter, CultureInfo culture) + { + return new MockViewModel { Text = value + "Converted" }; + } + + public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } + + [Test] + //https://bugzilla.xamarin.com/show_bug.cgi?id=24485 + public void BindingContextBoundThroughConverter() + { + var bindable = new MockBindable(); + bindable.BindingContext = "test"; + bindable.SetBinding (BindableObject.BindingContextProperty, new Binding (".", converter: new BindingContextConverter())); + bindable.SetBinding (MockBindable.TextProperty, "Text"); + + Assert.That (() => bindable.Text, Is.EqualTo ("testConverted")); + } + + public class VMLocator + { + public event EventHandler Invoked; + public int Count; + public object VM { + get { + Count++; + var eh = Invoked; + if (eh != null) + eh (this, EventArgs.Empty); + return new object (); + } + } + } + + [Test] + //https://bugzilla.xamarin.com/show_bug.cgi?id=27299 + public void BindingOnBindingContextDoesntReapplyBindingContextBinding () + { + var bindable = new MockBindable (); + var locator = new VMLocator (); + Assert.AreEqual (0, locator.Count); + locator.Invoked += (sender, e) => Assert.IsTrue (locator.Count <= 1); + bindable.SetBinding (BindableObject.BindingContextProperty, new Binding ("VM", source: locator)); + Assert.IsTrue (locator.Count == 1); + } + + [Test] + public void BindingsEditableAfterUnapplied() + { + var bindable = new MockBindable(); + + var binding = new Binding ("."); + bindable.SetBinding (MockBindable.TextProperty, binding); + bindable.BindingContext = "foo"; + + Assume.That (bindable.Text, Is.EqualTo (bindable.BindingContext)); + + bindable.RemoveBinding (MockBindable.TextProperty); + + Assert.That (() => binding.Path = "foo", Throws.Nothing); + } + + [Test] + // https://bugzilla.xamarin.com/show_bug.cgi?id=24054 + public void BindingsAppliedUnappliedWithNullContext() + { + var bindable = new MockBindable(); + + var binding = new Binding ("."); + bindable.SetBinding (MockBindable.TextProperty, binding); + bindable.BindingContext = "foo"; + + Assume.That (bindable.Text, Is.EqualTo (bindable.BindingContext)); + + bindable.BindingContext = null; + + Assume.That (bindable.Text, Is.EqualTo (bindable.BindingContext)); + + bindable.BindingContext = "bar"; + + Assume.That (bindable.Text, Is.EqualTo (bindable.BindingContext)); + + bindable.RemoveBinding (MockBindable.TextProperty); + + Assert.That (() => binding.Path = "Foo", Throws.Nothing); + } + } +}
\ No newline at end of file |