libhtmlpp 1.0.0
Loading...
Searching...
No Matches
csstest.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#include "../src/css.h"
32
33#define Red "\033[0;31m"
34#define Green "\033[0;32m"
35#define NOCOLOR "\033[0m"
36
37static int testCount = 0;
38static int passCount = 0;
39
40static void check(bool cond, const char *desc) {
41 ++testCount;
42 if (cond) {
43 ++passCount;
44 std::cout << Green << " PASS: " << desc << NOCOLOR << std::endl;
45 } else {
46 std::cout << Red << " FAIL: " << desc << NOCOLOR << std::endl;
47 }
48}
49
50int main(){
51 // --- Original setAttribute tests ---
52 std::cout << "=== setAttribute tests ===" << std::endl;
53
54 libhtmlpp::HtmlElement htmlel("div");
55 try{
56 htmlel.setAttribute("Style",":;(),+~'");
57 check(true, "setAttribute with valid CSS chars");
58 }catch(...){
59 check(false, "setAttribute with valid CSS chars");
60 }
61
62 try{
63 htmlel.setAttribute("Style", "\"");
64 check(false, "setAttribute rejects double-quote");
65 }catch(...){
66 check(true, "setAttribute rejects double-quote");
67 }
68
69 // --- CSSDeclaration: parse inline style ---
70 std::cout << "=== CSSDeclaration inline parse ===" << std::endl;
71 {
73 decl.parse("color: red; font-size: 14px; margin: 0 auto;");
74 check(decl.getProperties().size() == 3, "parsed 3 properties");
75
76 const auto *p = decl.getProperty("color");
77 check(p && p->getValue() == "red", "color is red");
78
79 p = decl.getProperty("font-size");
80 check(p && p->getValue() == "14px", "font-size is 14px");
81
82 p = decl.getProperty("margin");
83 check(p && p->getValue() == "0 auto", "margin is 0 auto");
84 }
85
86 // --- CSSDeclaration: property with function values ---
87 std::cout << "=== CSSDeclaration function values ===" << std::endl;
88 {
90 decl.parse("background: rgb(255, 0, 0); border: 1px solid black;");
91 check(decl.getProperties().size() == 2, "parsed 2 properties with function");
92
93 const auto *p = decl.getProperty("background");
94 check(p && p->getValue() == "rgb(255, 0, 0)", "background has rgb()");
95 }
96
97 // --- CSSDeclaration: addProperty / removeProperty ---
98 std::cout << "=== CSSDeclaration add/remove ===" << std::endl;
99 {
101 decl.addProperty("color", "blue");
102 decl.addProperty("margin", "10px");
103 check(decl.getProperties().size() == 2, "added 2 properties");
104
105 decl.addProperty("color", "green");
106 check(decl.getProperties().size() == 2, "overwrite keeps count at 2");
107
108 const auto *p = decl.getProperty("color");
109 check(p && p->getValue() == "green", "color overwritten to green");
110
111 decl.removeProperty("margin");
112 check(decl.getProperties().size() == 1, "removed margin, 1 remaining");
113 }
114
115 // --- CSSDeclaration: serialize ---
116 std::cout << "=== CSSDeclaration serialize ===" << std::endl;
117 {
119 decl.addProperty("color", "red");
120 decl.addProperty("font-size", "12px");
121 std::string s = decl.serialize();
122 check(s.find("color: red;") != std::string::npos, "serialize contains color");
123 check(s.find("font-size: 12px;") != std::string::npos, "serialize contains font-size");
124 }
125
126 // --- CSSRule ---
127 std::cout << "=== CSSRule ===" << std::endl;
128 {
129 libhtmlpp::CSSRule rule("div.container");
130 rule.getDeclaration().addProperty("padding", "5px");
131 rule.getDeclaration().addProperty("display", "flex");
132
133 check(rule.getSelector() == "div.container", "selector is div.container");
134
135 std::string s = rule.serialize();
136 check(s.find("div.container{") != std::string::npos, "serialized rule has selector");
137 check(s.find("padding: 5px;") != std::string::npos, "serialized rule has padding");
138 }
139
140 // --- CSSStyleSheet: parse simple rules ---
141 std::cout << "=== CSSStyleSheet parse ===" << std::endl;
142 {
143 std::string css =
144 "body { margin: 0; padding: 0; }\n"
145 ".header { background-color: #333; color: white; }\n"
146 "#main > p { font-size: 16px; }\n";
147
149 sheet.parse(css);
150 check(sheet.getRuleCount() == 3, "parsed 3 rules");
151
152 const auto *r = sheet.getRule(0);
153 check(r && r->getSelector() == "body", "rule 0 selector is body");
154 check(r && r->getDeclaration().getProperty("margin"), "body has margin");
155
156 r = sheet.getRule(1);
157 check(r && r->getSelector() == ".header", "rule 1 selector is .header");
158
159 r = sheet.getRule(2);
160 check(r && r->getSelector() == "#main > p", "rule 2 selector is #main > p");
161 }
162
163 // --- CSSStyleSheet: comments ---
164 std::cout << "=== CSSStyleSheet comments ===" << std::endl;
165 {
166 std::string css = "/* header styles */ h1 { color: blue; } /* end */";
168 sheet.parse(css);
169 check(sheet.getRuleCount() == 1, "parsed 1 rule with comments");
170 check(sheet.getRule(0)->getSelector() == "h1", "selector is h1");
171 }
172
173 // --- CSSStyleSheet: @-rules ---
174 std::cout << "=== CSSStyleSheet @-rules ===" << std::endl;
175 {
176 std::string css =
177 "@import url('fonts.css');\n"
178 "@media screen and (max-width: 600px) {\n"
179 " body { font-size: 12px; }\n"
180 " .nav { display: none; }\n"
181 "}\n"
182 "@font-face { font-family: MyFont; src: url('myfont.woff'); }\n";
183
185 sheet.parse(css);
186
187 // @import becomes a rule with empty declaration
188 check(sheet.getRuleCount() >= 1, "has at least 1 rule for @import");
189
190 // @media should produce nested rules
191 bool hasMediaBody = false;
192 bool hasFontFace = false;
193 for (size_t i = 0; i < sheet.getRuleCount(); ++i) {
194 const auto *r = sheet.getRule(i);
195 if (r->getSelector().find("@media") != std::string::npos &&
196 r->getSelector().find("body") != std::string::npos) {
197 hasMediaBody = true;
198 }
199 if (r->getSelector().find("@font-face") != std::string::npos) {
200 hasFontFace = true;
201 }
202 }
203 check(hasMediaBody, "@media body rule found");
204 check(hasFontFace, "@font-face rule found");
205 }
206
207 // --- CSSStyleSheet: parseInlineStyle static helper ---
208 std::cout << "=== parseInlineStyle ===" << std::endl;
209 {
210 auto decl = libhtmlpp::CSSStyleSheet::parseInlineStyle("color: red; font-weight: bold;");
211 check(decl.getProperties().size() == 2, "parseInlineStyle parsed 2 props");
212 check(decl.getProperty("color") && decl.getProperty("color")->getValue() == "red",
213 "inline color is red");
214 }
215
216 // --- CSSStyleSheet: serialize roundtrip ---
217 std::cout << "=== serialize roundtrip ===" << std::endl;
218 {
219 std::string css = "p { color: red; } a { text-decoration: none; }";
221 sheet.parse(css);
222
223 std::string out = sheet.serialize(false);
224 check(out.find("p{") != std::string::npos, "roundtrip contains p rule");
225 check(out.find("a{") != std::string::npos, "roundtrip contains a rule");
226 check(out.find("color: red;") != std::string::npos, "roundtrip contains color");
227 }
228
229 // --- Summary ---
230 std::cout << "\n=== " << passCount << "/" << testCount << " tests passed ===" << std::endl;
231
232 return (passCount == testCount) ? 0 : -1;
233}
void addProperty(const std::string &name, const std::string &value)
Definition css.cpp:92
void removeProperty(const std::string &name)
Definition css.cpp:107
const std::vector< CSSProperty > & getProperties() const
Definition css.cpp:124
std::string serialize() const
Definition css.cpp:128
const CSSProperty * getProperty(const std::string &name) const
Definition css.cpp:116
void parse(const std::string &input)
Definition css.cpp:140
CSSDeclaration & getDeclaration()
Definition css.cpp:228
std::string serialize(bool formatted=false) const
Definition css.cpp:231
const std::string & getSelector() const
Definition css.cpp:225
void parse(const std::string &input)
Definition css.cpp:281
static CSSDeclaration parseInlineStyle(const std::string &style)
Definition css.cpp:423
std::string serialize(bool formatted=false) const
Definition css.cpp:409
const CSSRule * getRule(size_t index) const
Definition css.cpp:396
size_t getRuleCount() const
Definition css.cpp:401
void setAttribute(const std::string &name, const std::string &value)
Definition html.cpp:2439
#define Green
Definition csstest.cpp:34
#define NOCOLOR
Definition csstest.cpp:35
int main()
Definition csstest.cpp:50
#define Red
Definition csstest.cpp:33