30#include "../src/html.h"
31#include "../src/css.h"
33#define Red "\033[0;31m"
34#define Green "\033[0;32m"
35#define NOCOLOR "\033[0m"
37static int testCount = 0;
38static int passCount = 0;
40static void check(
bool cond,
const char *desc) {
44 std::cout <<
Green <<
" PASS: " << desc <<
NOCOLOR << std::endl;
46 std::cout <<
Red <<
" FAIL: " << desc <<
NOCOLOR << std::endl;
52 std::cout <<
"=== setAttribute tests ===" << std::endl;
57 check(
true,
"setAttribute with valid CSS chars");
59 check(
false,
"setAttribute with valid CSS chars");
64 check(
false,
"setAttribute rejects double-quote");
66 check(
true,
"setAttribute rejects double-quote");
70 std::cout <<
"=== CSSDeclaration inline parse ===" << std::endl;
73 decl.
parse(
"color: red; font-size: 14px; margin: 0 auto;");
74 check(decl.
getProperties().size() == 3,
"parsed 3 properties");
77 check(p && p->getValue() ==
"red",
"color is red");
80 check(p && p->getValue() ==
"14px",
"font-size is 14px");
83 check(p && p->getValue() ==
"0 auto",
"margin is 0 auto");
87 std::cout <<
"=== CSSDeclaration function values ===" << std::endl;
90 decl.
parse(
"background: rgb(255, 0, 0); border: 1px solid black;");
91 check(decl.
getProperties().size() == 2,
"parsed 2 properties with function");
94 check(p && p->getValue() ==
"rgb(255, 0, 0)",
"background has rgb()");
98 std::cout <<
"=== CSSDeclaration add/remove ===" << std::endl;
103 check(decl.
getProperties().size() == 2,
"added 2 properties");
106 check(decl.
getProperties().size() == 2,
"overwrite keeps count at 2");
109 check(p && p->getValue() ==
"green",
"color overwritten to green");
112 check(decl.
getProperties().size() == 1,
"removed margin, 1 remaining");
116 std::cout <<
"=== CSSDeclaration serialize ===" << std::endl;
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");
127 std::cout <<
"=== CSSRule ===" << std::endl;
133 check(rule.
getSelector() ==
"div.container",
"selector is div.container");
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");
141 std::cout <<
"=== CSSStyleSheet parse ===" << std::endl;
144 "body { margin: 0; padding: 0; }\n"
145 ".header { background-color: #333; color: white; }\n"
146 "#main > p { font-size: 16px; }\n";
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");
157 check(r && r->getSelector() ==
".header",
"rule 1 selector is .header");
160 check(r && r->getSelector() ==
"#main > p",
"rule 2 selector is #main > p");
164 std::cout <<
"=== CSSStyleSheet comments ===" << std::endl;
166 std::string css =
"/* header styles */ h1 { color: blue; } /* end */";
169 check(sheet.
getRuleCount() == 1,
"parsed 1 rule with comments");
174 std::cout <<
"=== CSSStyleSheet @-rules ===" << std::endl;
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"
182 "@font-face { font-family: MyFont; src: url('myfont.woff'); }\n";
188 check(sheet.
getRuleCount() >= 1,
"has at least 1 rule for @import");
191 bool hasMediaBody =
false;
192 bool hasFontFace =
false;
194 const auto *r = sheet.
getRule(i);
195 if (r->getSelector().find(
"@media") != std::string::npos &&
196 r->getSelector().find(
"body") != std::string::npos) {
199 if (r->getSelector().find(
"@font-face") != std::string::npos) {
203 check(hasMediaBody,
"@media body rule found");
204 check(hasFontFace,
"@font-face rule found");
208 std::cout <<
"=== parseInlineStyle ===" << std::endl;
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");
217 std::cout <<
"=== serialize roundtrip ===" << std::endl;
219 std::string css =
"p { color: red; } a { text-decoration: none; }";
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");
230 std::cout <<
"\n=== " << passCount <<
"/" << testCount <<
" tests passed ===" << std::endl;
232 return (passCount == testCount) ? 0 : -1;
void addProperty(const std::string &name, const std::string &value)
void removeProperty(const std::string &name)
const std::vector< CSSProperty > & getProperties() const
std::string serialize() const
const CSSProperty * getProperty(const std::string &name) const
void parse(const std::string &input)
CSSDeclaration & getDeclaration()
std::string serialize(bool formatted=false) const
const std::string & getSelector() const
void parse(const std::string &input)
static CSSDeclaration parseInlineStyle(const std::string &style)
std::string serialize(bool formatted=false) const
const CSSRule * getRule(size_t index) const
size_t getRuleCount() const
void setAttribute(const std::string &name, const std::string &value)