public void Validation_Plugins_Send_Correct_Notifications() { var data = new IndeiTest(); var observer = new ExpressionObserver(data, nameof(data.MustBePositive), true); var result = new List<object>(); observer.Subscribe(x => result.Add(x)); observer.SetValue(5); observer.SetValue(-5); observer.SetValue("foo"); observer.SetValue(5); Assert.Equal(new[] { new BindingNotification(0), // Value is notified twice as ErrorsChanged is always called by IndeiTest. new BindingNotification(5), new BindingNotification(5), // Value is first signalled without an error as validation hasn't been updated. new BindingNotification(-5), new BindingNotification(new Exception("Must be positive"), BindingErrorType.DataValidationError, -5), // Exception is thrown by trying to set value to "foo". new BindingNotification( new ArgumentException("Object of type 'System.String' cannot be converted to type 'System.Int32'."), BindingErrorType.DataValidationError), // Value is set then validation is updated. new BindingNotification(new Exception("Must be positive"), BindingErrorType.DataValidationError, 5), new BindingNotification(5), }, result); }
public ExpressionObserver CreateExpressionObserver( IObservablePropertyBag instance, PerspexProperty property) { IObservable<object> dataContext = null; if (property != Control.DataContextProperty) { dataContext = instance.GetObservable(Control.DataContextProperty); } else { var parent = instance.InheritanceParent as IObservablePropertyBag; if (parent != null) { dataContext = parent.GetObservable(Control.DataContextProperty); } } if (dataContext != null) { var result = new ExpressionObserver(null, SourcePropertyPath); dataContext.Subscribe(x => result.Root = x); return result; } return null; }
public void Should_Get_Simple_Property_Value_Type() { var data = new { Foo = "foo" }; var target = new ExpressionObserver(data, "Foo"); Assert.Equal(typeof(string), target.ResultType); }
public void Should_Get_Simple_Property_Chain_Type() { var data = new { Foo = new { Bar = new { Baz = "baz" } } }; var target = new ExpressionObserver(data, "Foo.Bar.Baz"); Assert.Equal(typeof(string), target.ResultType); }
public void Should_Have_Null_ResultType_For_Broken_Chain() { var data = new { Foo = new { Bar = 1 } }; var target = new ExpressionObserver(data, "Foo.Bar.Baz"); Assert.Null(target.ResultType); }
public async void Should_Return_UnsetValue_For_String_Not_Convertible_To_Boolean() { var data = new { Foo = "foo" }; var target = new ExpressionObserver(data, "!Foo"); var result = await target.Take(1); Assert.Equal(AvaloniaProperty.UnsetValue, result); }
public async void Should_Return_UnsetValue_For_Root_UnsetValue() { var data = new Class3 { Foo = "foo" }; var target = new ExpressionObserver(AvaloniaProperty.UnsetValue, "Foo"); var result = await target.Take(1); Assert.Equal(AvaloniaProperty.UnsetValue, result); }
public async void Should_Get_Simple_Property_Value() { var data = new Class1(); var target = new ExpressionObserver(data, "Foo"); var result = await target.Take(1); Assert.Equal("foo", result); }
public async void Should_Get_Simple_Property_From_Base_Class() { var data = new Class3 { Foo = "foo" }; var target = new ExpressionObserver(data, "Foo"); var result = await target.Take(1); Assert.Equal("foo", result); }
public async void Should_Get_Simple_Property_Chain() { var data = new { Foo = new { Bar = new { Baz = "baz" } } }; var target = new ExpressionObserver(data, "Foo.Bar.Baz"); var result = await target.Take(1); Assert.Equal("baz", result); }
public async void Should_Get_Simple_Property_Value_Null() { var data = new { Foo = (string)null }; var target = new ExpressionObserver(data, "Foo"); var result = await target.Take(1); Assert.Null(result); }
public async void Should_Not_Have_Value_For_Broken_Chain() { var data = new { Foo = new { Bar = 1 } }; var target = new ExpressionObserver(data, "Foo.Bar.Baz"); var result = await target.Take(1); Assert.Equal(PerspexProperty.UnsetValue, result); }
public async void Should_Negate_0() { var data = new { Foo = 0 }; var target = new ExpressionObserver(data, "!Foo"); var result = await target.Take(1); Assert.Equal(true, result); }
public async void Should_Get_UnsetValue_For_Invalid_Dictionary_Index() { var data = new { Foo = new Dictionary<int, string> { { 1, "foo" } } }; var target = new ExpressionObserver(data, "Foo[invalid]"); var result = await target.Take(1); Assert.Equal(AvaloniaProperty.UnsetValue, result); }
public async void Should_Get_Array_Value() { var data = new { Foo = new [] { "foo", "bar" } }; var target = new ExpressionObserver(data, "Foo[1]"); var result = await target.Take(1); Assert.Equal("bar", result); }
public async void Should_Negate_Boolean_Value() { var data = new { Foo = true }; var target = new ExpressionObserver(data, "!Foo"); var result = await target.Take(1); Assert.Equal(false, result); }
public async void Should_Negate_True_String() { var data = new { Foo = "True" }; var target = new ExpressionObserver(data, "!Foo"); var result = await target.Take(1); Assert.Equal(false, result); }
public async void Array_Out_Of_Bounds_Should_Return_UnsetValue() { var data = new { Foo = new[] { "foo", "bar" } }; var target = new ExpressionObserver(data, "Foo[2]"); var result = await target.Take(1); Assert.Equal(AvaloniaProperty.UnsetValue, result); }
public async void Should_Return_Empty_For_Value_Not_Convertible_To_Boolean() { var data = new { Foo = new object() }; var target = new ExpressionObserver(data, "!Foo"); var result = await target.Take(1); Assert.Equal(PerspexProperty.UnsetValue, result); }
public async void Array_With_Wrong_Dimensions_Should_Return_UnsetValue() { var data = new { Foo = new[] { "foo", "bar" } }; var target = new ExpressionObserver(data, "Foo[1,2]"); var result = await target.Take(1); Assert.Equal(PerspexProperty.UnsetValue, result); }
public async void List_Out_Of_Bounds_Should_Return_UnsetValue() { var data = new { Foo = new List<string> { "foo", "bar" } }; var target = new ExpressionObserver(data, "Foo[2]"); var result = await target.Take(1); Assert.Equal(PerspexProperty.UnsetValue, result); }
public async void Should_Get_UnsetValue_For_Invalid_Array_Index() { var data = new { Foo = new[] { "foo", "bar" } }; var target = new ExpressionObserver(data, "Foo[invalid]"); var result = await target.Take(1); Assert.Equal(AvaloniaProperty.UnsetValue, result); }
public async void Should_Return_UnsetValue_For_Observable_Root_Null() { var data = new Class3 { Foo = "foo" }; var target = new ExpressionObserver(Observable.Return(default(object)), "Foo"); var result = await target.Take(1); Assert.Equal(AvaloniaProperty.UnsetValue, result); }
public async void Should_Get_UnsetValue_For_Object_Without_Indexer() { var data = new { Foo = 5 }; var target = new ExpressionObserver(data, "Foo[noindexer]"); var result = await target.Take(1); Assert.Equal(AvaloniaProperty.UnsetValue, result); }
public async void Should_Get_MultiDimensional_Array_Value() { var data = new { Foo = new[,] { { "foo", "bar" }, { "baz", "qux" } } }; var target = new ExpressionObserver(data, "Foo[1, 1]"); var result = await target.Take(1); Assert.Equal("qux", result); }
public async void Should_Get_Value_For_String_Indexer() { var data = new { Foo = new Dictionary<string, string> { { "foo", "bar" }, { "baz", "qux" } } }; var target = new ExpressionObserver(data, "Foo[foo]"); var result = await target.Take(1); Assert.Equal("bar", result); }
public async void Should_Get_Value_For_Non_String_Indexer() { var data = new { Foo = new Dictionary<double, string> { { 1.0, "bar" }, { 2.0, "qux" } } }; var target = new ExpressionObserver(data, "Foo[1.0]"); var result = await target.Take(1); Assert.Equal("bar", result); }
public void Exception_Validation_Sends_ValidationUpdate() { var data = new ExceptionTest { MustBePositive = 5 }; var observer = new ExpressionObserver(data, nameof(data.MustBePositive), false); var validationMessageFound = false; observer.Where(o => o is IValidationStatus).Subscribe(_ => validationMessageFound = true); observer.SetValue(-5); Assert.True(validationMessageFound); }
public void Indei_Validation_Does_Not_Subscribe_When_DataValidatation_Not_Enabled() { var data = new IndeiTest { MustBePositive = 5 }; var observer = new ExpressionObserver(data, nameof(data.MustBePositive), false); observer.Subscribe(_ => { }); Assert.Equal(0, data.ErrorsChangedSubscriptionCount); }
public void Disabled_Indei_Validation_Does_Not_Subscribe() { var data = new IndeiTest { MustBePositive = 5 }; var observer = new ExpressionObserver(data, nameof(data.MustBePositive), false); observer.Subscribe(_ => { }); Assert.Equal(0, data.SubscriptionCount); }
public void Should_Get_Property_Value_From_Observable_With_DataValidation_Enabled() { using (var sync = UnitTestSynchronizationContext.Begin()) { var data1 = new Class1(); var data2 = new Class2("foo"); var target = ExpressionObserver.Create(data1, o => o.Next.StreamBinding().Foo, true); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); data1.Next.OnNext(data2); sync.ExecutePostedCallbacks(); Assert.Equal(new[] { new BindingNotification("foo") }, result); sub.Dispose(); Assert.Equal(0, data1.PropertyChangedSubscriptionCount); GC.KeepAlive(data1); GC.KeepAlive(data2); } }
public void Should_Get_Property_Value_From_Observable() { using (var sync = UnitTestSynchronizationContext.Begin()) { var data = new Class1(); var target = ExpressionObserver.Create(data, o => o.Next.StreamBinding().Foo); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); data.Next.OnNext(new Class2("foo")); sync.ExecutePostedCallbacks(); Assert.Equal(new[] { "foo" }, result); sub.Dispose(); // Forces WeakEvent compact Dispatcher.UIThread.RunJobs(); Assert.Equal(0, data.PropertyChangedSubscriptionCount); GC.KeepAlive(data); } }
public void Can_Replace_Root() { var first = new Class1 { Foo = "foo" }; var second = new Class1 { Foo = "bar" }; var root = first; var target = new ExpressionObserver(() => root, "Foo"); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); root = second; target.UpdateRoot(); root = null; target.UpdateRoot(); Assert.Equal(new[] { "foo", "bar", PerspexProperty.UnsetValue }, result); Assert.Equal(0, first.SubscriptionCount); Assert.Equal(0, second.SubscriptionCount); }
public void Should_Return_BindingNotification_Error_On_Task_Exception() { using (var sync = UnitTestSynchronizationContext.Begin()) { var tcs = new TaskCompletionSource <string>(); var data = new { Foo = tcs.Task }; var target = new ExpressionObserver(data, "Foo"); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); tcs.SetException(new NotSupportedException()); sync.ExecutePostedCallbacks(); Assert.Equal( new[] { new BindingNotification( new AggregateException(new NotSupportedException()), BindingErrorType.Error) }, result); } }
public void Should_Return_BindingNotification_If_Stream_Operator_Applied_To_Not_Supported_Type() { using (var sync = UnitTestSynchronizationContext.Begin()) { var data = new Class2("foo"); var target = new ExpressionObserver(data, "Foo^", true); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); sync.ExecutePostedCallbacks(); Assert.Equal( new[] { new BindingNotification( new MarkupBindingChainException("Stream operator applied to unsupported type", "Foo^", "Foo^"), BindingErrorType.Error) }, result); sub.Dispose(); } }
public void Should_Track_Simple_Property_Value() { var data = new Class1 { Foo = "foo" }; var target = ExpressionObserver.Create(data, o => o.Foo); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); data.Foo = "bar"; Assert.Equal(new[] { "foo", "bar" }, result); sub.Dispose(); // Forces WeakEvent compact Dispatcher.UIThread.RunJobs(); Assert.Equal(0, data.PropertyChangedSubscriptionCount); GC.KeepAlive(data); }
public void Should_Track_Chained_Attached_Value() { var data = new Class1 { Next = new Class1 { [Owner.FooProperty] = "foo", } }; var target = new ExpressionObserver(data, "Next.(Owner.Foo)"); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); data.Next.SetValue(Owner.FooProperty, "bar"); Assert.Equal(new[] { "foo", "bar" }, result); sub.Dispose(); Assert.Null(((IAvaloniaObjectDebug)data).GetPropertyChangedSubscribers()); }
public async Task Should_Return_BindingNotification_For_Invalid_FallbackValue_With_Data_Validation() { var data = new Class1 { StringValue = "foo" }; var target = new BindingExpression( ExpressionObserver.Create(data, o => o.StringValue, true), typeof(int), "bar", AvaloniaProperty.UnsetValue, DefaultValueConverter.Instance); var result = await target.Take(1); Assert.Equal( new BindingNotification( new AggregateException( new InvalidCastException("'foo' is not a valid number."), new InvalidCastException("Could not convert FallbackValue 'bar' to 'System.Int32'")), BindingErrorType.Error), result); GC.KeepAlive(data); }
public void Subscribing_Multiple_Times_Should_Return_Values_To_All() { var data = new Class1 { Foo = "foo" }; var target = new ExpressionObserver(data, "Foo"); var result1 = new List <object>(); var result2 = new List <object>(); var result3 = new List <object>(); target.Subscribe(x => result1.Add(x)); target.Subscribe(x => result2.Add(x)); data.Foo = "bar"; target.Subscribe(x => result3.Add(x)); Assert.Equal(new[] { "foo", "bar" }, result1); Assert.Equal(new[] { "foo", "bar" }, result2); Assert.Equal(new[] { "bar" }, result3); GC.KeepAlive(data); }
public void Should_Track_Property_Chain_Breaking_With_Missing_Member_Then_Mending() { var data = new Class1 { Next = new Class2 { Bar = "bar" } }; var target = new ExpressionObserver(data, "Next.Bar"); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); var old = data.Next; var breaking = new WithoutBar(); data.Next = breaking; data.Next = new Class2 { Bar = "baz" }; Assert.Equal( new object[] { "bar", new BindingNotification( new MissingMemberException("Could not find CLR property 'Bar' on 'Avalonia.Markup.UnitTests.Data.ExpressionObserverTests_Property+WithoutBar'"), BindingErrorType.Error), "baz", }, result); sub.Dispose(); Assert.Equal(0, data.PropertyChangedSubscriptionCount); Assert.Equal(0, data.Next.PropertyChangedSubscriptionCount); Assert.Equal(0, breaking.PropertyChangedSubscriptionCount); Assert.Equal(0, old.PropertyChangedSubscriptionCount); }
private ExpressionObserver CreateDataContextObserver( IAvaloniaObject target, string path, bool targetIsDataContext, object anchor, bool enableDataValidation) { Contract.Requires <ArgumentNullException>(target != null); if (!(target is IStyledElement)) { target = anchor as IStyledElement; if (target == null) { throw new InvalidOperationException("Cannot find a DataContext to bind to."); } } if (!targetIsDataContext) { var result = new ExpressionObserver( () => target.GetValue(StyledElement.DataContextProperty), path, new UpdateSignal(target, StyledElement.DataContextProperty), enableDataValidation); return(result); } else { return(new ExpressionObserver( GetParentDataContext(target), path, enableDataValidation)); } }
public void Can_Replace_Root() { var first = new Class1 { Foo = "foo" }; var second = new Class1 { Foo = "bar" }; var root = first; var update = new Subject <Unit>(); var target = ExpressionObserver.Create(() => root, o => o.Foo, update); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); root = second; update.OnNext(Unit.Default); root = null; update.OnNext(Unit.Default); Assert.Equal( new object[] { "foo", "bar", new BindingNotification( new MarkupBindingChainException("Null value", "o => o.Foo", string.Empty), BindingErrorType.Error, AvaloniaProperty.UnsetValue) }, result); Assert.Equal(0, first.PropertyChangedSubscriptionCount); Assert.Equal(0, second.PropertyChangedSubscriptionCount); GC.KeepAlive(first); GC.KeepAlive(second); }
public void Sends_Correct_Notifications_With_Property_Chain() { var container = new Container(); var inner = new IndeiTest(); var observer = new ExpressionObserver( container, $"{nameof(Container.Inner)}.{nameof(IndeiTest.MustBePositive)}", true); var result = new List <object>(); observer.Subscribe(x => result.Add(x)); Assert.Equal(new[] { new BindingNotification( new MarkupBindingChainException("Null value", "Inner.MustBePositive", "Inner"), BindingErrorType.Error, AvaloniaProperty.UnsetValue), }, result); GC.KeepAlive(container); GC.KeepAlive(inner); }
public void Should_Track_End_Of_Property_Chain_Changing() { var data = new Class1 { Next = new Class2 { Bar = "bar" } }; var target = new ExpressionObserver(data, "Next.Bar"); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); ((Class2)data.Next).Bar = "baz"; ((Class2)data.Next).Bar = null; Assert.Equal(new[] { "bar", "baz", null }, result); sub.Dispose(); Assert.Equal(0, data.PropertyChangedSubscriptionCount); Assert.Equal(0, data.Next.PropertyChangedSubscriptionCount); GC.KeepAlive(data); }
public void Should_Not_Keep_Source_Alive() { Func <Tuple <ExpressionObserver, WeakReference> > run = () => { var source = new Class1 { Foo = "foo" }; var target = ExpressionObserver.Create(source, o => o.Foo); return(Tuple.Create(target, new WeakReference(source))); }; var result = run(); result.Item1.Subscribe(x => { }); // Mono trickery GC.Collect(2); GC.WaitForPendingFinalizers(); GC.WaitForPendingFinalizers(); GC.Collect(2); Assert.Null(result.Item2.Target); }
protected ExpressionObserver CreateDataContextObserver( IAvaloniaObject target, ExpressionNode node, bool targetIsDataContext, object anchor) { Contract.Requires <ArgumentNullException>(target != null); if (!(target is IDataContextProvider)) { target = anchor as IDataContextProvider; if (target == null) { throw new InvalidOperationException("Cannot find a DataContext to bind to."); } } if (!targetIsDataContext) { var result = new ExpressionObserver( () => target.GetValue(StyledElement.DataContextProperty), node, new UpdateSignal(target, StyledElement.DataContextProperty), null); return(result); } else { return(new ExpressionObserver( GetParentDataContext(target), node, null)); } }
public void Can_Replace_Root() { var first = new Class1 { Foo = "foo" }; var second = new Class1 { Foo = "bar" }; var root = first; var update = new Subject <Unit>(); var target = new ExpressionObserver(() => root, "Foo", update); var result = new List <object>(); var sub = target.Subscribe(x => result.Add(x)); root = second; update.OnNext(Unit.Default); root = null; update.OnNext(Unit.Default); Assert.Equal(new[] { "foo", "bar", AvaloniaProperty.UnsetValue }, result); Assert.Equal(0, first.SubscriptionCount); Assert.Equal(0, second.SubscriptionCount); }
public async Task Null_Value_Should_Use_TargetNullValue() { var data = new Class1 { StringValue = "foo" }; var target = new BindingExpression( ExpressionObserver.Create(data, o => o.StringValue), typeof(string), AvaloniaProperty.UnsetValue, "bar", DefaultValueConverter.Instance); object result = null; target.Subscribe(x => result = x); Assert.Equal("foo", result); data.StringValue = null; Assert.Equal("bar", result); GC.KeepAlive(data); }
public void Validation_Plugins_Send_Correct_Notifications() { var data = new IndeiTest(); var observer = new ExpressionObserver(data, nameof(data.MustBePositive), true); var result = new List <object>(); observer.Subscribe(x => result.Add(x)); observer.SetValue(5); observer.SetValue(-5); observer.SetValue("foo"); observer.SetValue(5); Assert.Equal(new[] { new BindingNotification(0), // Value is notified twice as ErrorsChanged is always called by IndeiTest. new BindingNotification(5), new BindingNotification(5), // Value is first signalled without an error as validation hasn't been updated. new BindingNotification(-5), new BindingNotification(new Exception("Must be positive"), BindingErrorType.DataValidationError, -5), // Exception is thrown by trying to set value to "foo". new BindingNotification( new ArgumentException("Object of type 'System.String' cannot be converted to type 'System.Int32'."), BindingErrorType.DataValidationError), // Value is set then validation is updated. new BindingNotification(new Exception("Must be positive"), BindingErrorType.DataValidationError, 5), new BindingNotification(5), }, result); GC.KeepAlive(data); }
/// <inheritdoc/> public InstancedBinding Initiate( IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor = null, bool enableDataValidation = false) { Contract.Requires <ArgumentNullException>(target != null); anchor = anchor ?? DefaultAnchor?.Target; enableDataValidation = enableDataValidation && Priority == BindingPriority.LocalValue; ExpressionObserver observer; var(node, mode) = ExpressionObserverBuilder.Parse(Path, enableDataValidation, TypeResolver); if (ElementName != null) { observer = CreateElementObserver( (target as IStyledElement) ?? (anchor as IStyledElement), ElementName, node); } else if (Source != null) { observer = CreateSourceObserver(Source, node); } else if (RelativeSource == null) { if (mode == SourceMode.Data) { observer = CreateDataContextObserver( target, node, targetProperty == StyledElement.DataContextProperty, anchor); } else { observer = new ExpressionObserver( (target as IStyledElement) ?? (anchor as IStyledElement), node); } } else if (RelativeSource.Mode == RelativeSourceMode.DataContext) { observer = CreateDataContextObserver( target, node, targetProperty == StyledElement.DataContextProperty, anchor); } else if (RelativeSource.Mode == RelativeSourceMode.Self) { observer = CreateSourceObserver( (target as IStyledElement) ?? (anchor as IStyledElement), node); } else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent) { observer = CreateTemplatedParentObserver( (target as IStyledElement) ?? (anchor as IStyledElement), node); } else if (RelativeSource.Mode == RelativeSourceMode.FindAncestor) { if (RelativeSource.Tree == TreeType.Visual && RelativeSource.AncestorType == null) { throw new InvalidOperationException("AncestorType must be set for RelativeSourceMode.FindAncestor when searching the visual tree."); } observer = CreateFindAncestorObserver( (target as IStyledElement) ?? (anchor as IStyledElement), RelativeSource, node); } else { throw new NotSupportedException(); } var fallback = FallbackValue; // If we're binding to DataContext and our fallback is UnsetValue then override // the fallback value to null, as broken bindings to DataContext must reset the // DataContext in order to not propagate incorrect DataContexts to child controls. // See Avalonia.Markup.UnitTests.Data.DataContext_Binding_Should_Produce_Correct_Results. if (targetProperty == StyledElement.DataContextProperty && fallback == AvaloniaProperty.UnsetValue) { fallback = null; } var converter = Converter; var targetType = targetProperty?.PropertyType ?? typeof(object); // We only respect `StringFormat` if the type of the property we're assigning to will // accept a string. Note that this is slightly different to WPF in that WPF only applies // `StringFormat` for target type `string` (not `object`). if (!string.IsNullOrWhiteSpace(StringFormat) && (targetType == typeof(string) || targetType == typeof(object))) { converter = new StringFormatValueConverter(StringFormat, converter); } var subject = new BindingExpression( observer, targetType, fallback, converter ?? DefaultValueConverter.Instance, ConverterParameter, Priority); return(new InstancedBinding(subject, Mode, Priority)); }
public void ConditionalExpressionActivateAndInactivate() { var a = InitializeComplexTypeInstance(); var result = string.Empty; var count = 0; ExpressionObserver.Observes( () => a.BoolProp ? a.NestedProp.StringProp : a.StringProp, (value, exception) => { Assert.Null(exception); result = value; count++; }); var ifFalseTestCases = new[] { "11", "22", "33" }; var ifTrueTestCases = new[] { "1", "2", "3", "4" }; var ifTrueNestedPropTestCases = new[] { new ComplexType { StringProp = "111" }, new ComplexType { StringProp = "222" }, new ComplexType { StringProp = "333" }, new ComplexType { StringProp = "444" }, new ComplexType { StringProp = "555" }, }; // Initial Test = false for (int i = 0; i < 5; i++) { count = 0; foreach (string testCase in ifFalseTestCases) { a.StringProp = testCase; Assert.Equal(a.BoolProp ? ifTrueNestedPropTestCases.Last().StringProp : testCase, result); } Assert.Equal(a.BoolProp ? 0 : ifFalseTestCases.Length, count); // ------------------------------------------------------- count = 0; foreach (string testCase in ifTrueTestCases) { a.NestedProp.StringProp = testCase; Assert.Equal(a.BoolProp ? testCase : ifFalseTestCases.Last(), result); } Assert.Equal(a.BoolProp ? ifTrueTestCases.Length : 0, count); // ------------------------------------------------------- count = 0; foreach (ComplexType testCase in ifTrueNestedPropTestCases) { a.NestedProp = testCase; Assert.Equal(a.BoolProp ? testCase.StringProp : ifFalseTestCases.Last(), result); } Assert.Equal(a.BoolProp ? ifTrueNestedPropTestCases.Length : 0, count); // ------------------------------------------------------- a.BoolProp = !a.BoolProp; Assert.Equal(a.BoolProp ? ifTrueNestedPropTestCases.Last().StringProp : ifFalseTestCases.Last(), result); } }
public InstancedBinding ItemsSelector(object item) { var obs = ExpressionObserver.Create(item, o => (o as Node).Children); return(InstancedBinding.OneWay(obs)); }
public InstancedBinding ItemsSelector(object item) { var obs = new ExpressionObserver(item, nameof(Node.Children)); return(InstancedBinding.OneWay(obs)); }
public void Convert_Casts_Should_Error() { var test = 1; Assert.Throws <ExpressionParseException>(() => ExpressionObserver.Create(test, o => (double)o)); }
public void ThreeLevelNestingConditionalExpressionInactivate() { var a = InitializeComplexTypeInstance(); var b = InitializeComplexTypeInstance(); var c = InitializeComplexTypeInstance(); var d = InitializeComplexTypeInstance(); var result = int.MinValue; var count = 0; ExpressionObserver.Observes(() => a.BoolProp ? a.IntProp : b.BoolProp ? b.IntProp : c.BoolProp ? c.IntProp : d.IntProp, (value, exception) => { Assert.Null(exception); result = value; count++; }); // 1. False-False-False -> d.IntProp Check(d, i => { a.IntProp = b.IntProp = c.IntProp = i + 10086; }); // 2. False-True-False -> b.IntProp b.BoolProp = true; Check(b, i => { a.IntProp = c.IntProp = d.IntProp = i + 10086; c.BoolProp = !c.BoolProp; }); // 3. True-False-False -> a.IntProp b.BoolProp = false; a.BoolProp = true; Check(a, i => { b.IntProp = c.IntProp = d.IntProp = i + 10086; b.BoolProp = !b.BoolProp; c.BoolProp = !c.BoolProp; }); void Check(ComplexType testObject, Action <int> uselessChange) { result = int.MinValue; count = 0; testObject.IntProp = 666; Assert.Equal(testObject.IntProp, result); Assert.Equal(1, count); for (int i = 0; i < 5; i++) { uselessChange(i); } Assert.Equal(testObject.IntProp, result); Assert.Equal(1, count); } }
public void TwoLevelNestingConditionalExpressionActivateAndInactivate() { var a = InitializeComplexTypeInstance(); var complexTypeTestCases = new[] { new ComplexType { IntProp = 111 }, new ComplexType { IntProp = 222 }, new ComplexType { IntProp = 333 }, new ComplexType { IntProp = 444 }, new ComplexType { IntProp = 555 }, }; foreach (var testCase in complexTypeTestCases) { a.ComplexList.Add(testCase); } var result = int.MinValue; var count = 0; ExpressionObserver.Observes( () => a.NestedProp.BoolProp ? a.NestedProp.IntProp : a.BoolProp ? a.IntProp : a.ComplexList[a.IntProp].IntProp, (value, exception) => { Assert.Null(exception); result = value; count++; }); // 1. False False: a.ComplexList[a.IntProp].IntProp for (int i = 1; i < a.ComplexList.Count; i++) { a.IntProp = i; Assert.Equal(a.ComplexList[i].IntProp, result); for (int j = 0; j < 5; j++) { var expected = a.ComplexList[i].IntProp = j + 10086; Assert.Equal(expected, result); } Assert.Equal(i * 6, count); } // 2. False True: a.IntProp result = int.MinValue; count = 0; a.BoolProp = true; Assert.Equal(a.IntProp, result); Assert.Equal(1, count); for (int i = 0; i < 5; i++) { a.ComplexList.Last().IntProp = i + 10086; Assert.Equal(a.IntProp, result); } Assert.Equal(1, count); // 3. True True: a.NestedProp.IntProp result = int.MinValue; count = 0; a.NestedProp.BoolProp = true; Assert.Equal(a.NestedProp.IntProp, result); Assert.Equal(1, count); for (int i = 0; i < 5; i++) { a.NestedProp.IntProp = i + 10086; Assert.Equal(a.NestedProp.IntProp, result); } Assert.Equal(6, count); // 4. True True/False: a.BoolProp ? a.IntProp : a.ComplexList[a.IntProp].IntProp result = int.MinValue; count = 0; for (int i = 0; i < 5; i++) { a.BoolProp = !a.BoolProp; a.IntProp = i + 10086; a.ComplexList.Last().IntProp = i + 10086; Assert.Equal(int.MinValue, result); } Assert.Equal(0, count); }