public void GetDescendants_Many_ManyMatches_NestedChildrenAndAttributes()
        {
            var sut = RapidXamlElement.Build("Parent");

            sut.AddChildAttribute(
                "Attr1",
                RapidXamlElement.Build("AttrChild")
                .AddChildAttribute("InnerAttrChild", RapidXamlElement.Build("Label")));
            sut.AddChildAttribute(
                "Attr2",
                RapidXamlElement.Build("AttrChild")
                .AddChild(RapidXamlElement.Build("Label")));
            sut.AddChild(RapidXamlElement.Build("MyChild")
                         .AddChildAttribute(
                             "MyChildAttr",
                             RapidXamlElement.Build("MyChildInnerAttr")
                             .AddChildAttribute(
                                 "Nested",
                                 RapidXamlElement.Build("Label"))))
            .AddChild(
                RapidXamlElement.Build("GrandChild")
                .AddChild(
                    RapidXamlElement.Build("GreatGrandChild")
                    .AddChild("Label")));

            var actual = sut.GetDescendants("Label");

            Assert.AreEqual(4, actual.Count());
        }
        public void ContainsChild_One_WithoutXmlns_Found()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddChild("test:One");

            Assert.IsTrue(sut.ContainsChild("One"));
        }
        public void GetAttributes_Empty()
        {
            var sut = RapidXamlElement.Build("Grid");

            var actual = sut.GetAttributes("Height");

            Assert.AreEqual(0, actual.Count());
        }
        public void ContainsChild_One_NotFound()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddChild("One");

            Assert.IsFalse(sut.ContainsChild("Any"));
        }
        public void GetDescendants_None_NoMatches()
        {
            var sut = RapidXamlElement.Build("Parent");

            var actual = sut.GetDescendants("Label");

            Assert.AreEqual(0, actual.Count());
        }
        public void GetChildren_None_NoMatches()
        {
            var sut = RapidXamlElement.Build("Grid");

            var actual = sut.GetChildren("Label");

            Assert.AreEqual(0, actual.Count());
        }
        public void ContainsDescendant_OneChild_Xmlns_Match()
        {
            var sut = RapidXamlElement.Build("Parent");

            sut.AddChild("tst:Child");

            Assert.IsTrue(sut.ContainsDescendant("Child"));
        }
        public void ContainsAttribute_One_Found()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddInlineAttribute("One", "ABC");

            Assert.IsTrue(sut.ContainsAttribute("One"));
        }
        public void ContainsAttribute_One_Part2OfDotted_NotFound()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddInlineAttribute("Grid.Row", "1");

            Assert.IsFalse(sut.ContainsAttribute("Row"));
        }
        public void ContainsDescendant_OneChild_NotMatch()
        {
            var sut = RapidXamlElement.Build("Parent");

            sut.AddChild("Child");

            Assert.IsFalse(sut.ContainsDescendant("one"));
        }
        public void ContainsAttribute_One_Dotted_Found()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddInlineAttribute("Grid.Row", "1");

            Assert.IsTrue(sut.ContainsAttribute("Grid.Row"));
        }
        public void ContainsChild_Two_Found()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddChild("One");
            sut.AddChild("Two");

            Assert.IsTrue(sut.ContainsChild("One"));
        }
        public void ContainsAttribute_Two_NotFound()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddInlineAttribute("One", "ABC");
            sut.AddInlineAttribute("Two", "DEF");

            Assert.IsFalse(sut.ContainsAttribute("Any"));
        }
        public void ContainsAttribute_Two_Found_CaseInsensitive()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddInlineAttribute("One", "ABC");
            sut.AddInlineAttribute("Two", "DEF");

            Assert.IsTrue(sut.ContainsAttribute("one"));
        }
        public void ContainsChild_Two_WithXmlns_Found_CaseInsensitive()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddChild("test:One");
            sut.AddChild("test:Two");

            Assert.IsTrue(sut.ContainsChild("one"));
        }
        public void GetAttributes_One_Match()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddInlineAttribute("Width", "Auto");

            var actual = sut.GetAttributes("Width");

            Assert.AreEqual(1, actual.Count());
        }
        public void FooElement_WithXmlns()
        {
            var xaml = @"<demo:Foo />";

            var expected = RapidXamlElement.Build("demo:Foo");

            var actual = RapidXamlElementExtractor.GetElement(xaml);

            RapidXamlElementAssert.AreEqual(expected, actual);
        }
        public void ContainsDescendant_OneChild_OneGrandChild_NotMatch()
        {
            var sut   = RapidXamlElement.Build("Parent");
            var child = RapidXamlElement.Build("Child");

            child.AddChild("Grandchild");

            sut.AddChild(child);

            Assert.IsFalse(sut.ContainsDescendant("Uncle"));
        }
        public void ContainsDescendant_OneChild_OneGrandChild_Match_Xmlns_CaseInsensitive()
        {
            var sut   = RapidXamlElement.Build("Parent");
            var child = RapidXamlElement.Build("Child");

            child.AddChild("tst:Grandchild");

            sut.AddChild(child);

            Assert.IsTrue(sut.ContainsDescendant("grandchild"));
        }
        public void ContainsDescendant_InGrandChild_AsAttribute_Xmlns_CaseInsensitive_Match()
        {
            var sut        = RapidXamlElement.Build("ml:Parent");
            var child      = RapidXamlElement.Build("ml:Child");
            var grandChild = RapidXamlElement.Build("ml:Grandchild");

            grandChild.AddChildAttribute("Content", RapidXamlElement.Build("tst:Attached.Nested"));
            child.AddChild(grandChild);
            sut.AddChild(child);

            Assert.IsTrue(sut.ContainsDescendant("Attached.nested"));
        }
        public void GetAttributes_Many_NoMatch()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddInlineAttribute("Width", "Auto");
            sut.AddInlineAttribute("Direction", "LTR");
            sut.AddInlineAttribute("Color", "Red");

            var actual = sut.GetAttributes("Height");

            Assert.AreEqual(0, actual.Count());
        }
        public void ContainsDescendant_OneChild_OneGrandChild_OneGreatGrandChild_AllXmlns_Match()
        {
            var sut        = RapidXamlElement.Build("ml:Parent");
            var child      = RapidXamlElement.Build("ml:Child");
            var grandChild = RapidXamlElement.Build("ml:Grandchild");

            grandChild.AddChild("ml:Greatgrandchild");

            child.AddChild(grandChild);
            sut.AddChild(child);

            Assert.IsTrue(sut.ContainsDescendant("ml:Greatgrandchild"));
        }
        public void GetChildren_Many_OneMatch()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddChild(RapidXamlElement.Build("StackPanel"));
            sut.AddChild(RapidXamlElement.Build("StackPanel"));
            sut.AddChild(RapidXamlElement.Build("Label"));
            sut.AddChild(RapidXamlElement.Build("StackPanel"));

            var actual = sut.GetChildren("Label");

            Assert.AreEqual(1, actual.Count());
        }
        public void GetDescendants_Many_OneMatch_DirectAttribute()
        {
            var sut = RapidXamlElement.Build("Parent");

            sut.AddChildAttribute("Content1", RapidXamlElement.Build("UserControl"));
            sut.AddChildAttribute("Content2", RapidXamlElement.Build("ContentControl"));
            sut.AddChild("Huey");
            sut.AddChild("Dewey");
            sut.AddChild("Louie");

            var actual = sut.GetDescendants("UserControl");

            Assert.AreEqual(1, actual.Count());
        }
        public void GetAttributes_Many_ManyMatches()
        {
            var sut = RapidXamlElement.Build("Grid");

            sut.AddInlineAttribute("Width", "Auto");
            sut.AddInlineAttribute("Direction", "LTR");
            sut.AddInlineAttribute("Color", "Red");
            sut.AddInlineAttribute("Height", "Red");
            sut.AddChildAttribute("Content", RapidXamlElement.Build("Label").AddInlineAttribute("Text", "Hello"));
            sut.AddChildAttribute("Content", RapidXamlElement.Build("Label").SetContent("World!"));

            var actual = sut.GetAttributes("Content");

            Assert.AreEqual(2, actual.Count());
        }
        public void ContainsDescendant_DeepNesting_AsAttribute_Xmlns_CaseInsensitive_Match()
        {
            var sut        = RapidXamlElement.Build("ml:Parent");
            var child      = RapidXamlElement.Build("ml:Child");
            var grandChild = RapidXamlElement.Build("ml:Grandchild");

            grandChild.AddChildAttribute(
                "Content",
                RapidXamlElement.Build("Panel")
                .AddChildAttribute(
                    "Content",
                    RapidXamlElement.Build("StackPanel")
                    .AddChildAttribute(
                        "Content",
                        RapidXamlElement.Build("ListBox")
                        .AddChildAttribute(
                            "Content",
                            RapidXamlElement.Build("tst:DeepNested")))));
            child.AddChild(grandChild);
            sut.AddChild(child);

            Assert.IsTrue(sut.ContainsDescendant("deepnested"));
        }
        // This doesn't have the extra input checking that is in the caller in the TestHelper.
        // Extra checks excluded here as input is already known good based on original doc parsing.
        public static RapidXamlElement GetElement(string xamlElement, int offset = 0)
        {
            // Call this when may be adding multiple
            ////IEnumerable<RapidXamlElement> GetElementsInternal(string xaml, int startOffset)
            ////{

            ////}

            RapidXamlElement GetElementInternal(string xaml, int startOffset)
            {
                if (string.IsNullOrWhiteSpace(xaml))
                {
                    return(null);
                }

                var docSyntax = Parser.ParseText(xaml);

                var xdoc = docSyntax?.RootSyntax;

                if (xdoc == null)
                {
                    return(null);
                }

                var elementName = xdoc.Name;

                var result = RapidXamlElement.Build(
                    elementName,
                    startOffset + docSyntax.SpanStart,
                    docSyntax.Width,
                    xaml);

                var content = (docSyntax.Body as IXmlElement).Value;

                foreach (var attr in xdoc.Attributes)
                {
                    result.AddInlineAttribute(attr.Name, attr.Value, startOffset + attr.SpanStart, attr.Width);
                }

                foreach (var child in docSyntax.Body.ChildNodes)
                {
                    if (child == null | child is XmlElementStartTagSyntax | child is XmlElementEndTagSyntax)
                    {
                        continue;
                    }

                    if (child is XmlElementSyntax childElement)
                    {
                        if (childElement.Name.StartsWith($"{elementName}."))
                        {
                            var fullspan   = childElement.Content.FullSpan;
                            var attrString = xaml.Substring(fullspan.Start, fullspan.Length);

                            if (attrString.TrimStart().StartsWith("<"))
                            {
                                var startingWhiteSpaceLength = attrString.IndexOf("<");

                                foreach (var innerChild in childElement.ChildNodes)
                                {
                                    if (innerChild == null | innerChild is XmlElementStartTagSyntax | innerChild is XmlElementEndTagSyntax)
                                    {
                                        continue;
                                    }

                                    if (innerChild is SyntaxList childList)
                                    {
                                        var attributeChildren = new List <RapidXamlElement>();

                                        foreach (SyntaxNode listItem in childList.ChildNodes)
                                        {
                                            attributeChildren.Add(
                                                GetElementInternal(
                                                    xaml.Substring(listItem.SpanStart, listItem.Width),
                                                    startOffset + listItem.SpanStart));
                                        }

                                        result.AddChildrenAttribute(
                                            childElement.Name.Substring(elementName.Length + 1),
                                            attributeChildren,
                                            startOffset + childElement.SpanStart,
                                            childElement.Width);
                                    }
                                    else
                                    {
                                        var innerString = xaml.Substring(innerChild.SpanStart, innerChild.Width);

                                        result.AddChildAttribute(
                                            childElement.Name.Substring(elementName.Length + 1),
                                            GetElementInternal(innerString, startOffset + startingWhiteSpaceLength + innerChild.Start),
                                            startOffset + childElement.SpanStart,
                                            childElement.Width);
                                    }
                                }
                            }
                            else
                            {
                                result.AddChildAttribute(
                                    childElement.Name.Substring(elementName.Length + 1),
                                    attrString,
                                    startOffset + childElement.SpanStart,
                                    childElement.Width);
                            }

                            var childAsString = xaml.TrimStart().Substring(childElement.Start, childElement.Width);

                            if (content.TrimStart().StartsWith(childAsString.TrimStart()))
                            {
                                content = content.TrimStart().Substring(childAsString.Length).Trim();
                            }
                        }
                        else
                        {
                            result.AddChild(GetElementInternal(content, startOffset + child.Start));
                        }
                    }
                    else if (child is XmlEmptyElementSyntax selfClosingChild)
                    {
                        var toAdd =
                            RapidXamlElement.Build(
                                selfClosingChild.Name,
                                startOffset + child.SpanStart,
                                child.Width,
                                xaml.Substring(child.SpanStart, child.Width));

                        foreach (var attr in selfClosingChild.AttributesNode)
                        {
                            toAdd.AddInlineAttribute(attr.Name, attr.Value, startOffset + attr.SpanStart, attr.Width);
                        }

                        result.AddChild(toAdd);
                    }
                    else if (child is SyntaxNode node)
                    {
                        foreach (var nodeChild in node.ChildNodes)
                        {
                            if (nodeChild is XmlTextTokenSyntax)
                            {
                                continue;
                            }

                            if (nodeChild is XmlElementSyntax ncElement)
                            {
                                if (ncElement.Name.StartsWith($"{elementName}."))
                                {
                                    var attrString = xaml.Substring(ncElement.Content.Span.Start, ncElement.Content.Span.Length);

                                    if (attrString.StartsWith("<"))
                                    {
                                        foreach (var attrChild in ncElement.ChildNodes)
                                        {
                                            if (attrChild is XmlElementSyntax || attrChild is XmlEmptyElementSyntax)
                                            {
                                                result.AddChildAttribute(
                                                    ncElement.Name.Substring(elementName.Length + 1),
                                                    GetElementInternal(attrString, startOffset + ncElement.Content.Span.Start),
                                                    startOffset + ncElement.SpanStart,
                                                    ncElement.Width);
                                            }
                                            else if (attrChild is SyntaxList acList)
                                            {
                                                var children = new List <RapidXamlElement>();

                                                foreach (var acListChild in acList.ChildNodes)
                                                {
                                                    children.Add(
                                                        GetElementInternal(
                                                            xaml.Substring(acListChild.SpanStart, acListChild.Width),
                                                            startOffset + acListChild.SpanStart));
                                                }

                                                result.AddChildrenAttribute(
                                                    ncElement.Name.Substring(elementName.Length + 1),
                                                    children,
                                                    startOffset + ncElement.SpanStart,
                                                    ncElement.Width);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        result.AddChildAttribute(
                                            ncElement.Name.Substring(elementName.Length + 1),
                                            attrString,
                                            startOffset + ncElement.SpanStart,
                                            ncElement.Width);
                                    }

                                    var childAsString = xaml.Substring(ncElement.Start, ncElement.Width);

                                    if (content.TrimStart().StartsWith(childAsString.TrimStart()))
                                    {
                                        content = content.TrimStart().Substring(childAsString.Length).Trim();
                                    }
                                }
                                else
                                {
                                    result.AddChild(GetElementInternal(xaml.Substring(nodeChild.SpanStart, nodeChild.Width), startOffset + nodeChild.SpanStart));
                                }
                            }
                            else if (nodeChild is XmlEmptyElementSyntax ncSelfClosing)
                            {
                                var nodeToAdd =
                                    RapidXamlElement.Build(
                                        ncSelfClosing.Name,
                                        startOffset + nodeChild.SpanStart,
                                        nodeChild.Width,
                                        xaml.Substring(nodeChild.SpanStart, nodeChild.Width));

                                foreach (var attr in ncSelfClosing.AttributesNode)
                                {
                                    nodeToAdd.AddInlineAttribute(attr.Name, attr.Value, startOffset + attr.SpanStart, attr.Width);
                                }

                                result.AddChild(nodeToAdd);
                            }
                        }
                    }
                }

                result.SetContent(content);

                return(result);
            }

            //// Cache these responses to avoid unnecessary repeated parsing
            if (!string.IsNullOrWhiteSpace(xamlElement) &&
                RxElementCache.ContainsKey(xamlElement))
            {
                return(RxElementCache[xamlElement]);
            }
            else
            {
                var rxElement = GetElementInternal(xamlElement, offset);

                if (rxElement != null)
                {
                    RxElementCache.Add(xamlElement, rxElement);
                }

                return(rxElement);
            }
        }
        public void ContainsAttribute_None_NotFound()
        {
            var sut = RapidXamlElement.Build("Grid");

            Assert.IsFalse(sut.ContainsAttribute("Any"));
        }
        public void ContainsDescendant_NoChildren()
        {
            var sut = RapidXamlElement.Build("Grid");

            Assert.IsFalse(sut.ContainsDescendant("one"));
        }