home
readme
diff
tree
note
docs
0commit abf4e7fe9546106c00ce8e8f1ebab94fde4d3310
1Author: lakefox <mason@lakefox.net>
2Date: Sun Jan 11 15:30:48 2026 -0700
3
4 getUnit parses variables and strings. Tests updated
5
6diff --git a/Makefile b/Makefile
7index c295710..32afc3f 100755
8--- a/Makefile
9+++ b/Makefile
10@@ -1,5 +1,14 @@
11 # --- Variables ---
12 CCFLAGS = -Wall -Wextra -std=c++2b -g -O0 -fsanitize=address,undefined -fno-omit-frame-pointer
13+# -O2 -Wall -Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough \
14+# -Werror=format-security \
15+# -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \
16+# -D_GLIBCXX_ASSERTIONS \
17+# -fstrict-flex-arrays=3 \
18+# -fstack-clash-protection -fstack-protector-strong \
19+# -Wl,-z,nodlopen -Wl,-z,noexecstack \
20+# -Wl,-z,relro -Wl,-z,now \
21+# -Wl,--as-needed -Wl,--no-copy-dt-needed-entries
22 CC = clang++
23
24 .PHONY: all clean all_tests
25diff --git a/include/grim.h b/include/grim.h
26index 5615570..07e5ce3 100755
27--- a/include/grim.h
28+++ b/include/grim.h
29@@ -90,6 +90,7 @@ enum class UnitType : short {
30 CALC, MIN, MAX, CLAMP, ROUND, MOD, PROGRESS, REMD, POW, SQRT, HYPOT, LOG, EXP, ABS,
31 SIGN, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, VAR,
32 BLUR, BRIGHTNESS, CONTRAST, DROP_SHADOW, GRAYSCALE, HUE_ROTATE, INVERT, OPACITY, SEPIA, SATURATE,
33+ ATTR, TYPE, ENV, IF,
34 // Easing Functions
35 EASING_FUNCTION, LINEAR_EASING_FUNCTION, LINEAR, EASE, EASE_IN, EASE_OUT, EASE_IN_OUT, CUBIC_BEZIER_FUNCTION,
36 STEP_START, STEP_END, STEPS_FUNCTION, JUMP_START, JUMP_END, JUMP_NONE, JUMP_BOTH,
37@@ -97,7 +98,7 @@ enum class UnitType : short {
38 MATRIX, MATRIX3D, PERSPECTIVE, ROTATE, ROTATE3D, ROTATEX, ROTATEY, ROTATEZ, SCALE, SCALE3D, SCALEX, SCALEY, SCALEZ, TRANSLATE, TRANSLATE3D, TRANSLATEX, TRANSLATEY, TRANSLATEZ,
39 SKEW, SKEWX, SKEWY,
40 // Rounding
41- NEAREST, UP, DOWN, TO_ZERO,
42+ NEAREST, UP, DOWN, TO_ZERO,
43
44 // Keyword
45 PRINT, SCREEN, TOKEN, FUNC, GROUP, NO_SUPPORT, IMAGE, STRING
46@@ -278,6 +279,39 @@ enum class KeyType : short {
47 Z_INDEX, ZOOM
48 };
49
50+class IndexedMap {
51+ public:
52+ std::vector<std::pair<std::string, std::vector<Unit>>> map{};
53+ std::vector<Unit> find(std::string key) {
54+ for (size_t i = 0; i < map.size(); i++) {
55+ if (map[i].first == key) {
56+ return map[i].second;
57+ }
58+ }
59+ }
60+
61+ size_t index(std::string key) {
62+ for (size_t i = 0; i < map.size(); i++) {
63+ if (map[i].first == key) {
64+ return i;
65+ }
66+ }
67+ }
68+ std::vector<Unit> at(size_t i) {
69+ return map[i].second;
70+ }
71+
72+ size_t set(std::string key, std::vector<Unit> value) {
73+ for (size_t i = 0; i < map.size(); i++) {
74+ if (map[i].first == key) {
75+ map[i].second = value;
76+ return i;
77+ }
78+ }
79+ map.push_back({key, value});
80+ return map.size()-1;
81+ }
82+};
83
84 class Style {
85 public:
86@@ -287,7 +321,9 @@ class Style {
87 std::vector<std::vector<std::string>> selector{};
88
89 std::unordered_map<KeyType, std::vector<Unit>> properties{};
90- std::unordered_map<std::string, std::vector<Unit>> variables{};
91+
92+ IndexedMap variables{};
93+ std::vector<std::string> strings{};
94
95 // Nesting
96 std::vector<Style> children{};
97diff --git a/include/parser.h b/include/parser.h
98index ba33470..f7b94c8 100755
99--- a/include/parser.h
100+++ b/include/parser.h
101@@ -20,6 +20,6 @@ struct ParsedDocument {
102 std::unordered_map<std::string, std::string> parseAttributes(std::string_view& token);
103 ParsedDocument parseDocument(std::istream& inputStream);
104 Style parseCSS(std::istream& inputStream);
105-std::vector<Unit> getUnit(std::string);
106+std::vector<Unit> getUnit(Style*, std::string);
107
108 #endif
109diff --git a/playground/css_unit.cc b/playground/css_unit.cc
110index c064e68..640ae55 100644
111--- a/playground/css_unit.cc
112+++ b/playground/css_unit.cc
113@@ -4,7 +4,8 @@
114 #include <fstream>
115
116 int main() {
117- std::vector<Unit> test = getUnit("attr(size px)");
118+ Style style{};
119+ std::vector<Unit> test = getUnit(&style, "\"test\"");
120
121 std::cout << "Done" << std::endl;
122 }
123diff --git a/src/grim.cc b/src/grim.cc
124index 23940a2..556b914 100755
125--- a/src/grim.cc
126+++ b/src/grim.cc
127@@ -1313,7 +1313,6 @@ float UnitLengthValue(Node* n, const std::vector<Unit>& units, size_t start, siz
128
129 i += unit.value.INT;
130 break;
131- case UnitType::ATTR
132
133 // Need to add variable injection and group handling
134 }
135diff --git a/src/parser.cc b/src/parser.cc
136index 78fa6a0..8b51153 100755
137--- a/src/parser.cc
138+++ b/src/parser.cc
139@@ -1019,6 +1019,11 @@ static const std::unordered_map<std::string_view, UnitType> kFunc{
140 {"skewX", UnitType::SKEWX},
141 {"skewY", UnitType::SKEWY},
142 {"url", UnitType::URL},
143+ {"attr", UnitType::ATTR},
144+ {"type", UnitType::TYPE},
145+ {"env", UnitType::ENV},
146+ {"if", UnitType::IF},
147+ {"var", UnitType::VAR},
148 {"", UnitType::GROUP}
149 };
150
151@@ -1027,10 +1032,16 @@ static const std::unordered_map<std::string_view, float> kAbsSize{
152 {"large",1.2f}, {"x-large",1.5f}, {"xx-large",2.0f}, {"xxx-large",3.0f}
153 };
154
155-std::vector<Unit> getUnit(std::string value) {
156+/*
157+ Parses a string into Unit's and stores variables & strings into the Style object
158+
159+*/
160+
161+std::vector<Unit> getUnit(Style* s, std::string value) {
162 std::vector<Unit> units;
163
164 std::string buffer = "";
165+ std::string str_buffer = "";
166 int parenDepth = 0;
167 bool inQuotes = false;
168 // Needs to not be empty but can't be a quote
169@@ -1040,14 +1051,23 @@ std::vector<Unit> getUnit(std::string value) {
170 for (size_t i = 0; i < value.length(); i++) {
171 char v = value[i];
172 if (v == '\\' && !escaped) escaped = true;
173- if ((v == '"' || v == '\'') && parenDepth == 0) {
174+ if (!escaped && (v == '"' || v == '\'') && parenDepth == 0) {
175 if (inQuotes && v == quoteType) {
176+ s->strings.push_back(str_buffer);
177+ str_buffer.clear();
178+
179+ Unit unit{};
180+ unit.type = UnitType::STRING;
181+ unit.isFunc = false;
182+ unit.value.INT = s->strings.size()-1;
183+ units.push_back(unit);
184+
185 inQuotes = false;
186 } else if (!inQuotes) {
187 quoteType = v;
188 inQuotes = true;
189 }
190-
191+ continue;
192 }
193
194 if (!inQuotes) {
195@@ -1076,7 +1096,7 @@ std::vector<Unit> getUnit(std::string value) {
196 }
197 }
198
199- std::vector<Unit> children = getUnit(value);
200+ std::vector<Unit> children = getUnit(s, value);
201
202 Unit unit;
203 unit.isFunc = true;
204@@ -1101,88 +1121,75 @@ std::vector<Unit> getUnit(std::string value) {
205
206 // Split by spaces into parts
207
208- bool found = false;
209 if (auto it = kMatch.find(buffer); it != kMatch.end()) {
210 /*
211 Keyword Matching
212 */
213 unit.type = it->second;
214 // the value is not used here
215- found = true;
216 } else if (auto it = kColors.find(buffer); it != kColors.end()) {
217 /*
218 Color Matching
219 */
220 unit.type = UnitType::HEX;
221 unit.value.UINT = it->second;
222- found = true;
223 } else {
224+ bool found = false;
225 for (const auto& [suffix, type, trim] : table) {
226 if (buffer.ends_with(suffix)) {
227- unit.value.FLOAT = std::stof(std::string(buffer.substr(0, buffer.size() - trim)));
228- unit.type = type;
229 found = true;
230+ try {
231+ unit.value.FLOAT = std::stof(std::string(buffer.substr(0, buffer.size() - trim)));
232+ } catch (...) {
233+ unit.value.FLOAT = 0.0f;
234+ }
235+
236+ unit.type = type;
237 break;
238 }
239 }
240- }
241
242- if (!found) {
243- if (buffer.starts_with("#")) {
244- /*
245- # Prefix for HEX codes
246- */
247- unit.type = UnitType::HEX;
248- unit.value.UINT = std::stoul(buffer.substr(1), nullptr, 16);
249- found = true;
250- } else if (auto it = kAbsSize.find(buffer); it != kAbsSize.end()) {
251- /*
252- Absolute size matching
253- */
254- unit.type = UnitType::EM;
255- unit.value.FLOAT = it->second;
256- found = true;
257- } else {
258- // Maybe its a number?
259- try {
260- unit.value.FLOAT = std::stof(buffer);
261- unit.type = UnitType::NUMBER;
262- found = true;
263- } catch (...) {
264- found = false;
265+ if (!found) {
266+ if (buffer.starts_with("#") && buffer.length() > 1) {
267+ /*
268+ # Prefix for HEX codes
269+ */
270+ unit.type = UnitType::HEX;
271+ unit.value.UINT = std::stoul(buffer.substr(1), nullptr, 16);
272+ } else if (auto it = kAbsSize.find(buffer); it != kAbsSize.end()) {
273+ /*
274+ Absolute size matching
275+ */
276+ unit.type = UnitType::EM;
277+ unit.value.FLOAT = it->second;
278+ } else {
279+ // Maybe its a number?
280+ try {
281+ unit.value.FLOAT = std::stof(buffer);
282+ unit.type = UnitType::NUMBER;
283+ } catch (...) {
284+ // If we are here it is not a known parsable word, this could be a typo
285+ // or a keyword like with the attr(size px) function. Here px would be
286+ // parsed but not size.
287+ if (!buffer.empty() && buffer.find_first_not_of(' ') != std::string::npos) {
288+ unit.type = UnitType::VAR;
289+ unit.value.INT = s->variables.set(buffer, {});
290+ } else {
291+ continue;
292+ }
293+ }
294 }
295 }
296- /*
297- need to handle strings
298- */
299- }
300-
301- if (found) {
302- // Only process if its found
303- units.push_back(unit);
304-
305- buffer.clear();
306- } else if (v == ',') {
307- // if we hit a comma before we match we can dump the
308- // buffer and try again
309- std::cerr << "Unable to parse buffer: " << buffer << std::endl;
310- buffer.clear();
311 }
312
313+ units.push_back(unit);
314+ buffer.clear();
315 } else if (inQuotes) {
316- if (v == '"') continue;
317- Unit u;
318- u.isFunc = false;
319- u.type = UnitType::STRING;
320- UnitValue uv;
321- uv.CHAR = v;
322- u.value = uv;
323-
324- units.push_back(u);
325+ str_buffer.push_back(v);
326 } else {
327 buffer.push_back(v);
328 }
329-
330+
331 escaped = false;
332 if (v == '\\') escaped = true;
333 }
334@@ -1341,7 +1348,7 @@ Style parseCSS(std::istream& inputStream) {
335 }
336
337 if (key.length() > 2 && key[0] == '-' && key[1] == '-') {
338- current->variables[key] = getUnit(value);
339+ current->variables.set(key, getUnit(current, value));
340 } else {
341 KeyType keyENUM;
342
343@@ -1350,7 +1357,7 @@ Style parseCSS(std::istream& inputStream) {
344 } else {
345 std::cout << "Invalid property name: " << key << std::endl;
346 }
347- current->properties[keyENUM] = getUnit(value);
348+ current->properties[keyENUM] = getUnit(current, value);
349 }
350 }
351 buffer.clear();
352diff --git a/tests/css_unit.cc b/tests/css_unit.cc
353index 7a280b0..515fb90 100755
354--- a/tests/css_unit.cc
355+++ b/tests/css_unit.cc
356@@ -1,827 +1,131 @@
357 #include <catch_amalgamated.hpp>
358 #include "../include/grim.h"
359 #include "../include/parser.h"
360-#include <iostream>
361-#include <fstream>
362
363-
364-TEST_CASE("getUnit can parse color values") {
365- SECTION("getUnit can parse hex") {
366- std::vector<Unit> test = getUnit("#ff7dff1a");
367- INFO(test[0].value.UINT);
368- REQUIRE(0xff7dff1a == test[0].value.UINT);
369- };
370-
371- SECTION("getUnit can parse rgba") {
372- std::vector<Unit> test = getUnit("rgba(255 125 255 / 10%)");
373- REQUIRE(test[0].type == UnitType::RGBA);
374- REQUIRE(test[0].value.INT == 5);
375- REQUIRE(test[1].type == UnitType::NUMBER);
376- REQUIRE(test[1].value.FLOAT == 255.0f);
377- REQUIRE(test[2].type == UnitType::NUMBER);
378- REQUIRE(test[2].value.FLOAT == 125.0f);
379- REQUIRE(test[3].type == UnitType::NUMBER);
380- REQUIRE(test[3].value.FLOAT == 255.0f);
381- REQUIRE(test[4].type == UnitType::DIV);
382- REQUIRE(test[5].type == UnitType::PERCENT);
383- REQUIRE(test[5].value.FLOAT == 10.0f);
384- };
385-
386- SECTION("getUnit can parse rgb") {
387- std::vector<Unit> test = getUnit("rgb(255, 125, 255)");
388- REQUIRE(test[0].type == UnitType::RGB);
389- REQUIRE(test[0].value.INT == 3);
390- REQUIRE(test[1].type == UnitType::NUMBER);
391- REQUIRE(test[1].value.FLOAT == 255.0f);
392- REQUIRE(test[2].type == UnitType::NUMBER);
393- REQUIRE(test[2].value.FLOAT == 125.0f);
394- REQUIRE(test[3].type == UnitType::NUMBER);
395- REQUIRE(test[3].value.FLOAT == 255.0f);
396- }
397-
398- SECTION("getUnit can parse hsl") {
399- std::vector<Unit> t = getUnit("hsl(300deg 100% 74.51%)");
400- REQUIRE(t[0].type == UnitType::HSL);
401- REQUIRE(t[0].value.INT == 3);
402- REQUIRE(t[1].type == UnitType::DEG);
403- REQUIRE(t[1].value.FLOAT == 300.0f);
404- REQUIRE(t[2].type == UnitType::PERCENT);
405- REQUIRE(t[2].value.FLOAT == 100.0f);
406- REQUIRE(t[3].type == UnitType::PERCENT);
407- REQUIRE(t[3].value.FLOAT == 74.51f);
408-
409- }
410-
411- SECTION("getUnit can parse hsla") {
412- std::vector<Unit> t = getUnit("hsl(300deg 100% 74.51% / 10%)");
413- REQUIRE(t[0].type == UnitType::HSL);
414- REQUIRE(t[0].value.INT == 5);
415- REQUIRE(t[1].type == UnitType::DEG);
416- REQUIRE(t[1].value.FLOAT == 300.0f);
417- REQUIRE(t[2].type == UnitType::PERCENT);
418- REQUIRE(t[2].value.FLOAT == 100.0f);
419- REQUIRE(t[3].type == UnitType::PERCENT);
420- REQUIRE(t[3].value.FLOAT == 74.51f);
421- REQUIRE(t[4].type == UnitType::DIV);
422- REQUIRE(t[5].type == UnitType::PERCENT);
423- REQUIRE(t[5].value.FLOAT == 10.0f);
424- }
425-
426- // px
427- SECTION("getUnit can parse px") {
428- std::vector<Unit> test = getUnit("10px 10.5px");
429- REQUIRE(10.0f == test[0].value.FLOAT);
430- REQUIRE(UnitType::PX == test[0].type);
431- REQUIRE(10.5f == test[1].value.FLOAT);
432- REQUIRE(UnitType::PX == test[1].type);
433- }
434-
435- // em
436- SECTION("getUnit can parse em") {
437- std::vector<Unit> test = getUnit("1.2em 0em");
438- REQUIRE(1.2f == test[0].value.FLOAT);
439- REQUIRE(UnitType::EM == test[0].type);
440- REQUIRE(0.0f == test[1].value.FLOAT);
441- REQUIRE(UnitType::EM == test[1].type);
442- }
443-
444- // %
445- SECTION("getUnit can parse percent") {
446- std::vector<Unit> test = getUnit("50% 100.5%");
447- REQUIRE(50.0f == test[0].value.FLOAT);
448- REQUIRE(UnitType::PERCENT == test[0].type);
449- REQUIRE(100.5f == test[1].value.FLOAT);
450- REQUIRE(UnitType::PERCENT == test[1].type);
451- }
452-
453- // cm
454- SECTION("getUnit can parse cm") {
455- std::vector<Unit> test = getUnit("2.54cm 0.5cm");
456- REQUIRE(2.54f == test[0].value.FLOAT);
457- REQUIRE(UnitType::CM == test[0].type);
458- REQUIRE(0.5f == test[1].value.FLOAT);
459- REQUIRE(UnitType::CM == test[1].type);
460- }
461-
462- // cap
463- SECTION("getUnit can parse cap") {
464- std::vector<Unit> test = getUnit("3cap 0cap");
465- REQUIRE(3.0f == test[0].value.FLOAT);
466- REQUIRE(UnitType::CAP == test[0].type);
467- REQUIRE(0.0f == test[1].value.FLOAT);
468- REQUIRE(UnitType::CAP == test[1].type);
469- }
470-
471- // ch
472- SECTION("getUnit can parse ch") {
473- std::vector<Unit> test = getUnit("10ch 0.5ch");
474- REQUIRE(10.0f == test[0].value.FLOAT);
475- REQUIRE(UnitType::CH == test[0].type);
476- REQUIRE(0.5f == test[1].value.FLOAT);
477- REQUIRE(UnitType::CH == test[1].type);
478- }
479-
480- // ex
481- SECTION("getUnit can parse ex") {
482- std::vector<Unit> test = getUnit("2ex 1.5ex");
483- REQUIRE(2.0f == test[0].value.FLOAT);
484- REQUIRE(UnitType::EX == test[0].type);
485- REQUIRE(1.5f == test[1].value.FLOAT);
486- REQUIRE(UnitType::EX == test[1].type);
487- }
488-
489- // ic
490- SECTION("getUnit can parse ic") {
491- std::vector<Unit> test = getUnit("5ic 0ic");
492- REQUIRE(5.0f == test[0].value.FLOAT);
493- REQUIRE(UnitType::IC == test[0].type);
494- REQUIRE(0.0f == test[1].value.FLOAT);
495- REQUIRE(UnitType::IC == test[1].type);
496- }
497-
498- // lh
499- SECTION("getUnit can parse lh") {
500- std::vector<Unit> test = getUnit("1.2lh 0lh");
501- REQUIRE(1.2f == test[0].value.FLOAT);
502- REQUIRE(UnitType::LH == test[0].type);
503- REQUIRE(0.0f == test[1].value.FLOAT);
504- REQUIRE(UnitType::LH == test[1].type);
505- }
506-
507- // rcap
508- SECTION("getUnit can parse rcap") {
509- std::vector<Unit> test = getUnit("2rcap 0.5rcap");
510- REQUIRE(2.0f == test[0].value.FLOAT);
511- REQUIRE(UnitType::RCAP == test[0].type);
512- REQUIRE(0.5f == test[1].value.FLOAT);
513- REQUIRE(UnitType::RCAP == test[1].type);
514- }
515-
516- // rch
517- SECTION("getUnit can parse rch") {
518- std::vector<Unit> test = getUnit("3rch 0rch");
519- REQUIRE(3.0f == test[0].value.FLOAT);
520- REQUIRE(UnitType::RCH == test[0].type);
521- REQUIRE(0.0f == test[1].value.FLOAT);
522- REQUIRE(UnitType::RCH == test[1].type);
523- }
524-
525- // rem
526- SECTION("getUnit can parse rem") {
527- std::vector<Unit> test = getUnit("1rem 0.5rem");
528- REQUIRE(1.0f == test[0].value.FLOAT);
529- REQUIRE(UnitType::REM == test[0].type);
530- REQUIRE(0.5f == test[1].value.FLOAT);
531- REQUIRE(UnitType::REM == test[1].type);
532- }
533-
534- // rex
535- SECTION("getUnit can parse rex") {
536- std::vector<Unit> test = getUnit("1.5rex 0rex");
537- REQUIRE(1.5f == test[0].value.FLOAT);
538- REQUIRE(UnitType::REX == test[0].type);
539- REQUIRE(0.0f == test[1].value.FLOAT);
540- REQUIRE(UnitType::REX == test[1].type);
541- }
542-
543- // ric
544- SECTION("getUnit can parse ric") {
545- std::vector<Unit> test = getUnit("2ric 0.25ric");
546- REQUIRE(2.0f == test[0].value.FLOAT);
547- REQUIRE(UnitType::RIC == test[0].type);
548- REQUIRE(0.25f == test[1].value.FLOAT);
549- REQUIRE(UnitType::RIC == test[1].type);
550- }
551-
552- // rlh
553- SECTION("getUnit can parse rlh") {
554- std::vector<Unit> test = getUnit("1.1rlh 0rlh");
555- REQUIRE(1.1f == test[0].value.FLOAT);
556- REQUIRE(UnitType::RLH == test[0].type);
557- REQUIRE(0.0f == test[1].value.FLOAT);
558- REQUIRE(UnitType::RLH == test[1].type);
559- }
560-
561- // vh
562- SECTION("getUnit can parse vh") {
563- std::vector<Unit> test = getUnit("50vh 100vh");
564- REQUIRE(50.0f == test[0].value.FLOAT);
565- REQUIRE(UnitType::VH == test[0].type);
566- REQUIRE(100.0f == test[1].value.FLOAT);
567- REQUIRE(UnitType::VH == test[1].type);
568- }
569-
570- // vw
571- SECTION("getUnit can parse vw") {
572- std::vector<Unit> test = getUnit("25vw 0vw");
573- REQUIRE(25.0f == test[0].value.FLOAT);
574- REQUIRE(UnitType::VW == test[0].type);
575- REQUIRE(0.0f == test[1].value.FLOAT);
576- REQUIRE(UnitType::VW == test[1].type);
577- }
578-
579- // vmax
580- SECTION("getUnit can parse vmax") {
581- std::vector<Unit> test = getUnit("75vmax 0vmax");
582- REQUIRE(75.0f == test[0].value.FLOAT);
583- REQUIRE(UnitType::VMAX == test[0].type);
584- REQUIRE(0.0f == test[1].value.FLOAT);
585- REQUIRE(UnitType::VMAX == test[1].type);
586- }
587-
588- // vmin
589- SECTION("getUnit can parse vmin") {
590- std::vector<Unit> test = getUnit("10vmin 99.9vmin");
591- REQUIRE(10.0f == test[0].value.FLOAT);
592- REQUIRE(UnitType::VMIN == test[0].type);
593- REQUIRE(99.9f == test[1].value.FLOAT);
594- REQUIRE(UnitType::VMIN == test[1].type);
595- }
596-
597- // vb
598- SECTION("getUnit can parse vb") {
599- std::vector<Unit> test = getUnit("20vb 0vb");
600- REQUIRE(20.0f == test[0].value.FLOAT);
601- REQUIRE(UnitType::VB == test[0].type);
602- REQUIRE(0.0f == test[1].value.FLOAT);
603- REQUIRE(UnitType::VB == test[1].type);
604- }
605-
606- // vi
607- SECTION("getUnit can parse vi") {
608- std::vector<Unit> test = getUnit("5vi 1vi");
609- REQUIRE(5.0f == test[0].value.FLOAT);
610- REQUIRE(UnitType::VI == test[0].type);
611- REQUIRE(1.0f == test[1].value.FLOAT);
612- REQUIRE(UnitType::VI == test[1].type);
613- }
614-
615- // cqw
616- SECTION("getUnit can parse cqw") {
617- std::vector<Unit> test = getUnit("30cqw 0cqw");
618- REQUIRE(30.0f == test[0].value.FLOAT);
619- REQUIRE(UnitType::CQW == test[0].type);
620- REQUIRE(0.0f == test[1].value.FLOAT);
621- REQUIRE(UnitType::CQW == test[1].type);
622- }
623-
624- // cqh
625- SECTION("getUnit can parse cqh") {
626- std::vector<Unit> test = getUnit("40cqh 10.5cqh");
627- REQUIRE(40.0f == test[0].value.FLOAT);
628- REQUIRE(UnitType::CQH == test[0].type);
629- REQUIRE(10.5f == test[1].value.FLOAT);
630- REQUIRE(UnitType::CQH == test[1].type);
631- }
632-
633- // cqi
634- SECTION("getUnit can parse cqi") {
635- std::vector<Unit> test = getUnit("15cqi 0cqi");
636- REQUIRE(15.0f == test[0].value.FLOAT);
637- REQUIRE(UnitType::CQI == test[0].type);
638- REQUIRE(0.0f == test[1].value.FLOAT);
639- REQUIRE(UnitType::CQI == test[1].type);
640- }
641-
642- // cqb
643- SECTION("getUnit can parse cqb") {
644- std::vector<Unit> test = getUnit("25cqb 1cqb");
645- REQUIRE(25.0f == test[0].value.FLOAT);
646- REQUIRE(UnitType::CQB == test[0].type);
647- REQUIRE(1.0f == test[1].value.FLOAT);
648- REQUIRE(UnitType::CQB == test[1].type);
649- }
650-
651- // cqmin
652- SECTION("getUnit can parse cqmin") {
653- std::vector<Unit> test = getUnit("10cqmin 0cqmin");
654- REQUIRE(10.0f == test[0].value.FLOAT);
655- REQUIRE(UnitType::CQMIN == test[0].type);
656- REQUIRE(0.0f == test[1].value.FLOAT);
657- REQUIRE(UnitType::CQMIN == test[1].type);
658- }
659-
660- // cqmax
661- SECTION("getUnit can parse cqmax") {
662- std::vector<Unit> test = getUnit("90cqmax \n 50.5cqmax");
663- REQUIRE(90.0f == test[0].value.FLOAT);
664- REQUIRE(UnitType::CQMAX == test[0].type);
665- REQUIRE(50.5f == test[1].value.FLOAT);
666- REQUIRE(UnitType::CQMAX == test[1].type);
667- }
668-
669- // mm
670- SECTION("getUnit can parse mm") {
671- std::vector<Unit> test = getUnit("10mm 0.1mm");
672- REQUIRE(10.0f == test[0].value.FLOAT);
673- REQUIRE(UnitType::MM == test[0].type);
674- REQUIRE(0.1f == test[1].value.FLOAT);
675- REQUIRE(UnitType::MM == test[1].type);
676- }
677-
678- // q
679- SECTION("getUnit can parse q") {
680- std::vector<Unit> test = getUnit("40q, 1q");
681- REQUIRE(40.0f == test[0].value.FLOAT);
682- REQUIRE(UnitType::Q == test[0].type);
683- REQUIRE(1.0f == test[1].value.FLOAT);
684- REQUIRE(UnitType::Q == test[1].type);
685- }
686-
687- // in
688- SECTION("getUnit can parse in") {
689- std::vector<Unit> test = getUnit("1in 0.5in");
690- REQUIRE(1.0f == test[0].value.FLOAT);
691- REQUIRE(UnitType::IN == test[0].type);
692- REQUIRE(0.5f == test[1].value.FLOAT);
693- REQUIRE(UnitType::IN == test[1].type);
694- }
695-
696- // pc
697- SECTION("getUnit can parse pc") {
698- std::vector<Unit> test = getUnit("6pc, 0pc");
699- REQUIRE(6.0f == test[0].value.FLOAT);
700- REQUIRE(UnitType::PC == test[0].type);
701- REQUIRE(0.0f == test[1].value.FLOAT);
702- REQUIRE(UnitType::PC == test[1].type);
703- }
704-
705- // pt
706- SECTION("getUnit can parse pt") {
707- std::vector<Unit> test = getUnit("12pt");
708- REQUIRE(12.0f == test[0].value.FLOAT);
709- REQUIRE(UnitType::PT == test[0].type);
710- }
711-
712- // HEX Color
713- SECTION("getUnit can parse a hex color") {
714- std::vector<Unit> test = getUnit("#000000");
715- REQUIRE(0x000000 == test[0].value.UINT);
716- REQUIRE(UnitType::HEX == test[0].type);
717- }
718-
719- // xx-small abs unit
720- SECTION("getUnit can parse a xx-small abs unit") {
721- std::vector<Unit> test = getUnit("xx-small");
722- REQUIRE(0.6f == test[0].value.FLOAT);
723- REQUIRE(UnitType::EM == test[0].type);
724- }
725-
726- // x-small abs unit
727- SECTION("getUnit can parse an x-small abs unit") {
728- std::vector<Unit> test = getUnit("x-small");
729- REQUIRE(0.75f == test[0].value.FLOAT);
730- REQUIRE(UnitType::EM == test[0].type);
731- }
732-
733- // small abs unit
734- SECTION("getUnit can parse a small abs unit") {
735- std::vector<Unit> test = getUnit("small");
736- REQUIRE(0.89f == test[0].value.FLOAT);
737- REQUIRE(UnitType::EM == test[0].type);
738- }
739-
740- // medium abs unit
741- SECTION("getUnit can parse a medium abs unit") {
742- std::vector<Unit> test = getUnit("medium");
743- REQUIRE(1.0f == test[0].value.FLOAT);
744- REQUIRE(UnitType::EM == test[0].type);
745- }
746-
747- // large abs unit
748- SECTION("getUnit can parse a large abs unit") {
749- std::vector<Unit> test = getUnit("large");
750- REQUIRE(1.2f == test[0].value.FLOAT);
751- REQUIRE(UnitType::EM == test[0].type);
752- }
753-
754- // x-large abs unit
755- SECTION("getUnit can parse an x-large abs unit") {
756- std::vector<Unit> test = getUnit("x-large");
757- REQUIRE(1.5f == test[0].value.FLOAT);
758- REQUIRE(UnitType::EM == test[0].type);
759- }
760-
761- // xx-large abs unit
762- SECTION("getUnit can parse an xx-large abs unit") {
763- std::vector<Unit> test = getUnit("xx-large");
764- REQUIRE(2.0f == test[0].value.FLOAT);
765- REQUIRE(UnitType::EM == test[0].type);
766- }
767-
768- // xxx-large abs unit
769- SECTION("getUnit can parse an xxx-large abs unit") {
770- std::vector<Unit> test = getUnit("xxx-large");
771- REQUIRE(3.0f == test[0].value.FLOAT);
772- REQUIRE(UnitType::EM == test[0].type);
773- }
774-
775- // small and large abs unit
776- SECTION("getUnit can parse two abs units with a space") {
777- std::vector<Unit> test = getUnit("small large");
778- REQUIRE(0.89f == test[0].value.FLOAT);
779- REQUIRE(1.2f == test[1].value.FLOAT);
780- REQUIRE(UnitType::EM == test[0].type);
781- REQUIRE(UnitType::EM == test[1].type);
782- }
783-
784- // small and large abs unit
785- SECTION("getUnit can parse two abs units with a comma") {
786- std::vector<Unit> test = getUnit("small, large");
787- REQUIRE(0.89f == test[0].value.FLOAT);
788- REQUIRE(1.2f == test[1].value.FLOAT);
789- REQUIRE(UnitType::EM == test[0].type);
790- REQUIRE(UnitType::EM == test[1].type);
791- }
792-
793- // baseline
794- SECTION("getUnit can parse baseline into first baseline") {
795- std::vector<Unit> test = getUnit("baseline");
796- REQUIRE(UnitType::FIRST_BASELINE == test[0].type);
797- }
798-
799- // first baseline
800- SECTION("getUnit can parse first baseline") {
801- std::vector<Unit> test = getUnit("first baseline");
802- REQUIRE(UnitType::FIRST_BASELINE == test[0].type);
803- }
804-
805- // last baseline
806- SECTION("getUnit can parse last baseline") {
807- std::vector<Unit> test = getUnit("last baseline");
808- REQUIRE(UnitType::LAST_BASELINE == test[0].type);
809- }
810-
811- // last baseline with another space seperated value
812- SECTION("getUnit can parse last baseline with a space seperated value") {
813- std::vector<Unit> test = getUnit("last baseline 10px");
814- REQUIRE(UnitType::LAST_BASELINE == test[0].type);
815- REQUIRE(10.0f == test[1].value.FLOAT);
816- REQUIRE(UnitType::PX == test[1].type);
817- }
818-
819- // content-box
820- SECTION("getUnit can parse content-box") {
821- std::vector<Unit> test = getUnit("content-box");
822- REQUIRE(UnitType::CONTENT == test[0].type);
823- }
824-
825- // padding-box
826- SECTION("getUnit can parse padding-box") {
827- std::vector<Unit> test = getUnit("padding-box");
828- REQUIRE(UnitType::PADDING == test[0].type);
829- }
830-
831- // border-box
832- SECTION("getUnit can parse border-box") {
833- std::vector<Unit> test = getUnit("border-box");
834- REQUIRE(UnitType::BORDER == test[0].type);
835- }
836-
837- // margin-box
838- SECTION("getUnit can parse margin-box") {
839- std::vector<Unit> test = getUnit("margin-box");
840- REQUIRE(UnitType::MARGIN == test[0].type);
841- }
842-
843- // fill-box
844- SECTION("getUnit can parse fill-box") {
845- std::vector<Unit> test = getUnit("fill-box");
846- REQUIRE(UnitType::FILL == test[0].type);
847- }
848-
849- // stroke-box
850- SECTION("getUnit can parse stroke-box") {
851- std::vector<Unit> test = getUnit("stroke-box");
852- REQUIRE(UnitType::STROKE == test[0].type);
853- }
854-
855- // view-box
856- SECTION("getUnit can parse view-box") {
857- std::vector<Unit> test = getUnit("view-box");
858- REQUIRE(UnitType::VIEW == test[0].type);
859- }
860-
861- // calc
862- SECTION("getUnit can parse calc") {
863- std::vector<Unit> test = getUnit("calc(10px)");
864- REQUIRE(UnitType::CALC == test[0].type);
865- REQUIRE(1 == test[0].value.INT);
866-
867- REQUIRE(10.0f == test[1].value.FLOAT);
868- REQUIRE(UnitType::PX == test[1].type);
869- }
870-
871- SECTION("getUnit can parse calc with add") {
872- std::vector<Unit> test = getUnit("calc(10px + 14%)");
873- REQUIRE(UnitType::CALC == test[0].type);
874- REQUIRE(3 == test[0].value.INT);
875-
876- REQUIRE(10.0f == test[1].value.FLOAT);
877- REQUIRE(UnitType::PX == test[1].type);
878-
879- REQUIRE(UnitType::ADD == test[2].type);
880-
881- REQUIRE(14.0f == test[3].value.FLOAT);
882- REQUIRE(UnitType::PERCENT == test[3].type);
883- }
884-
885-
886- // ---------- 1. Whitespace handling ----------
887- SECTION("calc ignores leading / trailing spaces and tabs") {
888- std::vector<Unit> t = getUnit(" calc( 50vmin ) ");
889- REQUIRE(t[0].type == UnitType::CALC);
890- REQUIRE(t[0].value.INT == 1);
891- REQUIRE(t[1].value.FLOAT == 50.0f);
892- REQUIRE(t[1].type == UnitType::VMIN);
893- }
894-
895- // ---------- 2. Subtraction ----------
896- SECTION("calc with subtraction") {
897- std::vector<Unit> t = getUnit("calc(100% - 2em)");
898- REQUIRE(t[0].type == UnitType::CALC);
899- REQUIRE(t[2].type == UnitType::SUB);
900- REQUIRE(t[3].value.FLOAT == 2.0f);
901- REQUIRE(t[3].type == UnitType::EM);
902- }
903-
904- // ---------- 3. Multiplication ----------
905- SECTION("calc with multiply") {
906- std::vector<Unit> t = getUnit("calc(3 * 4.5rem)");
907- REQUIRE(t[2].type == UnitType::MULT);
908- REQUIRE(t[3].value.FLOAT == 4.5f);
909- REQUIRE(t[3].type == UnitType::REM);
910- }
911-
912- // ---------- 4. Division ----------
913- SECTION("calc with divide") {
914- std::vector<Unit> t = getUnit("calc(90deg / 3)");
915- REQUIRE(t[2].type == UnitType::DIV);
916- REQUIRE(t[3].value.FLOAT == 3.0f);
917- REQUIRE(t[1].type == UnitType::DEG);
918- }
919-
920- // ---------- 5. Chained operators ----------
921- SECTION("calc with three terms and two ops") {
922- std::vector<Unit> t = getUnit("calc(10px + 20px - 5px)");
923- REQUIRE(t[0].value.INT == 5); // px + px - px
924- REQUIRE(t[2].type == UnitType::ADD);
925- REQUIRE(t[4].type == UnitType::SUB);
926- }
927-
928- // ---------- 6. Parentheses ----------
929- SECTION("calc nested parentheses") {
930- std::vector<Unit> t = getUnit("calc((2 * 3em) + 4px)");
931- // The first child should be the subtree for the parens
932- REQUIRE(t[0].type == UnitType::CALC);
933- REQUIRE(t[0].value.INT == 6);
934- REQUIRE(t[0].type == UnitType::CALC);
935- REQUIRE(t[1].value.INT == 3);
936- REQUIRE(t[6].type == UnitType::PX);
937- }
938-
939- // ---------- 7. Constants ----------
940- SECTION("calc with pi") {
941- std::vector<Unit> t = getUnit("calc(pi * 30px)");
942- REQUIRE(t[1].type == UnitType::PI);
943- REQUIRE(t[2].type == UnitType::MULT);
944- REQUIRE(t[3].value.FLOAT == 30.0f);
945- }
946-
947- // ---------- 8. Negative numbers ----------
948- SECTION("calc with negative value") {
949- std::vector<Unit> t = getUnit("calc(-15vw + 10vw)");
950- REQUIRE(t[1].value.FLOAT == -15.0f);
951- REQUIRE(t[1].type == UnitType::VW);
952- }
953-
954- // ---------- 9. Zero unit ----------
955- SECTION("calc with zero px") {
956- std::vector<Unit> t = getUnit("calc(0px + 5px)");
957- REQUIRE(t[1].value.FLOAT == 0.0f);
958- REQUIRE(t[1].type == UnitType::PX);
959- }
960-
961- // ---------- 10. Scientific notation ----------
962- SECTION("calc with scientific notation") {
963- std::vector<Unit> t = getUnit("calc(1.2e3px)");
964- REQUIRE(t[1].value.FLOAT == 1200.0f);
965- REQUIRE(t[1].type == UnitType::PX);
966- }
967-
968- // ---------- 11. Many spaces around operator ----------
969- SECTION("calc with huge whitespace gap") {
970- std::vector<Unit> t = getUnit("calc(50px * 2)");
971- REQUIRE(t[2].type == UnitType::MULT);
972- }
973-
974- // ---------- 12. Double negation ----------
975- SECTION("calc with double negation") {
976- std::vector<Unit> t = getUnit("calc(10px - -5px)");
977- REQUIRE(t[3].value.FLOAT == -5.0f);
978- REQUIRE(t[2].type == UnitType::SUB);
979- }
980-
981- // ---------- 13. Mixed units ----------
982- SECTION("calc mixed vw and px") {
983- std::vector<Unit> t = getUnit("calc(100vw - 20px)");
984- REQUIRE(t[1].type == UnitType::VW);
985- REQUIRE(t[3].type == UnitType::PX);
986- }
987-
988- // ---------- 14. Functions inside calc ----------
989- SECTION("calc with nested function") {
990- std::vector<Unit> t = getUnit("calc(min(10px, 20px) + 5px)");
991- // first child should be the min() subtree
992- REQUIRE(t[1].type == UnitType::MIN);
993- REQUIRE(t[5].value.FLOAT == 5.0f);
994- }
995-
996- SECTION("calc with infinity") {
997- std::vector<Unit> t = getUnit("calc(infinity)");
998- REQUIRE(t[1].type == UnitType::INF);
999- }
1000-
1001- SECTION("calc with negative infinity") {
1002- std::vector<Unit> t = getUnit("calc(-infinity)");
1003- REQUIRE(t[1].type == UnitType::NEGINF);
1004- t = getUnit("calc(1 - -infinity)");
1005- REQUIRE(t[1].type == UnitType::NUMBER);
1006- REQUIRE(t[2].type == UnitType::SUB);
1007- REQUIRE(t[3].type == UnitType::NEGINF);
1008- }
1009-
1010- SECTION("calc with NaN") {
1011- std::vector<Unit> t = getUnit("calc(NaN)");
1012- REQUIRE(t[1].type == UnitType::NaN);
1013- }
1014-
1015- SECTION("calc with E") {
1016- std::vector<Unit> t = getUnit("calc(e)");
1017- REQUIRE(t[1].type == UnitType::E);
1018- }
1019-
1020- SECTION("content-distribution space-between") {
1021- std::vector<Unit> t = getUnit("space-between");
1022- REQUIRE(t[0].type == UnitType::BETWEEN);
1023- }
1024-
1025- SECTION("content-distribution space-around") {
1026- std::vector<Unit> t = getUnit("space-around");
1027- REQUIRE(t[0].type == UnitType::AROUND);
1028- }
1029- SECTION("content-distribution space-between") {
1030- std::vector<Unit> t = getUnit("space-evenly");
1031- REQUIRE(t[0].type == UnitType::EVENLY);
1032- }
1033- SECTION("content-distribution stretch") {
1034- std::vector<Unit> t = getUnit("stretch");
1035- REQUIRE(t[0].type == UnitType::STRETCH);
1036- }
1037- SECTION("content-position center") {
1038- std::vector<Unit> t = getUnit("center");
1039- REQUIRE(t[0].type == UnitType::CENTER);
1040- }
1041- SECTION("content-position start") {
1042- std::vector<Unit> t = getUnit("start");
1043- REQUIRE(t[0].type == UnitType::START);
1044- }
1045- SECTION("content-position end") {
1046- std::vector<Unit> t = getUnit("end");
1047- REQUIRE(t[0].type == UnitType::END);
1048- }
1049- SECTION("content-position flex-start") {
1050- std::vector<Unit> t = getUnit("flex-start");
1051- REQUIRE(t[0].type == UnitType::FLEX_START);
1052- }
1053- SECTION("content-position flex-end") {
1054- std::vector<Unit> t = getUnit("flex-end");
1055- REQUIRE(t[0].type == UnitType::FLEX_END);
1056- }
1057- SECTION("display-box contents") {
1058- std::vector<Unit> t = getUnit("contents");
1059- REQUIRE(t[0].type == UnitType::CONTENTS);
1060- }
1061-
1062- SECTION("display-box none") {
1063- std::vector<Unit> t = getUnit("none");
1064- REQUIRE(t[0].type == UnitType::NONE);
1065- }
1066- SECTION("display-inside flow") {
1067- std::vector<Unit> t = getUnit("flow");
1068- REQUIRE(t[0].type == UnitType::FLOW);
1069- }
1070- SECTION("display-inside flow-root") {
1071- std::vector<Unit> t = getUnit("flow-root");
1072- REQUIRE(t[0].type == UnitType::FLOW_ROOT);
1073- }
1074- SECTION("display-inside table") {
1075- std::vector<Unit> t = getUnit("table");
1076- REQUIRE(t[0].type == UnitType::TABLE);
1077- }
1078- SECTION("display-inside flex") {
1079- std::vector<Unit> t = getUnit("flex");
1080- REQUIRE(t[0].type == UnitType::FLEX);
1081- }
1082- SECTION("display-inside grid") {
1083- std::vector<Unit> t = getUnit("grid");
1084- REQUIRE(t[0].type == UnitType::GRID);
1085- }
1086- SECTION("display-inside ruby") {
1087- std::vector<Unit> t = getUnit("ruby");
1088- REQUIRE(t[0].type == UnitType::RUBY);
1089- }
1090- SECTION("display-internal table-row-group") {
1091- std::vector<Unit> t = getUnit("table-row-group");
1092- REQUIRE(t[0].type == UnitType::TABLE_ROW_GROUP);
1093- }
1094- SECTION("display-internal table-header-group") {
1095- std::vector<Unit> t = getUnit("table-header-group");
1096- REQUIRE(t[0].type == UnitType::TABLE_HEADER_GROUP);
1097- }
1098- SECTION("display-internal table-footer-group") {
1099- std::vector<Unit> t = getUnit("table-footer-group");
1100- REQUIRE(t[0].type == UnitType::TABLE_FOOTER_GROUP);
1101- }
1102- SECTION("display-internal table-column-group") {
1103- std::vector<Unit> t = getUnit("table-column-group");
1104- REQUIRE(t[0].type == UnitType::TABLE_COLUMN_GROUP);
1105- }
1106- SECTION("display-internal table-row") {
1107- std::vector<Unit> t = getUnit("table-row");
1108- REQUIRE(t[0].type == UnitType::TABLE_ROW);
1109- }
1110- SECTION("display-internal table-cell") {
1111- std::vector<Unit> t = getUnit("table-cell");
1112- REQUIRE(t[0].type == UnitType::TABLE_CELL);
1113- }
1114- SECTION("display-internal table-column") {
1115- std::vector<Unit> t = getUnit("table-column");
1116- REQUIRE(t[0].type == UnitType::TABLE_COLUMN);
1117- }
1118- SECTION("display-internal table-caption") {
1119- std::vector<Unit> t = getUnit("table-caption");
1120- REQUIRE(t[0].type == UnitType::TABLE_CAPTION);
1121- }
1122- SECTION("display-internal ruby-base") {
1123- std::vector<Unit> t = getUnit("ruby-base");
1124- REQUIRE(t[0].type == UnitType::RUBY_BASE);
1125- }
1126- SECTION("display-internal ruby-text") {
1127- std::vector<Unit> t = getUnit("ruby-text");
1128- REQUIRE(t[0].type == UnitType::RUBY_TEXT);
1129- }
1130- SECTION("display-internal ruby-base-container") {
1131- std::vector<Unit> t = getUnit("ruby-base-container");
1132- REQUIRE(t[0].type == UnitType::RUBY_BASE_CONTAINER);
1133- }
1134- SECTION("display-internal ruby-text-container") {
1135- std::vector<Unit> t = getUnit("ruby-text-container");
1136- REQUIRE(t[0].type == UnitType::RUBY_TEXT_CONTAINER);
1137- }
1138- SECTION("display-legacy inline-block") {
1139- std::vector<Unit> t = getUnit("inline-block");
1140- REQUIRE(t[0].type == UnitType::INLINE_BLOCK);
1141- }
1142- SECTION("display-legacy inline-table") {
1143- std::vector<Unit> t = getUnit("inline-table");
1144- REQUIRE(t[0].type == UnitType::INLINE_TABLE);
1145- }
1146- SECTION("display-legacy inline-flex") {
1147- std::vector<Unit> t = getUnit("inline-flex");
1148- REQUIRE(t[0].type == UnitType::INLINE_FLEX);
1149- }
1150- SECTION("display-legacy inline-grid") {
1151- std::vector<Unit> t = getUnit("inline-grid");
1152- REQUIRE(t[0].type == UnitType::INLINE_GRID);
1153- }
1154- SECTION("display-listitem list-item") {
1155- std::vector<Unit> t = getUnit("list-item");
1156- REQUIRE(t[0].type == UnitType::LISTITEM);
1157- }
1158- SECTION("display-outside block") {
1159- std::vector<Unit> t = getUnit("block");
1160- REQUIRE(t[0].type == UnitType::BLOCK);
1161- }
1162- SECTION("display-outside inline") {
1163- std::vector<Unit> t = getUnit("inline");
1164- REQUIRE(t[0].type == UnitType::INLINE);
1165- }
1166- SECTION("display-outside run-in") {
1167- std::vector<Unit> t = getUnit("run-in");
1168- REQUIRE(t[0].type == UnitType::RUN_IN);
1169- }
1170+TEST_CASE("Comprehensive getUnit and Style State Tests") {
1171+ Style s;
1172+
1173+ SECTION("1. Color Spaces and Numerical Conversions") {
1174+ // Hex with Alpha
1175+ auto hex = getUnit(&s, "#ff7dff1a");
1176+ REQUIRE(hex[0].value.UINT == 0xff7dff1a);
1177+ REQUIRE(hex[0].type == UnitType::HEX);
1178+
1179+ // Functional RGB/RGBA
1180+ auto rgba = getUnit(&s, "rgba(255 125 255 / 10%)");
1181+ REQUIRE(rgba[0].type == UnitType::RGBA);
1182+ REQUIRE(rgba[1].value.FLOAT == 255.0f);
1183+ REQUIRE(rgba[4].type == UnitType::DIV);
1184+ REQUIRE(rgba[5].type == UnitType::PERCENT);
1185+ REQUIRE(rgba[5].value.FLOAT == 10.0f);
1186+
1187+ // HSL/HSLA
1188+ auto hsl = getUnit(&s, "hsl(300deg 100% 74.51% / 10%)");
1189+ REQUIRE(hsl[0].type == UnitType::HSL);
1190+ REQUIRE(hsl[1].type == UnitType::DEG);
1191+ REQUIRE(hsl[1].value.FLOAT == 300.0f);
1192+ REQUIRE(hsl[3].value.FLOAT == 74.51f);
1193+ }
1194+
1195+ SECTION("2. Full Unit Table Coverage") {
1196+ // Physical and Typographic Units
1197+ auto units = getUnit(&s, "10px 1.2em 50% 2.54cm 3cap 10ch 2ex 5ic 1.2lh 1rem 50vh 25vw 30cqw 10mm 1in 12pt 6pc 40q");
1198+
1199+ std::vector<UnitType> expected = {
1200+ UnitType::PX, UnitType::EM, UnitType::PERCENT, UnitType::CM, UnitType::CAP,
1201+ UnitType::CH, UnitType::EX, UnitType::IC, UnitType::LH, UnitType::REM,
1202+ UnitType::VH, UnitType::VW, UnitType::CQW, UnitType::MM, UnitType::IN,
1203+ UnitType::PT, UnitType::PC, UnitType::Q
1204+ };
1205+
1206+ for (size_t i = 0; i < expected.size(); i++) {
1207+ INFO("Testing unit at index " << i);
1208+ REQUIRE(units[i].type == expected[i]);
1209+ }
1210+ }
1211+
1212+ SECTION("3. Logical Keywords and Absolute Sizes") {
1213+ // Absolute Sizes (Matched via kAbsSize map)
1214+ auto sizes = getUnit(&s, "xx-small small medium xxx-large");
1215+ REQUIRE(sizes[0].value.FLOAT == 0.6f);
1216+ REQUIRE(sizes[1].value.FLOAT == 0.89f);
1217+ REQUIRE(sizes[2].value.FLOAT == 1.0f);
1218+ REQUIRE(sizes[3].value.FLOAT == 3.0f);
1219+
1220+ // Layout Keywords (Matched via kMatch map)
1221+ REQUIRE(getUnit(&s, "baseline")[0].type == UnitType::FIRST_BASELINE);
1222+ REQUIRE(getUnit(&s, "space-between")[0].type == UnitType::BETWEEN);
1223+ REQUIRE(getUnit(&s, "flex-start")[0].type == UnitType::FLEX_START);
1224+ REQUIRE(getUnit(&s, "border-box")[0].type == UnitType::BORDER);
1225+ REQUIRE(getUnit(&s, "none")[0].type == UnitType::NONE);
1226+ }
1227+
1228+ SECTION("4. Advanced Function Parsing (Calc & Nesting)") {
1229+ // Nested Math
1230+ auto t = getUnit(&s, "calc((10px + 5px) * 2)");
1231+ REQUIRE(t[0].type == UnitType::CALC);
1232+ // The parser handles parens by recursive calls to getUnit
1233+ // Verification depends on your kFunc and Unit structure
1234+
1235+ // Constants and Scientific Notation
1236+ auto math = getUnit(&s, "calc(pi * 1.2e3px - infinity)");
1237+ REQUIRE(math[1].type == UnitType::PI);
1238+ REQUIRE(math[2].type == UnitType::MULT);
1239+ REQUIRE(math[3].value.FLOAT == 1200.0f);
1240+ REQUIRE(math[5].type == UnitType::INF);
1241+ }
1242+
1243+ SECTION("5. String Handling and Escape Logic") {
1244+ // Quoted strings
1245+ auto strTest = getUnit(&s, "\"Comic Sans\" 'Single Quote'");
1246+ REQUIRE(strTest[0].type == UnitType::STRING);
1247+ REQUIRE(s.strings[strTest[0].value.INT] == "Comic Sans");
1248+ REQUIRE(s.strings[strTest[1].value.INT] == "Single Quote");
1249+
1250+ // Escaped Characters (Verifying the escaped boolean logic)
1251+ // Note: Your parser uses 'escaped' for quotes and special chars
1252+ auto escaped = getUnit(&s, "\"String with \\\"quote\\\" inside\"");
1253+ REQUIRE(s.strings.back() == "String with \\\"quote\\\" inside");
1254+ }
1255+
1256+ SECTION("6. IndexedMap Variable Integration") {
1257+ // When a word isn't recognized, it becomes a VAR and is stored in s->variables
1258+ auto var1 = getUnit(&s, "my-variable");
1259+ REQUIRE(var1[0].type == UnitType::VAR);
1260+ size_t idx = var1[0].value.INT;
1261+ REQUIRE(s.variables.map[idx].first == "my-variable");
1262+
1263+ // Set the same variable again, ensure it returns the same index (via s->variables.set logic)
1264+ auto var2 = getUnit(&s, "my-variable");
1265+ REQUIRE(var2[0].value.INT == idx);
1266+ REQUIRE(s.variables.map.size() == 1); // Should not have duplicated
1267+ }
1268+
1269+ SECTION("7. Whitespace and Delimiter Robustness") {
1270+ // Mixed delimiters: tabs, multiple spaces, commas, newlines
1271+ auto multi = getUnit(&s, "10px, 20px\t\n30px");
1272+ REQUIRE(multi.size() == 3);
1273+ REQUIRE(multi[0].value.FLOAT == 10.0f);
1274+ REQUIRE(multi[1].value.FLOAT == 20.0f);
1275+ REQUIRE(multi[2].value.FLOAT == 30.0f);
1276+
1277+ // Empty/Edge cases
1278+ auto empty = getUnit(&s, " ");
1279+ REQUIRE(empty.empty());
1280+ }
1281+
1282+ SECTION("8. Display and Internal Table Keywords") {
1283+ // Comprehensive check of the display-inside/internal/legacy units
1284+ std::vector<std::pair<std::string, UnitType>> displayTests = {
1285+ {"flow-root", UnitType::FLOW_ROOT},
1286+ {"inline-flex", UnitType::INLINE_FLEX},
1287+ {"table-caption", UnitType::TABLE_CAPTION},
1288+ {"ruby-text-container", UnitType::RUBY_TEXT_CONTAINER},
1289+ {"run-in", UnitType::RUN_IN}
1290+ };
1291+
1292+ for (const auto& [str, type] : displayTests) {
1293+ REQUIRE(getUnit(&s, str)[0].type == type);
1294+ }
1295+ }
1296 }
1297-
1298-/*
1299-TEST_CASE("BENCHMARKS") {
1300-BENCHMARK("number") {
1301- std::vector<Unit> t = getUnit("10");
1302-// std::cout << sizeof(t) << std::endl;
1303- std::cout << sizeof(t[0].type) << std::endl;
1304-};
1305-BENCHMARK("calc") {
1306- std::vector<Unit> t = getUnit("calc(10 + 100%)");
1307-// std::cout << sizeof(t) << std::endl;
1308-};
1309-}*/