示例#1
0
        public virtual async Task <long> GetCurrentPing(string ipOrUrl = "8.8.8.8", int timeoutInMs = 500)
        {
            PingReply pingReply = await new Ping().SendPingAsync(ipOrUrl, timeoutInMs);

            AssertV2.IsNotNull(pingReply, "result");
            return(pingReply.RoundtripTime); // return ping in MS
        }
示例#2
0
        public void DateTime_MoreTests()
        {
            AssertV2.ThrowExeptionIfAssertionFails(false, () => {
                var dateTime1 = DateTimeParser.NewDateTimeFromUnixTimestamp(1547535889);
                var dateTime2 = DateTimeParser.NewDateTimeFromUnixTimestamp(1547535889000);
                Assert.Equal(dateTime1, dateTime2);
                var dateTime3 = DateTimeParser.NewDateTimeFromUnixTimestamp(1547535889, autoCorrectIfPassedInSeconds: false);
                Assert.NotEqual(dateTime1, dateTime3);
            });
            AssertV2.ThrowExeptionIfAssertionFails(false, () => {
                var dateTime1 = DateTimeParser.NewDateTimeFromUnixTimestamp(-2);
                var dateTime2 = DateTimeParser.NewDateTimeFromUnixTimestamp(2);
                Assert.True(dateTime1.IsBefore(dateTime2));
                Assert.False(dateTime2.IsBefore(dateTime1));
                Assert.True(dateTime2.IsAfter(dateTime1));
                Assert.False(dateTime1.IsAfter(dateTime2));
                Assert.True(DateTimeParser.NewDateTimeFromUnixTimestamp(0).IsBetween(dateTime1, dateTime2));
                Assert.False(DateTimeParser.NewDateTimeFromUnixTimestamp(0).IsBetween(dateTime2, dateTime1));
                Assert.False(DateTimeParser.NewDateTimeFromUnixTimestamp(3).IsBetween(dateTime1, dateTime2));
            });

            // Make sure the assertions in DateTimeParser.NewDateTimeFromUnixTimestamp work correctly and detect abnormal behavior:
            Assert.Throws <Exception>(() => {
                AssertV2.ThrowExeptionIfAssertionFails(() => {
                    DateTimeParser.NewDateTimeFromUnixTimestamp(-1);
                });
            });
        }
        private static bool IsDefaultValue <T>(T storeValue, T defaultValue)
        {
            var res = Equals(storeValue, defaultValue);

            AssertV2.IsTrue(res == JsonWriter.HasEqualJson(storeValue, defaultValue), $"Equals says {res} but EqualJson says {!res}!");
            return(res);
        }
示例#4
0
        public void ExampleUsage1()
        {
            MyClass1 original = new MyClass1()
            {
                name = "1", child = new MyClass1()
                {
                    name = "2"
                }
            };

            MyClass1 copy = original.DeepCopyViaJson();

            Assert.Null(MergeJson.GetDiff(original, copy)); // No diff between original and copy
            AssertV2.AreEqualJson(original, copy);          // WIll use MergeJson.GetDiff internally
            Assert.Equal(original.child.name, copy.child.name);
            // Modify the copy, changing the copy will not change the original:
            copy.child.name = "Some new name..";
            // Check that the change was only done in the copy and not the original:
            Assert.NotEqual(original.child.name, copy.child.name);
            Assert.NotNull(MergeJson.GetDiff(original, copy));

            // Objects that impl. IClonable can also ShallowCopy (will call .Clone internally):
            MyClass1 shallowCopy = original.ShallowCopyViaClone();

            Assert.NotSame(original, shallowCopy);
            Assert.Same(original.child, shallowCopy.child);
        }
示例#5
0
 private static JToken CreateJValueParentsIfNeeded(this FieldView self, JToken currentLevel)
 {
     if (self.IsInChildObject())   // Navigate down to the correct child JObject
     {
         string[] parents = self.fullPath.Split(".");
         for (int i = 0; i < parents.Length - 1; i++)
         {
             string fieldName = parents.ElementAt(i);
             var    child     = GetChildJToken(currentLevel, fieldName);
             if (child == null)
             {
                 if (int.TryParse(parents.ElementAt(i + 1), out int _))
                 {
                     currentLevel[fieldName] = new JArray();
                 }
                 else
                 {
                     currentLevel[fieldName] = new JObject();
                 }
             }
             currentLevel = child;
             AssertV2.IsNotNull(currentLevel, $"rootModel (p='{fieldName}', child={child}");
         }
     }
     return(currentLevel);
 }
