libhtmlpp 1.0.0
Loading...
Searching...
No Matches
htmlparenttest.cpp
Go to the documentation of this file.
1/*******************************************************************************
2Copyright (c) 2021, Jan Koester jan.koester@gmx.net
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the <organization> nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*******************************************************************************/
27
28#include <iostream>
29
30#include "../src/html.h"
31
32#define Red "\033[0;31m"
33#define Green "\033[0;32m"
34#define NOCOLOR "\033[0m"
35
36static int testCount = 0;
37static int passCount = 0;
38
39static void check(bool cond, const char *desc) {
40 ++testCount;
41 if (cond) {
42 ++passCount;
43 std::cout << Green << " PASS: " << desc << NOCOLOR << std::endl;
44 } else {
45 std::cout << Red << " FAIL: " << desc << NOCOLOR << std::endl;
46 }
47}
48
49int main(){
50 // --- parentElement() after parsing ---
51 std::cout << "=== parentElement() after parse ===" << std::endl;
52 {
53 std::string html = "<div id=\"outer\"><p id=\"inner\">hi</p></div>";
54 libhtmlpp::HtmlString htmlString(html);
55 libhtmlpp::Element &root = htmlString.parse();
56
58 static_cast<libhtmlpp::HtmlElement*>(&root)->getElementbyID("outer");
60 static_cast<libhtmlpp::HtmlElement*>(&root)->getElementbyID("inner");
61 check(outer != nullptr && inner != nullptr, "found both elements by id");
62 if (outer && inner) {
63 check(inner->parentElement() == outer, "inner element's parent is the outer div");
64 check(outer->parentElement() != outer, "outer element's parent is not itself");
65 }
66 }
67
68 // --- appendChild / insertChild set parentElement() ---
69 std::cout << "=== appendChild / insertChild parent ===" << std::endl;
70 {
71 libhtmlpp::HtmlElement div("div");
72 libhtmlpp::HtmlElement span("span");
73 div.appendChild(&span);
74 libhtmlpp::Element *child = div.firstChild();
75 check(child != nullptr && child->parentElement() == &div,
76 "appendChild's new node has the container as its parent");
77 }
78 {
79 libhtmlpp::HtmlElement div("div");
80 libhtmlpp::HtmlElement span("span");
81 div.insertChild(&span);
82 libhtmlpp::Element *child = div.firstChild();
83 check(child != nullptr && child->parentElement() == &div,
84 "insertChild's new node has the container as its parent");
85 }
86
87 // --- copy re-parents into the NEW tree, not the original ---
88 std::cout << "=== copy re-parents subtree ===" << std::endl;
89 {
90 std::string html = "<div id=\"outer\"><p id=\"inner\">hi</p></div>";
91 libhtmlpp::HtmlString htmlString(html);
92 libhtmlpp::Element &root = htmlString.parse();
93 libhtmlpp::HtmlElement *origOuter =
94 static_cast<libhtmlpp::HtmlElement*>(&root)->getElementbyID("outer");
95
97 copyRoot = *static_cast<libhtmlpp::HtmlElement*>(&root);
98
99 libhtmlpp::HtmlElement *copiedInner = copyRoot.getElementbyID("inner");
100 libhtmlpp::HtmlElement *copiedOuter = copyRoot.getElementbyID("outer");
101 check(copiedInner != nullptr && copiedOuter != nullptr,
102 "found both elements by id in the copied tree");
103 if (copiedInner && copiedOuter && origOuter) {
104 check(copiedInner->parentElement() == copiedOuter,
105 "copied inner element's parent is the COPIED outer div");
106 check(copiedInner->parentElement() != origOuter,
107 "copied inner element's parent is NOT the original outer div");
108 }
109 }
110
111 // --- remove(): first-child case (the original bug) ---
112 std::cout << "=== remove() first child ===" << std::endl;
113 {
114 std::string html = "<ul><li id=\"a\">1</li><li id=\"b\">2</li><li id=\"c\">3</li></ul>";
115 libhtmlpp::HtmlString htmlString(html);
116 libhtmlpp::Element &root = htmlString.parse();
118 static_cast<libhtmlpp::HtmlElement*>(&root)->getElementbyTag("ul");
119 check(ul != nullptr, "found <ul>");
120 if (ul) {
121 // remove() destroys the node it's given (matching its only
122 // real caller, insertChild, which never touches the old child
123 // again) -- so nothing about the removed node itself is
124 // checked below, only what remains in `ul`.
125 ul->remove(ul->firstChild());
126
127 libhtmlpp::Element *newFirst = ul->firstChild();
128 check(newFirst != nullptr, "ul still has a first child after removing the old one");
129 if (newFirst) {
130 libhtmlpp::HtmlElement *newFirstHel = static_cast<libhtmlpp::HtmlElement*>(newFirst);
131 check(newFirstHel->getAtributte("id") == "b",
132 "ul's first child is now \"b\" (the old first child's next sibling)");
133 check(newFirstHel->prevElement() == nullptr,
134 "the new first child's prevElement is cleared (no dangling back-pointer)");
135 libhtmlpp::Element *third = newFirst->nextElement();
136 check(third != nullptr &&
137 static_cast<libhtmlpp::HtmlElement*>(third)->getAtributte("id") == "c",
138 "the rest of the sibling chain (\"c\") survived (the original bug lost it)");
139 }
140 }
141 }
142
143 // --- remove(): a node reached by normal sibling advancement (the crash case) ---
144 std::cout << "=== remove() non-first child (previously crashed) ===" << std::endl;
145 {
146 std::string html = "<ul><li id=\"a\">1</li><li id=\"b\">2</li><li id=\"c\">3</li></ul>";
147 libhtmlpp::HtmlString htmlString(html);
148 libhtmlpp::Element &root = htmlString.parse();
150 static_cast<libhtmlpp::HtmlElement*>(&root)->getElementbyTag("ul");
151 libhtmlpp::HtmlElement *b = static_cast<libhtmlpp::HtmlElement*>(&root)->getElementbyID("b");
152 check(ul != nullptr && b != nullptr, "found <ul> and \"b\"");
153 if (ul && b) {
155 // remove() destroys `b` (see the first-child case's comment)
156 // -- `b` must not be dereferenced after this call.
157 ul->remove(b); // previously: null-pointer dereference crash
158 check(true, "removing a middle child (reached via sibling advancement) doesn't crash");
159
160 check(a != nullptr && a->nextElement() != nullptr, "\"a\" still has a next sibling");
161 if (a && a->nextElement()) {
163 check(c->getAtributte("id") == "c", "\"a\"'s next sibling is now \"c\", skipping removed \"b\"");
164 check(c->prevElement() == a,
165 "\"c\"'s prevElement correctly points to \"a\", not left dangling at removed \"b\"");
166 }
167 }
168 }
169
170 // --- Summary ---
171 std::cout << "\n=== " << passCount << "/" << testCount << " tests passed ===" << std::endl;
172
173 return (passCount == testCount) ? 0 : -1;
174}
Abstract base class for all nodes in the HTML tree.
Definition html.h:76
Element * prevElement() const
Definition html.cpp:1389
Element * parentElement() const
Definition html.cpp:1393
Element * nextElement() const
Definition html.cpp:1385
const std::string getAtributte(const std::string &name) const
Definition html.cpp:2574
void appendChild(const Element *el)
Definition html.cpp:821
void remove(Element *el)
Definition html.cpp:898
void insertChild(const Element *el)
Definition html.cpp:784
Element * firstChild() const
Definition html.cpp:2506
HtmlElement * getElementbyID(const std::string &id) const
Definition html.cpp:2452
libhtmlpp::Element & parse()
Parses the current buffer into a DOM-like tree and returns the root element.
Definition html.cpp:365
#define Green
#define NOCOLOR
int main()
#define Red