private void AssertUpdateMeasureCalls(MeasureArrangeCallChecker element, bool shouldBeCalled)
 {
     Assert.AreEqual(shouldBeCalled, element.MeasureHasBeenCalled);
     Assert.AreEqual(false, element.ArrangeHasBeenCalled);
 }
        public void TestInvalidationPropagation()
        {
            // construct a simple hierarchy:
            // (legend: f need forced updates, i are invalidated, u should be updated, o are OK)
            //        o     root
            //        |
            //        o     elt1
            //       / \
            //      o   o   elt2 / elt3
            //         / \
            //        o   o elt4 / elt5
            //            |
            //            o elt6

            var elt6 = new MeasureArrangeCallChecker { Name = "elt6" };
            var elt5 = new MeasureArrangeCallChecker { Name = "elt5" }; elt5.Children.Add(elt6);
            var elt4 = new MeasureArrangeCallChecker { Name = "elt4" };
            var elt3 = new MeasureArrangeCallChecker { Name = "elt3" }; elt3.Children.Add(elt4); elt3.Children.Add(elt5);
            var elt2 = new MeasureArrangeCallChecker { Name = "elt2" };
            var elt1 = new MeasureArrangeCallChecker { Name = "elt1" }; elt1.Children.Add(elt2); elt1.Children.Add(elt3);
            var root = new MeasureArrangeCallChecker { Name = "root" }; root.Children.Add(elt1);
            var elements = new List<MeasureArrangeCallChecker> { root, elt1, elt2, elt3, elt4, elt5, elt6 };
            
            root.Measure(Vector3.Zero);
            root.Arrange(Vector3.Zero, false);
            foreach (var element in elements)
                element.Reset();

            // invalidate el3 measure and check that the tree is correctly updated 
            //        fiu     root
            //        |
            //        fiu     elt1
            //       / \
            //      o   fiu   elt2 / elt3 
            //         / \
            //        i   i elt4 / elt5
            //            |
            //            i elt6
            elt3.DefaultDepth = 333;
            AssertMeasureState(root, false, false);
            AssertMeasureState(elt1, false, false);
            AssertMeasureState(elt2, true, true);
            AssertMeasureState(elt3, false, false);
            AssertMeasureState(elt4, true, false);
            AssertMeasureState(elt5, true, false);
            AssertMeasureState(elt6, true, false);

            root.Measure(Vector3.Zero);
            root.Arrange(Vector3.Zero, false);

            AssetMeasureArrangeStateValid(elements);
            AssertMeasureCalls(root, true);
            AssertMeasureCalls(elt1, true);
            AssertMeasureCalls(elt2, false);
            AssertMeasureCalls(elt3, true);
            AssertMeasureCalls(elt4, false);
            AssertMeasureCalls(elt5, false);
            AssertMeasureCalls(elt6, false);

            foreach (var element in elements)
                element.Reset();

            // invalidate el3 arrange and check that the tree is correctly updated
            //        fiu     root
            //        |
            //        fiu     elt1
            //       / \
            //      o   fiu   elt2 / elt3 
            //         / \
            //        i   i elt4 / elt5
            //            |
            //            i elt6
            elt3.HorizontalAlignment = HorizontalAlignment.Right;
            AssertArrangeState(root, false, false);
            AssertArrangeState(elt1, false, false);
            AssertArrangeState(elt2, true, true);
            AssertArrangeState(elt3, false, false);
            AssertArrangeState(elt4, true, false);
            AssertArrangeState(elt5, true, false);
            AssertArrangeState(elt6, true, false);

            root.Measure(Vector3.Zero);
            root.Arrange(Vector3.Zero, false);

            AssetMeasureArrangeStateValid(elements);
            AssertArrangeCalls(root, true);
            AssertArrangeCalls(elt1, true);
            AssertArrangeCalls(elt2, false);
            AssertArrangeCalls(elt3, true);
            AssertArrangeCalls(elt4, false);
            AssertMeasureCalls(elt5, false);
            AssertMeasureCalls(elt6, false);
            
            elt3.OnMeasureOverride += margins => Vector3.Zero;
            elt3.OnArrangeOverride += margins => Vector3.Zero;

            root.Measure(Vector3.Zero);
            root.Arrange(Vector3.Zero, false);

            foreach (var element in elements)
                element.Reset();
            
            // change root measure provided size and check that the tree is correctly updated
            //        u     root
            //        |
            //        u     elt1
            //       / \
            //      u   u   elt2 / elt3 
            //         / \
            //        o   o elt4 / elt5
            //            |
            //            o elt6
            AssertMeasureState(root, true, true);
            AssertMeasureState(elt1, true, true);
            AssertMeasureState(elt2, true, true);
            AssertMeasureState(elt3, true, true);
            AssertMeasureState(elt4, true, true);
            AssertMeasureState(elt5, true, true);
            AssertMeasureState(elt6, true, true);

            root.Measure(Vector3.One);
            root.Arrange(Vector3.Zero, false);

            AssetMeasureArrangeStateValid(elements);
            AssertUpdateMeasureCalls(root, true);
            AssertUpdateMeasureCalls(elt1, true);
            AssertUpdateMeasureCalls(elt2, true);
            AssertUpdateMeasureCalls(elt3, true);
            AssertUpdateMeasureCalls(elt4, false);
            AssertUpdateMeasureCalls(elt5, false);
            AssertUpdateMeasureCalls(elt6, false);
            
            foreach (var element in elements)
                element.Reset();

            // change root measure provided size and check that the tree is correctly updated (x need measure update)
            //        x     root
            //        |
            //        x     elt1
            //       / \
            //      x   x   elt2 / elt3 
            //         / \
            //        o   o elt4 / elt5
            //            |
            //            o elt6
            AssertMeasureState(root, true, true);
            AssertMeasureState(elt1, true, true);
            AssertMeasureState(elt2, true, true);
            AssertMeasureState(elt3, true, true);
            AssertMeasureState(elt4, true, true);
            AssertMeasureState(elt5, true, true);
            AssertMeasureState(elt6, true, true);

            root.Measure(Vector3.One);
            root.Arrange(Vector3.One, false);

            AssetMeasureArrangeStateValid(elements);
            AssertArrangeCalls(root, true);
            AssertArrangeCalls(elt1, true);
            AssertArrangeCalls(elt2, true);
            AssertArrangeCalls(elt3, true);
            AssertArrangeCalls(elt4, false);
            AssertArrangeCalls(elt5, false);
            AssertArrangeCalls(elt6, false);


            // check that invalidation propagation works with visual parent too.
            var testVisualChildElement = new VisualChildTestClass();

            testVisualChildElement.Measure(Vector3.One);
            testVisualChildElement.Arrange(Vector3.One, false);
            
            AssertMeasureState(testVisualChildElement, true, true);
            testVisualChildElement.InvalidateVisualChildMeasure();
            AssertMeasureState(testVisualChildElement, false, false);
        }