示例#6
0
        public override IEnumerator RunTest()
        {
            // Show some empty view as a background for the toasts:
            ViewStackHelper.MainViewStack().ShowView(someUiScreenPrefabName);

            Toast.Show("Some toast 1", "Lorem ipsum 1");
            yield return(new WaitForSeconds(1));

            Toast.Show("Some toast 2");

            // In between show another screen on the main view stack, to ensure it does not interrupt showing the toasts:
            ViewStackHelper.MainViewStack().SwitchToView(someUiScreenPrefabName);

            yield return(new WaitForSeconds(1));

            var toast3 = Toast.Show("Some toast 3", "Lorem ipsum 3", 2500);

            AssertV2.IsFalse(toast3.IsDestroyed(), "Toast was already destroyed");
            yield return(new WaitForSeconds(3));

            AssertV2.IsTrue(toast3.IsDestroyed(), "Toast could not be destroyed");

            RootCanvas.GetAllRootCanvases().Single().gameObject.Destroy();
            Toast.Show("Some toast 4");
            yield return(new WaitForSeconds(3));
        }
示例#7
0
 public void TestUsingAssertV2ForPrintDebugging()
 {
     AssertV2.SetupPrintDebuggingSuccessfulAssertions(); // Turn on print debugging
     // Then call AssertV2 methods that normally do not produce any log output (because they dont fail):
     TestAssertV2Methods();
     AssertV2.onAssertSuccess = null; // Turn off print debugging again
 }
示例#8
0
        public async Task ExampleUsage1()
        {
            // First the test produces a state myState1:
            MyClass1 myState1 = new MyClass1()
            {
                myName     = "abc",
                myChildren = new MyClass1[] {
                    new MyClass1()
                    {
                        myName = "def"
                    }
                }
            };

            // The regression test wants to ensure that this state does never change
            // Assertions ensure the correctness of the tested component
            Assert.NotNull(myState1.myName);

            // In addition the state can be persisted to detect any changes caused e.g. by future refactorings
            // To create such a persisted snapshot the PersistedRegression class can be used as follows:

            // The passed myState will be compared to the persisted regression entry stored on disk:
            await new PersistedRegression().AssertEqualToPersisted("PersistedRegressionTests_ExampleUsage1_1", myState1);
            // If the myState1 ever differs from how it was the first time the test was executed this will fail
            // This way changes have to be manually approved by the developer

            // The same regression test can also be triggered through the AssertV2 helper:
            AssertV2.IsEqualToPersisted("PersistedRegressionTests_ExampleUsage1_1", myState1);
        }
示例#9
0
        public async Task <GameObject> NewViewFromSchema(JsonSchema schema, JsonSchemaToView generator)
        {
            AssertV2.IsNotNull(schema, "schema");
            AssertV2.IsNotNull(generator, "generator");
            if (schema.properties == null)
            {
                AssertV2.IsFalse(generator.schemaGenerator.schemas.IsNullOrEmpty(), "generator.schema dict is emtpy!");
                if (generator.schemaGenerator.schemas.TryGetValue(schema.modelType, out JsonSchema vm))
                {
                    schema = vm;
                }
                else
                {
                    Log.e($"No Schema found for schema.modelType={schema.modelType}");
                }
            }
            AssertV2.IsNotNull(schema.properties, "schema.properties");
            GameObject rootContainerView = await generator.NewRootContainerView(rootPrefabName);

            rootContainerView.GetComponentInChildren <FieldView>().field = schema;
            var innerContainer = await generator.SelectInnerViewContainerFromObjectFieldView(rootContainerView);

            await generator.ObjectJsonSchemaToView(schema, innerContainer);

            return(rootContainerView);
        }
示例#10
0
 public void TestReadableAssertAreEqualErrorOutputs()
 {
     AssertV2.AreEqual("abcd", "abce");
     AssertV2.AreEqual(new int[4] {
         1, 2, 2, 4
     }, new int[4] {
         1, 2, 3, 4
     });
     AssertV2.AreEqual(new int[2] {
         1, 2
     }, new int[2] {
         1, 3
     });
     AssertV2.AreEqual(new int[6] {
         1, 2, 3, 4, 5, 6
     }, new int[6] {
         1, 2, 3, 4, 5, 7
     });
     AssertV2.AreEqual(new int[2] {
         1, 2
     }, new int[1] {
         1
     });
     AssertV2.AreEqual(new int[1] {
         1
     }, new int[2] {
         1, 2
     });
 }
