예제 #1
0
        public void Container_RemoveContent_NullNode_Throws(Fb2Container node)
        {
            var firstAllowedNode = Fb2NodeFactory.GetNodeByName(node.AllowedElements.First());

            node.Invoking(n => n.RemoveContent((Fb2Node)null)) // Fb2Node
            .Should()
            .ThrowExactly <ArgumentNullException>();

            node.Invoking(n => n.RemoveContent((IEnumerable <Fb2Node>)null)) // IEnumerable<Fb2Node>
            .Should()
            .ThrowExactly <ArgumentNullException>();

            node.Invoking(n => n.RemoveContent((Func <Fb2Node, bool>)null)) // Func<Fb2Node, bool>
            .Should()
            .ThrowExactly <ArgumentNullException>();

            node.Invoking(n => n.RemoveContent(new List <Fb2Node> {
                null, null
            }))                                                                   // IEnumerable<Fb2Node>
            .Should()
            .ThrowExactly <ArgumentNullException>();

            node.Invoking(n => n.RemoveContent(new List <Fb2Node> {
                firstAllowedNode, null
            }))                                                                               // IEnumerable<Fb2Node>
            .Should()
            .ThrowExactly <ArgumentNullException>();
        }
예제 #2
0
 public virtual IEnumerator <object[]> GetEnumerator()
 {
     return(AllElementsNames
            .Select(name => new object[1] {
         Fb2NodeFactory.GetNodeByName(name)
     })
            .GetEnumerator());
 }
예제 #3
0
        public void GetElementByNodeName_InvalidNodeName_Throws()
        {
            var invalidNodeName = "invalidNodeName";

            Action act = () => { var node = Fb2NodeFactory.GetNodeByName(invalidNodeName); };

            act.Should().Throw <InvalidNodeException>()
            .WithMessage($"'{invalidNodeName}' is not known Fb2 node name.");
        }
예제 #4
0
        public void Container_AddContent_NullNode_Throws(Fb2Container node)
        {
            node.Should().NotBeNull();
            var firstAllowedNode = Fb2NodeFactory.GetNodeByName(node.AllowedElements.First());

            node.Invoking(n => n.AddContent((Fb2Node)null)) // Fb2Node
            .Should()
            .Throw <ArgumentNullException>();

            //string nodeName
            node.Invoking(n => n.AddContent("")).Should().Throw <ArgumentNullException>();

            //string nodeName
            node.Invoking(n => n.AddContent((string)null)).Should().Throw <ArgumentNullException>();

            // params Fb2Node[] nodes
            node.Invoking(n => n.AddContent()).Should().Throw <ArgumentNullException>();

            // params Fb2Node[] nodes
            node.Invoking(n => n.AddContent(null, null)) // lol
            .Should()
            .Throw <ArgumentNullException>();

            node.Invoking(n => n.AddContent(() => null)) // Func<Fb2Node>
            .Should()
            .Throw <ArgumentNullException>();

            node.Invoking(n => n.AddContent((Func <Fb2Node>)null)) // Func<Fb2Node>
            .Should()
            .Throw <ArgumentNullException>();

            node.Invoking(n => n.AddContent((List <Fb2Node>)null)) // IEnumerable<Fb2Node>
            .Should()
            .Throw <ArgumentNullException>();

            node.Invoking(n => n.AddContent(new List <Fb2Node> {
                null, null
            }))                                                                // IEnumerable<Fb2Node>
            .Should()
            .Throw <ArgumentNullException>();

            node.Invoking(n => n.AddContent(new List <Fb2Node> {
                firstAllowedNode, null
            }))                                                                            // IEnumerable<Fb2Node>
            .Should()
            .Throw <ArgumentNullException>();

            node.Invoking(async n => await n.AddContentAsync(
                              async() => await Task.FromResult <Fb2Node>(null))) // async node provider
            .Should()
            .ThrowExactlyAsync <ArgumentNullException>();

            node.Invoking(async n => await n.AddContentAsync(null))
            .Should()
            .ThrowExactlyAsync <ArgumentNullException>();
        }
예제 #5
0
        public void EmptyNodes_EqualityNullTest(Fb2Node instance)
        {
            instance.Should().NotBe(null);

            var instanceTwo = Fb2NodeFactory.GetNodeByName(instance.Name);

            instanceTwo.Should().NotBe(null);

            instance.Should().Be(instanceTwo);
        }
