54 std::cout <<
"=== approximateSelectorMatch ===" << std::endl;
57 std::vector<std::string> classes = {
"card",
"featured"};
59 check(CSSStyleSheet::approximateSelectorMatch(
"div",
"div", classes,
"hero"),
61 check(!CSSStyleSheet::approximateSelectorMatch(
"span",
"div", classes,
"hero"),
62 "wrong tag doesn't match");
63 check(CSSStyleSheet::approximateSelectorMatch(
".card",
"div", classes,
"hero"),
64 "single class matches");
65 check(CSSStyleSheet::approximateSelectorMatch(
".card.featured",
"div", classes,
"hero"),
66 "every class in compound must be present -- matches when all are");
67 check(!CSSStyleSheet::approximateSelectorMatch(
".card.missing",
"div", classes,
"hero"),
68 "every class in compound must be present -- rejects when one is absent");
69 check(CSSStyleSheet::approximateSelectorMatch(
"#hero",
"div", classes,
"hero"),
70 "id selector matches");
71 check(CSSStyleSheet::approximateSelectorMatch(
"div.card.featured#hero",
"div", classes,
"hero"),
72 "full compound tag.class.class#id matches");
73 check(CSSStyleSheet::approximateSelectorMatch(
".other, .card",
"div", classes,
"hero"),
74 "comma list matches if any branch matches");
78 std::cout <<
"=== approximateSelectorMatch rejects unsafe syntax ===" << std::endl;
81 std::vector<std::string> classes = {
"card"};
82 check(!CSSStyleSheet::approximateSelectorMatch(
"[data-x]",
"div", classes,
""),
83 "attribute selector rejected");
84 check(!CSSStyleSheet::approximateSelectorMatch(
"div:hover",
"div", classes,
""),
85 "pseudo-class rejected");
86 check(!CSSStyleSheet::approximateSelectorMatch(
"*",
"div", classes,
""),
87 "universal selector rejected");
88 check(!CSSStyleSheet::approximateSelectorMatch(
"[data-atom=header]>div",
"div", classes,
""),
89 "bare tag left after a combinator is rejected (would over-match every element of that tag)");
90 check(CSSStyleSheet::approximateSelectorMatch(
"[data-atom=header]>div.card",
"div", classes,
""),
91 "a qualified compound after a combinator is still specific enough to check");
95 std::cout <<
"=== collectApproximateMatches cascade ===" << std::endl;
99 ".box { color: red; font-size: 12px; }\n"
100 ".box { color: blue; }\n";
104 std::map<std::string,std::string> props;
105 props[
"color"] =
"inline-value";
106 std::string mediaRules;
107 std::set<std::string> seen;
108 sheet.collectApproximateMatches(
"div",
"box",
"hero", props, mediaRules, seen);
110 check(props[
"color"] ==
"inline-value",
111 "inline value beats a later plain (non-important) rule");
112 check(props[
"font-size"] ==
"12px",
"non-conflicting property still merged in");
116 std::string css =
"#hero { color: green !important; }\n";
120 std::map<std::string,std::string> props;
121 props[
"color"] =
"inline-value";
122 std::string mediaRules;
123 std::set<std::string> seen;
124 sheet.collectApproximateMatches(
"div",
"box",
"hero", props, mediaRules, seen);
126 check(props[
"color"] ==
"green",
127 "an !important rule overrides even an inline-set value (matches real cascade precedence)");
132 ".box { color: red; }\n"
133 ".box { color: blue; }\n";
137 std::map<std::string,std::string> props;
138 std::string mediaRules;
139 std::set<std::string> seen;
140 sheet.collectApproximateMatches(
"div",
"box",
"", props, mediaRules, seen);
142 check(props[
"color"] ==
"blue",
"later plain rule wins over an earlier plain rule");
147 ".box { color: red !important; }\n"
148 ".box { color: blue; }\n";
152 std::map<std::string,std::string> props;
153 std::string mediaRules;
154 std::set<std::string> seen;
155 sheet.collectApproximateMatches(
"div",
"box",
"", props, mediaRules, seen);
157 check(props[
"color"] ==
"red",
"!important beats a later plain rule");
161 std::cout <<
"=== collectApproximateMatches @media dedup ===" << std::endl;
164 std::string css =
"@media (max-width: 600px) { .box { color: red; } }";
168 std::set<std::string> seen;
169 for (
int i = 0; i < 3; ++i) {
170 std::map<std::string,std::string> props;
171 std::string mediaRules;
172 sheet.collectApproximateMatches(
"div",
"box",
"", props, mediaRules, seen);
173 check((i == 0) == !mediaRules.empty(),
174 "media block text only appended the first time it's seen");
176 check(seen.size() == 1,
"seenMediaBlocks accumulated exactly one block");
180 std::cout <<
"=== collectStyleBlocks + getCSSRules ===" << std::endl;
184 "<style>.card { color: red; } #hero { font-size: 20px; }</style>"
186 "<div id=\"hero\" class=\"card\" style=\"margin: 0\">hi</div>"
194 check(sheet.
getRuleCount() == 2,
"collected both <style> block rules");
197 check(target !=
nullptr,
"found target element by id");
200 std::set<std::string> seen;
202 check(result.properties[
"color"] ==
"red",
"getCSSRules folds in matching <style> block rule by class");
203 check(result.properties[
"font-size"] ==
"20px",
"getCSSRules folds in matching <style> block rule by id");
204 check(result.properties[
"margin"] ==
"0",
"getCSSRules includes the element's own inline style");
209 std::cout <<
"=== resolveCSSVariables ===" << std::endl;
211 std::map<std::string,std::string> props = {{
"--color-bg",
"0,0,0"}, {
"--alpha-bg",
"1"}};
214 "simple substitution, multiple var() in one value");
217 std::map<std::string,std::string> props;
219 "fallback used when the referenced name is unset");
222 std::map<std::string,std::string> props;
224 "no fallback and unset name resolves to empty (invalid, per spec)");
229 std::map<std::string,std::string> props = {
230 {
"--color-bg",
"10,20,30"},
231 {
"--alpha-bg",
"0.5"},
232 {
"--gradient-bg",
"rgba(var(--color-bg),var(--alpha-bg))"},
235 "multi-hop resolution through an intermediate custom property");
239 std::map<std::string,std::string> props = {{
"--color-bg",
"0,0,0"}};
241 "var(--gradient-bg, rgba(var(--color-bg),1))", props) ==
"rgba(0,0,0,1)",
242 "nested var() inside a fallback value is resolved too");
246 std::map<std::string,std::string> props = {{
"--a",
"var(--b)"}, {
"--b",
"var(--a)"}};
248 "cyclic custom-property reference resolves to empty instead of looping forever");
252 "a value with no var( at all is returned unchanged");
256 std::cout <<
"\n=== " << passCount <<
"/" << testCount <<
" tests passed ===" << std::endl;
258 return (passCount == testCount) ? 0 : -1;