示例#11
0
        public NewsManager newsManager; // protected because its accessed by the list entries

        public async Task LoadNews()
        {
            AssertV2.NotNull(newsManager, "newsManager");
            var allNews = showOnlyUnread ? await newsManager.GetAllUnreadNews() : await newsManager.GetAllNews();

            this.CellData = allNews.ToList(); // This will trigger showing the list entries
        }
示例#12
0
        public void TestPerformance1()
        {
            // The EventBus can be accessed via EventBus.instance
            EventBus eventBus  = GetEventBusForTesting();
            string   eventName = "TestEvent1 - TestPerformance1";

            var receivedEventsCounter = 0;

            //Register a subscriber for the eventName that gets notified when ever an event is send:
            object subscriber1 = new object(); // can be of any type

            eventBus.Subscribe(subscriber1, eventName, () => {
                receivedEventsCounter++;
            });

            var timing            = Log.MethodEntered();
            var nrOfEventsSendOut = 1000000;

            for (int i = 0; i < nrOfEventsSendOut; i++)
            {
                eventBus.Publish(eventName);
            }
            AssertV2.ThrowExeptionIfAssertionFails(() => {
                timing.AssertUnderXms(5000);
            });
            Assert.Equal(nrOfEventsSendOut, receivedEventsCounter);
        }
示例#13
0
        private static string GetKeyFromBsonDoc(BsonDocument x)
        {
            var key = x.Keys.First();

            AssertV2.AreEqual("_id", key);
            return(x[key].AsString);
        }
示例#14
0
        public async Task OnHasInternet(bool hasInet)
        {
            if (oldHasInet != hasInet)
            {
                if (oldHasInet != null)
                {
                    EventBus.instance.Publish(EventConsts.catSystem + EventConsts.INET_CHANGED, oldHasInet, hasInet);
                }
                oldHasInet = hasInet;
            }
            if (hasInet)
            {
                foreach (var key in (await store.GetAllKeys()).ToList())
                {
                    try {
                        if (await SendEventToExternalSystem(await store.Get(key, null)))
                        {
                            var wasRemoved = await store.Remove(key);

                            AssertV2.IsTrue(wasRemoved, "Could not remove key " + key);
                        }
                    }
                    catch (Exception e) { Log.e(e); }
                }
            }
        }
示例#15
0
        private void CalcAnchors()
        {
            try {
                RectTransform rt         = gameObject.GetOrAddComponent <RectTransform>();
                var           canvasRect = rt.GetRootCanvas().pixelRect;
                var           safeArea   = Screen.safeArea;
                Vector2       anchorMin  = safeArea.position;
                anchorMin.x /= canvasRect.width;
                anchorMin.y /= canvasRect.height;

                Vector2 anchorMax = safeArea.position + safeArea.size;
                anchorMax.x /= canvasRect.width;
                anchorMax.y /= canvasRect.height;

                //AssertV2.IsTrue(anchorMin.y <= ONE, "anchorMin.y=" + anchorMin.y);
                //AssertV2.IsTrue(anchorMax.y <= ONE, "anchorMax.y=" + anchorMax.y);
                AssertV2.IsTrue(rt.localScale.magnitude > 0, "rt.localScale=" + rt.localScale);
                if (anchorMax.x > ONE || anchorMax.y > ONE)
                {
                    return;
                }
                if (anchorMin.x == 0 && anchorMin.y == 0 && (anchorMax.x < MIN || anchorMax.y < MIN))
                {
                    return;
                }

                rt.anchorMin = anchorMin;
                rt.anchorMax = anchorMax;
                rt.SetPadding(0);
            }
            catch (System.Exception) { }
        }
示例#16
0
 public ProgressionSystem(LocalAnalytics analytics, FeatureFlagManager <T> featureFlagManager)
 {
     // Make sure the FeatureFlag system was set up too:
     AssertV2.IsNotNull(FeatureFlagManager <T> .instance, "FeatureFlagManager.instance");
     this.analytics          = analytics;
     this.featureFlagManager = featureFlagManager;
 }