예제 #6
0
        public void IsKnownNode_ImpostorNode_ReturnsFalse()
        {
            var impostor = new ImpostorNode();

            Fb2NodeFactory.IsKnownNode(impostor).Should().BeFalse();

            var sneakyImpostor = new ImpostorNode(ElementNames.Paragraph);

            Fb2NodeFactory.IsKnownNode(sneakyImpostor).Should().BeFalse();
        }
예제 #7
0
        /// <summary>
        /// Adds new node to <see cref="Content"/> using node's `Name`.
        /// </summary>
        /// <param name="nodeName">Name to instantiate node by.</param>
        /// <returns>Current container.</returns>
        /// <exception cref="ArgumentNullException"></exception>
        public Fb2Container AddContent(string nodeName)
        {
            if (string.IsNullOrWhiteSpace(nodeName))
            {
                throw new ArgumentNullException(nameof(nodeName));
            }

            var node = Fb2NodeFactory.GetNodeByName(nodeName);

            return(AddContent(node));
        }
예제 #8
0
        public void EmptyLine_AddTextContent_IsIgnored()
        {
            var emptyLine = Fb2NodeFactory.GetNodeByName(ElementNames.EmptyLine) as Fb2Element;

            emptyLine.Should().NotBeNull();

            emptyLine.Content.Should().Be(Environment.NewLine);

            emptyLine.AddContent("test content", " ");

            emptyLine.Content.Should().Be(Environment.NewLine);

            emptyLine.AddContent(() => "test content", " ");

            emptyLine.Content.Should().Be(Environment.NewLine);
        }
예제 #9
0
        /// <summary>
        /// Gets first matching child of element by given name.
        /// </summary>
        /// <param name="name">Name to select child element by. Optional.</param>
        /// <returns>First matched child node or <see langword="null"/>.</returns>
        /// <exception cref="InvalidNodeException"></exception>
        public Fb2Node?GetFirstChild(string?name)
        {
            if (!string.IsNullOrEmpty(name) &&
                !Fb2NodeFactory.IsKnownNodeName(name))
            {
                throw new InvalidNodeException(name);
            }

            if (IsEmpty)
            {
                return(null);
            }

            return(string.IsNullOrWhiteSpace(name) ?
                   content.FirstOrDefault() :
                   content.FirstOrDefault(elem => elem.Name.EqualsIgnoreCase(name)));
        }
예제 #10
0
        public void ValidNodeName_CaseInvariantNodeName_Works()
        {
            var titleInfoCasedNodeName     = "tItLe-iNFo";
            var strikethroughCasedNodeName = "sTrIkEtHrOuGh";

            Fb2NodeFactory.IsKnownNodeName(titleInfoCasedNodeName).Should().BeTrue();
            Fb2NodeFactory.IsKnownNodeName(strikethroughCasedNodeName).Should().BeTrue();

            var titleInfo     = Fb2NodeFactory.GetNodeByName(titleInfoCasedNodeName);
            var strikethrough = Fb2NodeFactory.GetNodeByName(strikethroughCasedNodeName);

            titleInfo.Should().NotBeNull();
            strikethrough.Should().NotBeNull();

            titleInfo.Name.Should().Be(ElementNames.TitleInfo);
            strikethrough.Name.Should().Be(ElementNames.Strikethrough);
        }
예제 #11
0
        public async Task Container_AddContent_AllowedElement_Works(Fb2Container node)
        {
            node.Should().NotBeNull();
            var allowedElementName = node.AllowedElements.First();
            var firstAllowedNode   = Fb2NodeFactory.GetNodeByName(allowedElementName);

            node.AddContent(firstAllowedNode);

            node.Content.Should().NotBeEmpty().And.Subject.Should().HaveCount(1);

            ClearContainerContent(node);

            // params Fb2Node[] nodes
            node.AddContent(firstAllowedNode, firstAllowedNode); // lol

            node.Content.Should().NotBeEmpty().And.Subject.Should().HaveCount(2);

            ClearContainerContent(node);

            node.AddContent(() => firstAllowedNode); // Func<Fb2Node>

            node.Content.Should().NotBeEmpty().And.Subject.Should().HaveCount(1);

            ClearContainerContent(node);

            node.AddContent(new List <Fb2Node> {
                firstAllowedNode
            });                                                      // IEnumerable<Fb2Node>

            node.Content.Should().NotBeEmpty().And.Subject.Should().HaveCount(1);

            ClearContainerContent(node);

            // async node provider
            await node.AddContentAsync(async() => await Task.FromResult(firstAllowedNode));

            node.Content.Should().NotBeEmpty().And.Subject.Should().HaveCount(1);

            ClearContainerContent(node);

            //string name
            node.AddContent(node.AllowedElements.First());

            node.Content.Should().HaveCount(1);
        }
