From 8853b7f0c083c3e1829b11425a6eb796fa9bd22d Mon Sep 17 00:00:00 2001 From: Dan Sinclair Date: Tue, 13 Feb 2018 19:00:27 +0000 Subject: Add tests for CXFA_Node child manipulation This CL adds tests for CXFA_Node::InsertChild and CXFA_Node::RemoveChild methods. Change-Id: I6ef9e76dfbfa8a9b8246620ecf80c88812b332fc Reviewed-on: https://pdfium-review.googlesource.com/26371 Commit-Queue: dsinclair Reviewed-by: Tom Sepez --- xfa/fxfa/parser/cxfa_document.h | 7 +- xfa/fxfa/parser/cxfa_node.cpp | 3 - xfa/fxfa/parser/cxfa_node.h | 1 + xfa/fxfa/parser/cxfa_node_unittest.cpp | 402 ++++++++++++++++++++++++++++++++- 4 files changed, 404 insertions(+), 9 deletions(-) diff --git a/xfa/fxfa/parser/cxfa_document.h b/xfa/fxfa/parser/cxfa_document.h index f12148bee4..09c2601fa9 100644 --- a/xfa/fxfa/parser/cxfa_document.h +++ b/xfa/fxfa/parser/cxfa_document.h @@ -60,14 +60,15 @@ class CXFA_Object; class CXFA_Document { public: explicit CXFA_Document(CXFA_DocumentParser* pParser); - ~CXFA_Document(); + virtual ~CXFA_Document(); + + virtual CXFA_FFNotify* GetNotify() const; CFXJSE_Engine* InitScriptContext(CFXJS_Engine* fxjs_engine); CXFA_Node* GetRoot() const { return m_pRootNode; } - CFX_XMLDoc* GetXMLDoc() const; - CXFA_FFNotify* GetNotify() const; + CXFA_LocaleMgr* GetLocalMgr(); CXFA_Object* GetXFAObject(XFA_HashCode wsNodeNameHash); CXFA_Node* GetNodeByID(CXFA_Node* pRoot, const WideStringView& wsID); diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp index 04e947e64f..4896d0c39f 100644 --- a/xfa/fxfa/parser/cxfa_node.cpp +++ b/xfa/fxfa/parser/cxfa_node.cpp @@ -1149,9 +1149,6 @@ void CXFA_Node::InsertChild(int32_t index, CXFA_Node* pNode) { while (++iCount != index && pPrev->next_sibling_) pPrev = pPrev->next_sibling_; - if (index > 0 && index != iCount) - return; - pNode->next_sibling_ = pPrev->next_sibling_; pPrev->next_sibling_ = pNode; index = iCount; diff --git a/xfa/fxfa/parser/cxfa_node.h b/xfa/fxfa/parser/cxfa_node.h index 09db729130..7362c206bd 100644 --- a/xfa/fxfa/parser/cxfa_node.h +++ b/xfa/fxfa/parser/cxfa_node.h @@ -181,6 +181,7 @@ class CXFA_Node : public CXFA_Object { CXFA_Node* GetNextSibling() const { return next_sibling_; } CXFA_Node* GetPrevSibling() const; CXFA_Node* GetFirstChild() const { return first_child_; } + CXFA_Node* GetLastChild() const { return last_child_; } CXFA_Node* GetParent() const { return parent_; } CXFA_Node* GetNextContainerSibling() const; diff --git a/xfa/fxfa/parser/cxfa_node_unittest.cpp b/xfa/fxfa/parser/cxfa_node_unittest.cpp index dedef5df3a..9afc0f254f 100644 --- a/xfa/fxfa/parser/cxfa_node_unittest.cpp +++ b/xfa/fxfa/parser/cxfa_node_unittest.cpp @@ -3,11 +3,64 @@ // found in the LICENSE file. #include "xfa/fxfa/parser/cxfa_node.h" - #include "testing/gtest/include/gtest/gtest.h" #include "testing/test_support.h" +#include "third_party/base/ptr_util.h" +#include "xfa/fxfa/parser/cxfa_document.h" +#include "xfa/fxfa/parser/cxfa_document_parser.h" + +namespace { + +class CXFA_DocumentMock : public CXFA_Document { + public: + explicit CXFA_DocumentMock(CXFA_DocumentParser* parser) + : CXFA_Document(parser) {} + ~CXFA_DocumentMock() override = default; + + CXFA_FFNotify* GetNotify() const override { return nullptr; } +}; + +class TestNode : public CXFA_Node { + public: + explicit TestNode(CXFA_Document* doc) + : CXFA_Node(doc, + XFA_PacketType::Form, + (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form), + XFA_ObjectType::Node, + XFA_Element::Unknown, + nullptr, + nullptr, + L"TestNode") {} + + ~TestNode() override = default; +}; + +} // namespace -TEST(CXFA_NodeTest, NameToAttribute) { +class CXFANodeTest : public testing::Test { + public: + void SetUp() override { + doc_parser_ = pdfium::MakeUnique(nullptr); + doc_ = pdfium::MakeUnique(doc_parser_.get()); + node_ = pdfium::MakeUnique(doc_.get()); + } + + void TearDown() override { + node_ = nullptr; + doc_ = nullptr; + doc_parser_ = nullptr; + } + + CXFA_Document* GetDoc() const { return doc_.get(); } + CXFA_Node* GetNode() const { return node_.get(); } + + private: + std::unique_ptr doc_parser_; + std::unique_ptr doc_; + std::unique_ptr node_; +}; + +TEST_F(CXFANodeTest, NameToAttribute) { EXPECT_EQ(XFA_Attribute::Unknown, CXFA_Node::NameToAttribute(L"")); EXPECT_EQ(XFA_Attribute::Unknown, CXFA_Node::NameToAttribute(L"nonesuch")); EXPECT_EQ(XFA_Attribute::H, CXFA_Node::NameToAttribute(L"h")); @@ -16,7 +69,7 @@ TEST(CXFA_NodeTest, NameToAttribute) { CXFA_Node::NameToAttribute(L"decipherOnly")); } -TEST(CXFA_NodeTest, GetAttributeEnumByName) { +TEST_F(CXFANodeTest, GetAttributeEnumByName) { EXPECT_FALSE(!!CXFA_Node::NameToAttributeEnum(L"")); EXPECT_FALSE(!!CXFA_Node::NameToAttributeEnum(L"nonesuch")); EXPECT_EQ(XFA_AttributeEnum::Asterisk, *CXFA_Node::NameToAttributeEnum(L"*")); @@ -25,3 +78,346 @@ TEST(CXFA_NodeTest, GetAttributeEnumByName) { EXPECT_EQ(XFA_AttributeEnum::Lowered, *CXFA_Node::NameToAttributeEnum(L"lowered")); } + +TEST_F(CXFANodeTest, InsertFirstChild) { + EXPECT_EQ(nullptr, GetNode()->GetFirstChild()); + EXPECT_EQ(nullptr, GetNode()->GetLastChild()); + + CXFA_Node* child = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child); + + EXPECT_EQ(GetNode(), child->GetParent()); + EXPECT_EQ(child, GetNode()->GetFirstChild()); + EXPECT_EQ(child, GetNode()->GetLastChild()); + EXPECT_EQ(nullptr, child->GetPrevSibling()); + EXPECT_EQ(nullptr, child->GetNextSibling()); +} + +TEST_F(CXFANodeTest, InsertChildByNegativeIndex) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child); + + EXPECT_EQ(GetNode(), child->GetParent()); + EXPECT_EQ(nullptr, child->GetNextSibling()); + EXPECT_EQ(child0, child->GetPrevSibling()); + EXPECT_EQ(child, child0->GetNextSibling()); + EXPECT_EQ(nullptr, child0->GetPrevSibling()); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child, GetNode()->GetLastChild()); +} + +TEST_F(CXFANodeTest, InsertChildByIndex) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child1); + + CXFA_Node* child2 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child2); + + CXFA_Node* child3 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child3); + + CXFA_Node* child = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(2, child); + + EXPECT_EQ(GetNode(), child->GetParent()); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child1, child0->GetNextSibling()); + EXPECT_EQ(child, child1->GetNextSibling()); + EXPECT_EQ(child2, child->GetNextSibling()); + EXPECT_EQ(child3, child2->GetNextSibling()); + EXPECT_EQ(nullptr, child3->GetNextSibling()); + + EXPECT_EQ(child3, GetNode()->GetLastChild()); + EXPECT_EQ(child2, child3->GetPrevSibling()); + EXPECT_EQ(child, child2->GetPrevSibling()); + EXPECT_EQ(child1, child->GetPrevSibling()); + EXPECT_EQ(child0, child1->GetPrevSibling()); + EXPECT_EQ(nullptr, child0->GetPrevSibling()); +} + +TEST_F(CXFANodeTest, InsertChildIndexPastEnd) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child1); + + CXFA_Node* child = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(20, child); + + EXPECT_EQ(GetNode(), child->GetParent()); + EXPECT_EQ(nullptr, child->GetNextSibling()); + EXPECT_EQ(child1, child->GetPrevSibling()); + EXPECT_EQ(child, child1->GetNextSibling()); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child, GetNode()->GetLastChild()); +} + +TEST_F(CXFANodeTest, InsertFirstChildBeforeNullptr) { + EXPECT_EQ(nullptr, GetNode()->GetFirstChild()); + EXPECT_EQ(nullptr, GetNode()->GetLastChild()); + + CXFA_Node* child = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(child, nullptr); + + EXPECT_EQ(child, GetNode()->GetFirstChild()); + EXPECT_EQ(child, GetNode()->GetLastChild()); +} + +TEST_F(CXFANodeTest, InsertBeforeWithNullBefore) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child1); + + CXFA_Node* child = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(child, nullptr); + + EXPECT_EQ(GetNode(), child->GetParent()); + EXPECT_EQ(nullptr, child->GetNextSibling()); + EXPECT_EQ(child1, child->GetPrevSibling()); + EXPECT_EQ(child, child1->GetNextSibling()); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child, GetNode()->GetLastChild()); +} + +TEST_F(CXFANodeTest, InsertBeforeFirstChild) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child1); + + CXFA_Node* child = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(child, child0); + + EXPECT_EQ(GetNode(), child->GetParent()); + EXPECT_EQ(child0, child->GetNextSibling()); + EXPECT_EQ(nullptr, child->GetPrevSibling()); + EXPECT_EQ(child, child0->GetPrevSibling()); + + EXPECT_EQ(child, GetNode()->GetFirstChild()); + EXPECT_EQ(child1, GetNode()->GetLastChild()); +} + +TEST_F(CXFANodeTest, InsertBefore) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child1); + + CXFA_Node* child2 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child2); + + CXFA_Node* child3 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child3); + + CXFA_Node* child = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(child, child2); + + EXPECT_EQ(GetNode(), child->GetParent()); + EXPECT_EQ(child2, child->GetNextSibling()); + EXPECT_EQ(child1, child->GetPrevSibling()); + EXPECT_EQ(child, child1->GetNextSibling()); + EXPECT_EQ(child, child2->GetPrevSibling()); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child3, GetNode()->GetLastChild()); +} + +TEST_F(CXFANodeTest, RemoveOnlyChild) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child0, GetNode()->GetLastChild()); + + GetNode()->RemoveChild(child0, false); + + EXPECT_EQ(nullptr, GetNode()->GetFirstChild()); + EXPECT_EQ(nullptr, GetNode()->GetLastChild()); + + EXPECT_EQ(nullptr, child0->GetParent()); + EXPECT_EQ(nullptr, child0->GetNextSibling()); + EXPECT_EQ(nullptr, child0->GetPrevSibling()); +} + +TEST_F(CXFANodeTest, RemoveFirstChild) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child1); + + CXFA_Node* child2 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child2); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child2, GetNode()->GetLastChild()); + + GetNode()->RemoveChild(child0, false); + + EXPECT_EQ(child1, GetNode()->GetFirstChild()); + EXPECT_EQ(child2, GetNode()->GetLastChild()); + + EXPECT_EQ(nullptr, child1->GetPrevSibling()); + EXPECT_EQ(nullptr, child0->GetParent()); + EXPECT_EQ(nullptr, child0->GetNextSibling()); + EXPECT_EQ(nullptr, child0->GetPrevSibling()); +} + +TEST_F(CXFANodeTest, RemoveLastChild) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child1); + + CXFA_Node* child2 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child2); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child2, GetNode()->GetLastChild()); + + GetNode()->RemoveChild(child2, false); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child1, GetNode()->GetLastChild()); + + EXPECT_EQ(nullptr, child1->GetNextSibling()); + EXPECT_EQ(nullptr, child2->GetParent()); + EXPECT_EQ(nullptr, child2->GetNextSibling()); + EXPECT_EQ(nullptr, child2->GetPrevSibling()); +} + +TEST_F(CXFANodeTest, RemoveChild) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child1); + + CXFA_Node* child2 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child2); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child2, GetNode()->GetLastChild()); + + GetNode()->RemoveChild(child1, false); + + EXPECT_EQ(child0, GetNode()->GetFirstChild()); + EXPECT_EQ(child2, GetNode()->GetLastChild()); + + EXPECT_EQ(child2, child0->GetNextSibling()); + EXPECT_EQ(child0, child2->GetPrevSibling()); + EXPECT_EQ(nullptr, child1->GetParent()); + EXPECT_EQ(nullptr, child1->GetNextSibling()); + EXPECT_EQ(nullptr, child1->GetPrevSibling()); +} + +#ifndef NDEBUG +TEST_F(CXFANodeTest, InsertChildWithParent) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + child0->InsertChild(-1, child1); + + EXPECT_DEATH(GetNode()->InsertChild(0, child1), ""); +} + +TEST_F(CXFANodeTest, InsertNullChild) { + EXPECT_DEATH(GetNode()->InsertChild(0, nullptr), ""); +} + +TEST_F(CXFANodeTest, InsertBeforeWithNullChild) { + EXPECT_DEATH(GetNode()->InsertChild(nullptr, nullptr), ""); +} + +TEST_F(CXFANodeTest, InsertBeforeWithBeforeInAnotherParent) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + child0->InsertChild(-1, child1); + + CXFA_Node* child = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + EXPECT_DEATH(GetNode()->InsertChild(child, child1), ""); +} + +TEST_F(CXFANodeTest, InsertBeforeWithNodeInAnotherParent) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + child0->InsertChild(-1, child1); + + EXPECT_DEATH(GetNode()->InsertChild(child1, nullptr), ""); +} + +TEST_F(CXFANodeTest, RemoveChildNullptr) { + EXPECT_DEATH(GetNode()->RemoveChild(nullptr, false), ""); +} + +TEST_F(CXFANodeTest, RemoveChildAnotherParent) { + CXFA_Node* child0 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + GetNode()->InsertChild(-1, child0); + + CXFA_Node* child1 = + GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui); + child0->InsertChild(-1, child1); + + EXPECT_DEATH(GetNode()->RemoveChild(child1, false), ""); +} +#endif // NDEBUG -- cgit v1.2.3