示例#17
0
 public void DateTime_MoreTests()
 {
     AssertV2.ThrowExeptionIfAssertionFails(false, () => {
         var dateTime1 = DateTimeV2.NewDateTimeFromUnixTimestamp(1547535889);
         var dateTime2 = DateTimeV2.NewDateTimeFromUnixTimestamp(1547535889000);
         Assert.Equal(dateTime1, dateTime2);
         var dateTime3 = DateTimeV2.NewDateTimeFromUnixTimestamp(1547535889, autoCorrectIfPassedInSeconds: false);
         Assert.NotEqual(dateTime1, dateTime3);
     });
     AssertV2.ThrowExeptionIfAssertionFails(false, () => {
         if (AssertV2.throwExeptionIfAssertionFails)
         {
             return;
         }                                                       // Abort test if the flag is not correct
         var dateTime1 = DateTimeV2.NewDateTimeFromUnixTimestamp(-2);
         var dateTime2 = DateTimeV2.NewDateTimeFromUnixTimestamp(2);
         Assert.True(dateTime1.IsBefore(dateTime2));
         Assert.False(dateTime2.IsBefore(dateTime1));
         Assert.True(dateTime2.IsAfter(dateTime1));
         Assert.False(dateTime1.IsAfter(dateTime2));
         Assert.True(DateTimeV2.NewDateTimeFromUnixTimestamp(0).IsBetween(dateTime1, dateTime2));
         Assert.False(DateTimeV2.NewDateTimeFromUnixTimestamp(0).IsBetween(dateTime2, dateTime1));
         Assert.False(DateTimeV2.NewDateTimeFromUnixTimestamp(3).IsBetween(dateTime1, dateTime2));
     });
 }
示例#18
0
        public override IEnumerator RunTest()
        {
            MyUserUi userUiPresenter = new MyUserUi();

            userUiPresenter.targetView = gameObject.GetViewStack().GetLatestView();

            { // Load a first user into the UI by passing it through the presenter:
                var user1 = new MyUserModel()
                {
                    userName = "******", userAge = 4
                };
                yield return(userUiPresenter.LoadModelIntoView(user1).AsCoroutine());

                AssertV2.AreEqual("Carl", userUiPresenter.NameInputField().text);
                AssertV2.AreEqual("4", userUiPresenter.AgeInputField().text);
            }

            yield return(new WaitForSeconds(1f)); // Load another user into the UI:

            {                                     // Example of loading a second user in a separate asyn method "LoadUser2":
                yield return(LoadUser2(userUiPresenter).AsCoroutine());

                AssertV2.AreEqual("55", userUiPresenter.AgeInputField().text); // The age of user 2
            }
        }
示例#19
0
        public void TestFromJsonForReadonlyFields()
        {
            MyClass1 x = new MyClass1(12, ImmutableList.Create(new string[] { "a", "b", "c" }));

            {
                var xAsJson = JsonWriter.GetWriter().Write(x);
                Assert.NotEmpty(xAsJson);

                // The fields are immutable so the json logic has to use the constructor to init them from the json:
                var y = JsonReader.GetReader().Read <MyClass1>(xAsJson);
                Assert.Equal(x.myNumber, y.myNumber);
                AssertV2.AreEqualJson(x, y);
            }

            // The constructor json logic can also be mixed with normal field json logic:
            x.myMutableList = new List <string>()
            {
                "d", "e"
            };
            {
                var xAsJson = JsonWriter.GetWriter().Write(x);
                Assert.NotEmpty(xAsJson);
                var y = JsonReader.GetReader().Read <MyClass1>(xAsJson);

                // myMutableList is not required in the constructor but still correctly set by the json logic:
                Assert.Equal(x.myMutableList, y.myMutableList);
                AssertV2.AreEqualJson(x, y);
            }
        }
示例#20
0
        /// <summary> Connects a model with a view </summary>
        /// <returns> A task that can be awaited on, that returns the fully setup presenter </returns>
        public static async Task <Presenter <T> > LoadModelIntoView <T>(this Presenter <T> self, T model)
        {
            AssertV2.IsNotNull(self.targetView, "presenter.targetView");
            await self.OnLoad(model);

            return(self);
        }