예제 #12
0
        public void Container_AddContent_NotAllowedElement_Throws(Fb2Container node)
        {
            node.Should().NotBeNull();
            var dataCollection = new Fb2ContainerCollection();

            var notAllowedElementName = dataCollection.AllElementsNames.Except(node.AllowedElements).Skip(5).First();

            var notAllowedNode = Fb2NodeFactory.GetNodeByName(notAllowedElementName);

            node.Invoking(n => n.AddContent(notAllowedNode.Name)) // string nodeName
            .Should()
            .Throw <UnexpectedNodeException>()
            .WithMessage($"Node '{node.Name}' can not contain '{notAllowedNode.Name}'.");

            node.Invoking(n => n.AddContent(notAllowedNode)) // Fb2Node
            .Should()
            .Throw <UnexpectedNodeException>()
            .WithMessage($"Node '{node.Name}' can not contain '{notAllowedNode.Name}'.");

            // params Fb2Node[] nodes
            node.Invoking(n => n.AddContent(notAllowedNode, notAllowedNode)) // lol
            .Should()
            .Throw <UnexpectedNodeException>()
            .WithMessage($"Node '{node.Name}' can not contain '{notAllowedNode.Name}'.");

            node.Invoking(n => n.AddContent(() => notAllowedNode)) // Func<Fb2Node>
            .Should()
            .Throw <UnexpectedNodeException>()
            .WithMessage($"Node '{node.Name}' can not contain '{notAllowedNode.Name}'.");

            node.Invoking(n => n.AddContent(new List <Fb2Node> {
                notAllowedNode
            }))                                                                    // IEnumerable<Fb2Node>
            .Should()
            .Throw <UnexpectedNodeException>()
            .WithMessage($"Node '{node.Name}' can not contain '{notAllowedNode.Name}'.");

            node.Invoking(async n =>
                          await n.AddContentAsync(async() => await Task.FromResult(notAllowedNode))) // async node provider
            .Should()
            .ThrowExactlyAsync <UnexpectedNodeException>()
            .WithMessage($"Node '{node.Name}' can not contain '{notAllowedNode.Name}'.");
        }
예제 #13
0
        /// <summary>
        /// Gets children of element by given name.
        /// </summary>
        /// <param name="name">Name to select child elements by. Case insensitive.</param>
        /// <returns>List of found child elements, if any.</returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="InvalidNodeException"></exception>
        public IEnumerable <Fb2Node> GetChildren(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (!Fb2NodeFactory.IsKnownNodeName(name))
            {
                throw new InvalidNodeException(name);
            }

            if (IsEmpty)
            {
                return(Enumerable.Empty <Fb2Node>());
            }

            return(content.Where(elem => elem.Name.EqualsIgnoreCase(name)));
        }
예제 #14
0
        /// <summary>
        /// Recursively gets all descendants of element by given name.
        /// </summary>
        /// <param name="name">Name to select descendants by.</param>
        /// <returns>List of found descendants, if any.</returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="InvalidNodeException"></exception>
        public IEnumerable <Fb2Node> GetDescendants(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (!Fb2NodeFactory.IsKnownNodeName(name))
            {
                throw new InvalidNodeException(name);
            }

            var result = new List <Fb2Node>();

            if (IsEmpty)
            {
                return(result);
            }

            for (int i = 0; i < content.Count; i++)
            {
                var element = content[i];

                if (element.Name.EqualsIgnoreCase(name))
                {
                    result.Add(element);
                }

                if (element is Fb2Container containerElement)
                {
                    var desc = containerElement.GetDescendants(name);

                    if (desc != null && desc.Any())
                    {
                        result.AddRange(desc);
                    }
                }
            }

            return(result);
        }