示例#21
0
        private async Task RunWaitForNoVisualChangeInSceneTest()
        {
            AssertVisually assertVisually = NewAssertVisuallyInstance("Ui19_RunVisualRegression_ExampleUsage3");

            Task visualChangeMonitorTask = assertVisually.WaitForNoVisualChangeInScene();

            AssertV2.IsFalse(visualChangeMonitorTask.IsCompleted, "visualChangeMonitorTask.IsCompleted");

            gameObject.AddChild(await NewUiFor <MyUserModelv1>()); // Change the UI
            await TaskV2.Delay(200);                               // After 200 ms the monitorTask should still be checking:

            AssertV2.IsFalse(visualChangeMonitorTask.IsCompleted, "visualChangeMonitorTask.IsCompleted");

            gameObject.AddChild(await NewUiFor <MyUserModelv2>()); // Change the UI again
            await TaskV2.Delay(200);                               // After 200 ms the monitorTask should still be checking:

            AssertV2.IsFalse(visualChangeMonitorTask.IsCompleted, "visualChangeMonitorTask.IsCompleted");

            gameObject.AddChild(await NewUiFor <MyUserModelv1>()); // Change the UI again
            await TaskV2.Delay(200);                               // After 200 ms the monitorTask should still be checking:

            AssertV2.IsFalse(visualChangeMonitorTask.IsCompleted, "visualChangeMonitorTask.IsCompleted");

            await TaskV2.Delay(2000); // Dont change the UI for 2 sec

            // Now the change monitor task should have completed since the sceen did not change for 2 sec:
            AssertV2.IsTrue(visualChangeMonitorTask.IsCompleted, "visualChangeMonitorTask.IsCompleted");

            await visualChangeMonitorTask; // await the task in case there was an exception
        }
示例#22
0
        private void OnProgressUpdate(object sender, IProgress _)
        {
            AssertV2.IsTrue(sender == progressManager, "sender != pm (ProgressManager field)");
            var percent = Math.Round(progressManager.combinedAvgPercent, 3);

            SetPercentInUi(percent);
            if (progressText != null)
            {
                progressText.text = $"{percent}% ({progressManager.combinedCount}/{progressManager.combinedTotalCount})";
            }

            // Handle progress UI fading:
            if (enableProgressUiFading)
            {
                if (canvasGroupFader == null)
                {
                    canvasGroupFader = GetProgressUiGo().GetComponentInParents <CanvasGroupFader>();
                }
                if (percent == 0 || percent >= 100)
                {
                    canvasGroupFader.targetAlpha = 0;
                }
                else
                {
                    canvasGroupFader.targetAlpha = canvasGroupFader.initialAlpha;
                }
            }

            if (percent >= 100 && delayInMsBeforeProgressCleanup >= 0)
            {
                this.ExecuteDelayed(ResetProgressManagerIfAllFinished, delayInMsBeforeProgressCleanup);
                onProgressUiComplete?.Invoke();
            }
        }
示例#23
0
        public void TestFilePathesInJson()
        {
            var root      = EnvironmentV2.instance.GetOrAddTempFolder("TestFilePathesInJson");
            var file1     = root.GetChildDir("SubDir1").GetChildDir("SubSubDir1").GetChild("child1.txt");
            var savedText = "Test 123";

            file1.SaveAsText(savedText);
            IFileRef x1 = new FileRef();

            x1.SetPath(file1);

            var x2 = x1.DeepCopyViaJson();

            AssertV2.AreEqualJson(x1, x2);
            Assert.NotEmpty(x1.fileName);
            Assert.NotEmpty(x2.fileName);

            // GetChild ensures that no special characters like / are in the file name:
            var fullPathViaGetChild = root.GetChild("" + x2.GetPath());

            Assert.False(fullPathViaGetChild.Exists);

            // ResolveFilePath can be used to resolve full pathes including / characters:
            var file2 = root.ResolveFilePath("" + x2.GetPath());

            Assert.True(file2.Exists);
            Assert.Equal(savedText, file2.LoadAs <string>());
        }
示例#24
0
        public override DirectoryInfo GetTempFolder()
        {
            var d = new DirectoryInfo(Application.temporaryCachePath);

            AssertV2.AreEqual(base.GetTempFolder().FullPath(), d.FullPath()); // TODO test this
            return(d);
        }
示例#25
0
        public void TestLinkMaps()
        {
            bool prefabLoadedEventReceived = false;

            EventBus.instance.Subscribe(new object(), IoEvents.PREFAB_LOADED, () => { prefabLoadedEventReceived = true; });
            GameObject prefab = ResourcesV2.LoadPrefab("ExamplePrefab1.prefab");

            Assert.IsTrue(prefabLoadedEventReceived);

            bool linkMapCreationEventReceived = false;

            EventBus.instance.Subscribe(new object(), LinkingEvents.LINK_MAP_CREATED, () => { linkMapCreationEventReceived = true; });
            var links = prefab.GetLinkMap();

            Assert.IsTrue(linkMapCreationEventReceived);

            Assert.IsNotNull(links.Get <Button>("Button 1"));
            Assert.IsNotNull(links.Get <GameObject>("Button 1"));
            AssertV2.Throws <Exception>(() => { links.Get <Button>("Button 2"); });

            links.Get <Text>("Text 1").text = "Some text";
            Assert.AreEqual("Some text", links.Get <Text>("Text 1").text);
            links.Get <Button>("Button 1").SetOnClickAction(delegate {
                Log.d("Button 1 clicked");
            });
            links.Get <Toggle>("Toggle 1").SetOnValueChangedAction((isNowChecked) => {
                Log.d("Toggle 1 is now " + (isNowChecked ? "checked" : "unchecked"));
                return(true);
            });
        }
示例#26
0
 public void TestLoadingPrefabs()
 {
     // Load the ExamplePrefab1.prefab located in Assets\Tests\TestLinking\Resources :
     Assert.IsNotNull(ResourcesV2.LoadPrefab("ExamplePrefab1"));
     // Loading a prefab that does not exist results in an error:
     AssertV2.Throws <Exception>(() => { ResourcesV2.LoadPrefab("ExamplePrefab2"); });
 }
示例#27
0
        public static Canvas GetOrAddRootCanvas()
        {
            var roots = GetAllRootCanvases();

            if (roots.IsNullOrEmpty())
            {
                return(CreateNewRootCanvas());
            }
            // Check if there is a root canvas that has a ViewStack attached:
            var rootCanvasesWithViewStack = roots.Filter(x => x.GetComponent <ViewStack>() != null);

            if (!rootCanvasesWithViewStack.IsNullOrEmpty())
            {
                AssertV2.AreEqual(1, rootCanvasesWithViewStack.Count(), "rootCanvasesWithViewStack");
                return(rootCanvasesWithViewStack.First());
            }
            // Prefer canvas objects that are on the root level of the open scene:
            var canvasesOnRootOfScene = roots.Filter(x => x.gameObject.GetParent() == null);

            if (canvasesOnRootOfScene.IsNullOrEmpty())
            {
                AssertV2.AreEqual(1, canvasesOnRootOfScene.Count(), "canvasesOnRootOfScene");
                return(canvasesOnRootOfScene.First());
            }
            // As a fallback return the first root canvas:
            return(roots.First());
        }
示例#28
0
 private void AssertChildrenHaveCorrectMonosAttached()
 {
     foreach (var t in GetComponent <ToggleGroup>().ActiveToggles())
     {
         AssertV2.IsTrue(t.GetComponentV2 <ToggleListener>() != null, "Missing ToggleListener MonoBehaviour for child of ToggleGroup", t.gameObject);
         AssertV2.IsTrue(t.GetComponentV2 <RadioButton>() != null, "Missing RadioButton MonoBehaviour for child of ToggleGroup", t.gameObject);
     }
 }
示例#29
0
        private static Task StartCoroutineAsTask(IEnumerator iEnum)
        {
            AssertV2.IsTrue(ApplicationV2.isPlaying, "In EDIT mode!");
            var tcs = new TaskCompletionSource <bool>();

            MainThread.Invoke(() => { MainThread.instance.StartCoroutineAsTask(tcs, iEnum, () => true); });
            return(tcs.Task);
        }
示例#30
0
 private static Transform GetNextChild(Transform parent, int currentIndex, bool loopChildren)
 {
     AssertV2.AreNotEqual(0, parent.childCount);
     if (currentIndex + 1 >= parent.childCount)
     {
         return(loopChildren ? parent.GetChild(0) : null);
     }
     return(parent.GetChild(currentIndex + 1));
 }