예제 #15
0
        /// <summary>
        /// Adds given node to <see cref="Content"/>.
        /// </summary>
        /// <param name="node">Child node to add to Content.</param>
        /// <returns>Current container.</returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="InvalidNodeException"></exception>
        /// <exception cref="UnexpectedNodeException"></exception>
        public Fb2Container AddContent(Fb2Node node)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (!Fb2NodeFactory.IsKnownNode(node))
            {
                throw new InvalidNodeException(node);
            }

            var nodeName   = node.Name;
            var isTextNode = node is TextItem;

            if (isTextNode && !CanContainText)
            {
                throw new UnexpectedNodeException(Name, nodeName);
            }

            if (!AllowedElements.Contains(nodeName) && !isTextNode)
            {
                throw new UnexpectedNodeException(Name, nodeName);
            }

            if (isTextNode)
            {
                return(TryMergeTextContent((node as TextItem) !.Content));
            }

            node.Parent = this;
            if (node.NodeMetadata == null && NodeMetadata?.DefaultNamespace != null) // copy parent default namespace to prevent serialization issues
            {
                node.NodeMetadata = new Fb2NodeMetadata(NodeMetadata?.DefaultNamespace);
            }

            content.Add(node);
            return(this);
        }
예제 #16
0
        /// <summary>
        /// Recursively looks for first matching descendant of element by given name.
        /// </summary>
        /// <param name="name">Name to select descendant by.</param>
        /// <returns>First matching descendant node or <see langword="null"/>.</returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="InvalidNodeException"></exception>
        public Fb2Node?GetFirstDescendant(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (!Fb2NodeFactory.IsKnownNodeName(name))
            {
                throw new InvalidNodeException(name);
            }

            if (IsEmpty)
            {
                return(null);
            }

            for (int i = 0; i < content.Count; i++)
            {
                var element = content[i];

                if (element.Name.EqualsIgnoreCase(name))
                {
                    return(element);
                }

                if (element is Fb2Container containerElement)
                {
                    var firstDesc = containerElement.GetFirstDescendant(name);

                    if (firstDesc != null)
                    {
                        return(firstDesc);
                    }
                }
            }

            return(null);
        }
예제 #17
0
        public void CloneNode_EqualityTest(Fb2Node instance)
        {
            var instanceTwo = Fb2NodeFactory.GetNodeByName(instance.Name);

            instance.Should().Be(instanceTwo);
        }
예제 #18
0
 public void IsKnownNode_ValidNode_ReturnsTrue(Fb2Node node)
 {
     Fb2NodeFactory.IsKnownNode(node).Should().BeTrue();
 }
예제 #19
0
 public void IsKnownNodeName_ValidNodeName_ReturnsTrue(string nodeName)
 {
     Fb2NodeFactory.IsKnownNodeName(nodeName).Should().BeTrue();
 }
예제 #20
0
        public void IsKnownNodeName_InvalidNodeName_ReturnsFalse()
        {
            var invalidNodeName = "invalidNodeName";

            Fb2NodeFactory.IsKnownNodeName(invalidNodeName).Should().BeFalse();
        }
예제 #21
0
        public void Container_RemoveContent_ExistingElement_Works(Fb2Container node)
        {
            node.Should().NotBeNull();

            var firstAllowedNode = Fb2NodeFactory.GetNodeByName(node.AllowedElements.First());
            var lastAllowedNode  = Fb2NodeFactory.GetNodeByName(node.AllowedElements.Last());

            var nodesEquals = firstAllowedNode.Equals(lastAllowedNode);

            node.AddContent(firstAllowedNode, lastAllowedNode);
            node.Content.Should().NotBeEmpty().And.Subject.Should().HaveCount(2);

            firstAllowedNode.Parent.Should().NotBeNull();
            firstAllowedNode.Parent.Should().Be(node);

            lastAllowedNode.Parent.Should().NotBeNull();
            lastAllowedNode.Parent.Should().Be(node);

            node.RemoveContent(firstAllowedNode); // Fb2Node
            firstAllowedNode.Parent.Should().BeNull();

            node.Content.Should().NotBeEmpty().And.Subject.Should().HaveCount(1);
            node.Content.Should().Contain(lastAllowedNode);

            // empty nodes (without sub tree) of same type are, basically, equal lol
            // so if you add 2 empty "bold" elements to "paragraph"
            // and then use RemoveContent(firstAllowedNode), and check Contains - it will return true
            if (!nodesEquals) // when container can have only one type child
            {
                node.Content.Contains(firstAllowedNode).Should().BeFalse();
            }

            ClearContainerContent(node);

            lastAllowedNode.Parent.Should().BeNull();

            node.AddContent(firstAllowedNode, lastAllowedNode);
            node.Content.Should().NotBeEmpty().And.Subject.Should().HaveCount(2);

            firstAllowedNode.Parent.Should().NotBeNull();
            firstAllowedNode.Parent.Should().Be(node);

            lastAllowedNode.Parent.Should().NotBeNull();
            lastAllowedNode.Parent.Should().Be(node);

            node.RemoveContent(new List <Fb2Node> {
                firstAllowedNode, lastAllowedNode
            });                                                                          // IEnumerable<Fb2Node>

            node.Content.Should().BeEmpty();

            node.AddContent(firstAllowedNode, lastAllowedNode);
            node.Content.Should().NotBeEmpty().And.Subject.Should().HaveCount(2);

            node.RemoveContent(n => n.Name.Equals(firstAllowedNode.Name)); // Func<Fb2Node, bool> predicate

            if (nodesEquals)
            {
                node.Content.Should().BeEmpty();
            }
            else
            {
                node.Content.Should().NotBeEmpty().And.Subject.Should().HaveCount(1);
                node.Content.Should().Contain(lastAllowedNode);
                node.Content.Should().NotContain(firstAllowedNode);
            }

            ClearContainerContent(node);
        }
예제 #22
0
        /// <summary>
        /// Container node loading mechanism. Loads attributes and sequentially calls `Load` on all child nodes.
        /// </summary>
        /// <param name="node">Node to load as Fb2Container</param>
        /// <param name="preserveWhitespace">Indicates if whitespace chars (\t, \n, \r) should be preserved. By default `false`.</param>
        /// <param name="loadUnsafe">Indicates whether "Unsafe" children should be loaded. By default `true`. </param>
        public override void Load(
            [In] XNode node,
            [In] Fb2Container?parentNode = null,
            bool preserveWhitespace      = false,
            bool loadUnsafe            = true,
            bool loadNamespaceMetadata = true)
        {
            base.Load(node, parentNode, preserveWhitespace, loadUnsafe, loadNamespaceMetadata);

            var element = node as XElement;

            if (element == null || element.IsEmpty)
            {
                return;
            }

            var nodes = element.Nodes()
                        .Where(n =>
            {
                if (n.NodeType == XmlNodeType.Text)
                {
                    return(true);
                }

                var isElement = n.NodeType == XmlNodeType.Element;
                if (!isElement)
                {
                    return(false);
                }

                var elementNode   = n as XElement;
                var nodeLocalName = elementNode.Name.LocalName;
                return(!nodeLocalName.EqualsIgnoreCase(ElementNames.FictionText) &&
                       Fb2NodeFactory.IsKnownNodeName(nodeLocalName));
            })
                        .ToList();

            var nodesCount = nodes.Count;

            if (nodesCount == 0)
            {
                return;
            }

            for (int i = 0; i < nodesCount; i++)
            {
                var validNode = nodes[i];

                string localName = validNode.NodeType == XmlNodeType.Element ?
                                   ((XElement)validNode).Name.LocalName.ToLowerInvariant() :
                                   ElementNames.FictionText;

                var isUnsafe = validNode.NodeType == XmlNodeType.Text ?
                               !CanContainText :
                               !AllowedElements.Contains(localName);

                if (isUnsafe && !loadUnsafe)
                {
                    continue;
                }

                var elem = Fb2NodeFactory.GetNodeByName(localName);
                elem.Load(validNode, this, preserveWhitespace, loadUnsafe, loadNamespaceMetadata);
                elem.IsUnsafe = isUnsafe;

                content.Add(elem);
            }
        }