Line data Source code
1 : // Copyright (c) 2015-2022 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/csspp
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : /** \file
21 : * \brief Test the color.cpp file.
22 : *
23 : * This test runs a battery of tests agains the color.cpp
24 : * implementation to ensure full coverage.
25 : */
26 :
27 : // csspp
28 : //
29 : #include <csspp/color.h>
30 :
31 : #include <csspp/exception.h>
32 : #include <csspp/lexer.h>
33 :
34 :
35 : // self
36 : //
37 : #include "catch_main.h"
38 :
39 :
40 : // C++
41 : //
42 : #include <iomanip>
43 : #include <sstream>
44 :
45 :
46 : // C
47 : //
48 : #include <math.h>
49 : #include <string.h>
50 :
51 :
52 : // last include
53 : //
54 : #include <snapdev/poison.h>
55 :
56 :
57 :
58 : namespace
59 : {
60 :
61 : char const test_colors[] =
62 : "aliceblue #f0f8ff 240,248,255\n"
63 : "antiquewhite #faebd7 250,235,215\n"
64 : "aqua #00ffff 0,255,255\n"
65 : "aquamarine #7fffd4 127,255,212\n"
66 : "azure #f0ffff 240,255,255\n"
67 : "beige #f5f5dc 245,245,220\n"
68 : "bisque #ffe4c4 255,228,196\n"
69 : "black #000000 0,0,0\n"
70 : "blanchedalmond #ffebcd 255,235,205\n"
71 : "blue #0000ff 0,0,255\n"
72 : "blueviolet #8a2be2 138,43,226\n"
73 : "brown #a52a2a 165,42,42\n"
74 : "burlywood #deb887 222,184,135\n"
75 : "cadetblue #5f9ea0 95,158,160\n"
76 : "chartreuse #7fff00 127,255,0\n"
77 : "chocolate #d2691e 210,105,30\n"
78 : "coral #ff7f50 255,127,80\n"
79 : "cornflowerblue #6495ed 100,149,237\n"
80 : "cornsilk #fff8dc 255,248,220\n"
81 : "crimson #dc143c 220,20,60\n"
82 : "cyan #00ffff 0,255,255\n"
83 : "darkblue #00008b 0,0,139\n"
84 : "darkcyan #008b8b 0,139,139\n"
85 : "darkgoldenrod #b8860b 184,134,11\n"
86 : "darkgray #a9a9a9 169,169,169\n"
87 : "darkgreen #006400 0,100,0\n"
88 : "darkgrey #a9a9a9 169,169,169\n"
89 : "darkkhaki #bdb76b 189,183,107\n"
90 : "darkmagenta #8b008b 139,0,139\n"
91 : "darkolivegreen #556b2f 85,107,47\n"
92 : "darkorange #ff8c00 255,140,0\n"
93 : "darkorchid #9932cc 153,50,204\n"
94 : "darkred #8b0000 139,0,0\n"
95 : "darksalmon #e9967a 233,150,122\n"
96 : "darkseagreen #8fbc8f 143,188,143\n"
97 : "darkslateblue #483d8b 72,61,139\n"
98 : "darkslategray #2f4f4f 47,79,79\n"
99 : "darkslategrey #2f4f4f 47,79,79\n"
100 : "darkturquoise #00ced1 0,206,209\n"
101 : "darkviolet #9400d3 148,0,211\n"
102 : "deeppink #ff1493 255,20,147\n"
103 : "deepskyblue #00bfff 0,191,255\n"
104 : "dimgray #696969 105,105,105\n"
105 : "dimgrey #696969 105,105,105\n"
106 : "dodgerblue #1e90ff 30,144,255\n"
107 : "firebrick #b22222 178,34,34\n"
108 : "floralwhite #fffaf0 255,250,240\n"
109 : "forestgreen #228b22 34,139,34\n"
110 : "fuchsia #ff00ff 255,0,255\n"
111 : "gainsboro #dcdcdc 220,220,220\n"
112 : "ghostwhite #f8f8ff 248,248,255\n"
113 : "gold #ffd700 255,215,0\n"
114 : "goldenrod #daa520 218,165,32\n"
115 : "gray #808080 128,128,128\n"
116 : "green #008000 0,128,0\n"
117 : "greenyellow #adff2f 173,255,47\n"
118 : "grey #808080 128,128,128\n"
119 : "honeydew #f0fff0 240,255,240\n"
120 : "hotpink #ff69b4 255,105,180\n"
121 : "indianred #cd5c5c 205,92,92\n"
122 : "indigo #4b0082 75,0,130\n"
123 : "ivory #fffff0 255,255,240\n"
124 : "khaki #f0e68c 240,230,140\n"
125 : "lavender #e6e6fa 230,230,250\n"
126 : "lavenderblush #fff0f5 255,240,245\n"
127 : "lawngreen #7cfc00 124,252,0\n"
128 : "lemonchiffon #fffacd 255,250,205\n"
129 : "lightblue #add8e6 173,216,230\n"
130 : "lightcoral #f08080 240,128,128\n"
131 : "lightcyan #e0ffff 224,255,255\n"
132 : "lightgoldenrodyellow #fafad2 250,250,210\n"
133 : "lightgray #d3d3d3 211,211,211\n"
134 : "lightgreen #90ee90 144,238,144\n"
135 : "lightgrey #d3d3d3 211,211,211\n"
136 : "lightpink #ffb6c1 255,182,193\n"
137 : "lightsalmon #ffa07a 255,160,122\n"
138 : "lightseagreen #20b2aa 32,178,170\n"
139 : "lightskyblue #87cefa 135,206,250\n"
140 : "lightslategray #778899 119,136,153\n"
141 : "lightslategrey #778899 119,136,153\n"
142 : "lightsteelblue #b0c4de 176,196,222\n"
143 : "lightyellow #ffffe0 255,255,224\n"
144 : "lime #00ff00 0,255,0\n"
145 : "limegreen #32cd32 50,205,50\n"
146 : "linen #faf0e6 250,240,230\n"
147 : "magenta #ff00ff 255,0,255\n"
148 : "maroon #800000 128,0,0\n"
149 : "mediumaquamarine #66cdaa 102,205,170\n"
150 : "mediumblue #0000cd 0,0,205\n"
151 : "mediumorchid #ba55d3 186,85,211\n"
152 : "mediumpurple #9370db 147,112,219\n"
153 : "mediumseagreen #3cb371 60,179,113\n"
154 : "mediumslateblue #7b68ee 123,104,238\n"
155 : "mediumspringgreen #00fa9a 0,250,154\n"
156 : "mediumturquoise #48d1cc 72,209,204\n"
157 : "mediumvioletred #c71585 199,21,133\n"
158 : "midnightblue #191970 25,25,112\n"
159 : "mintcream #f5fffa 245,255,250\n"
160 : "mistyrose #ffe4e1 255,228,225\n"
161 : "moccasin #ffe4b5 255,228,181\n"
162 : "navajowhite #ffdead 255,222,173\n"
163 : "navy #000080 0,0,128\n"
164 : "oldlace #fdf5e6 253,245,230\n"
165 : "olive #808000 128,128,0\n"
166 : "olivedrab #6b8e23 107,142,35\n"
167 : "orange #ffa500 255,165,0\n"
168 : "orangered #ff4500 255,69,0\n"
169 : "orchid #da70d6 218,112,214\n"
170 : "palegoldenrod #eee8aa 238,232,170\n"
171 : "palegreen #98fb98 152,251,152\n"
172 : "paleturquoise #afeeee 175,238,238\n"
173 : "palevioletred #db7093 219,112,147\n"
174 : "papayawhip #ffefd5 255,239,213\n"
175 : "peachpuff #ffdab9 255,218,185\n"
176 : "peru #cd853f 205,133,63\n"
177 : "pink #ffc0cb 255,192,203\n"
178 : "plum #dda0dd 221,160,221\n"
179 : "powderblue #b0e0e6 176,224,230\n"
180 : "purple #800080 128,0,128\n"
181 : "red #ff0000 255,0,0\n"
182 : "rosybrown #bc8f8f 188,143,143\n"
183 : "royalblue #4169e1 65,105,225\n"
184 : "saddlebrown #8b4513 139,69,19\n"
185 : "salmon #fa8072 250,128,114\n"
186 : "sandybrown #f4a460 244,164,96\n"
187 : "seagreen #2e8b57 46,139,87\n"
188 : "seashell #fff5ee 255,245,238\n"
189 : "sienna #a0522d 160,82,45\n"
190 : "silver #c0c0c0 192,192,192\n"
191 : "skyblue #87ceeb 135,206,235\n"
192 : "slateblue #6a5acd 106,90,205\n"
193 : "slategray #708090 112,128,144\n"
194 : "slategrey #708090 112,128,144\n"
195 : "snow #fffafa 255,250,250\n"
196 : "springgreen #00ff7f 0,255,127\n"
197 : "steelblue #4682b4 70,130,180\n"
198 : "tan #d2b48c 210,180,140\n"
199 : "teal #008080 0,128,128\n"
200 : "thistle #d8bfd8 216,191,216\n"
201 : "tomato #ff6347 255,99,71\n"
202 : "turquoise #40e0d0 64,224,208\n"
203 : "violet #ee82ee 238,130,238\n"
204 : "wheat #f5deb3 245,222,179\n"
205 : "white #ffffff 255,255,255\n"
206 : "whitesmoke #f5f5f5 245,245,245\n"
207 : "yellow #ffff00 255,255,0\n"
208 : "yellowgreen #9acd32 154,205,50\n"
209 : ;
210 :
211 : } // no name namespace
212 :
213 :
214 1 : CATCH_TEST_CASE("Invalid colors", "[color] [invalid]")
215 : {
216 1 : csspp::color c;
217 :
218 1 : CATCH_REQUIRE(!c.set_color("", false));
219 1 : CATCH_REQUIRE(!c.set_color("1", false));
220 1 : CATCH_REQUIRE(!c.set_color("12", false));
221 1 : CATCH_REQUIRE(!c.set_color("1234", false));
222 1 : CATCH_REQUIRE(!c.set_color("12345", false));
223 1 : CATCH_REQUIRE(!c.set_color("1234567", false));
224 1 : CATCH_REQUIRE(!c.set_color("12345G", false));
225 1 : CATCH_REQUIRE(!c.set_color("/01234", false));
226 1 : CATCH_REQUIRE(!c.set_color("/05", false));
227 1 : CATCH_REQUIRE(!c.set_color("44G", false));
228 1 : CATCH_REQUIRE(!c.set_color("#333", false));
229 1 : CATCH_REQUIRE(!c.set_color("unknown", false));
230 :
231 1 : CATCH_REQUIRE(!c.set_color("", true));
232 1 : CATCH_REQUIRE(!c.set_color("1", true));
233 1 : CATCH_REQUIRE(!c.set_color("12", true));
234 1 : CATCH_REQUIRE(!c.set_color("123", true)); // this would work with false
235 1 : CATCH_REQUIRE(!c.set_color("1234", true));
236 1 : CATCH_REQUIRE(!c.set_color("12345", true));
237 1 : CATCH_REQUIRE(!c.set_color("123456", true)); // this would work with false
238 1 : CATCH_REQUIRE(!c.set_color("1234567", true));
239 1 : CATCH_REQUIRE(!c.set_color("12345G", true));
240 1 : CATCH_REQUIRE(!c.set_color("/01234", true));
241 1 : CATCH_REQUIRE(!c.set_color("/05", true));
242 1 : CATCH_REQUIRE(!c.set_color("44G", true));
243 1 : CATCH_REQUIRE(!c.set_color("#333", true));
244 1 : CATCH_REQUIRE(!c.set_color("unknown", true));
245 1 : }
246 :
247 1 : CATCH_TEST_CASE("Default color", "[color] [default]")
248 : {
249 1 : csspp::color c;
250 1 : CATCH_REQUIRE(c.get_color() == 0xFF000000U);
251 :
252 1 : csspp::color_component_t cr;
253 1 : csspp::color_component_t cg;
254 1 : csspp::color_component_t cb;
255 1 : csspp::color_component_t ca;
256 1 : c.get_color(cr, cg, cb, ca);
257 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(cr, 0.0f, 0.0f));
258 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(cg, 0.0f, 0.0f));
259 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(cb, 0.0f, 0.0f));
260 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(ca, 1.0f, 0.0f));
261 1 : }
262 :
263 1 : CATCH_TEST_CASE("Verify #XXX colors", "[color] [parse]")
264 : {
265 4097 : for(int i(0); i < 0x1000; ++i)
266 : {
267 4096 : csspp::byte_component_t const r((i >> 0) & 15);
268 4096 : csspp::byte_component_t const g((i >> 4) & 15);
269 4096 : csspp::byte_component_t const b((i >> 8) & 15);
270 :
271 4096 : std::stringstream ss;
272 4096 : ss << std::hex << static_cast<int>(r) << static_cast<int>(g) << static_cast<int>(b);
273 :
274 4096 : csspp::color c;
275 4096 : CATCH_REQUIRE(c.set_color(ss.str(), false));
276 :
277 4096 : CATCH_REQUIRE(c.get_color() == (r * 0x11) + (g * 0x1100) + (b * 0x110000) + 0xFF000000);
278 4096 : CATCH_REQUIRE(c.is_solid());
279 4096 : CATCH_REQUIRE(!c.is_transparent());
280 :
281 4096 : csspp::color_component_t cr;
282 4096 : csspp::color_component_t cg;
283 4096 : csspp::color_component_t cb;
284 4096 : csspp::color_component_t ca;
285 4096 : c.get_color(cr, cg, cb, ca);
286 4096 : CATCH_REQUIRE((fabs(cr - (r * 0x11U) / 255.0) < 0.0001));
287 4096 : CATCH_REQUIRE((fabs(cg - (g * 0x11U) / 255.0) < 0.0001));
288 4096 : CATCH_REQUIRE((fabs(cb - (b * 0x11U) / 255.0) < 0.0001));
289 4096 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(ca, 1.0f, 0.0f));
290 4096 : }
291 1 : }
292 :
293 1 : CATCH_TEST_CASE("Verify #XXXXXX colors", "[color] [parse]")
294 : {
295 16731 : for(int i(0); i < 0x1000000; i += rand() % 2000 + 1)
296 : {
297 16730 : csspp::byte_component_t const r((i >> 0) & 255);
298 16730 : csspp::byte_component_t const g((i >> 8) & 255);
299 16730 : csspp::byte_component_t const b((i >> 16) & 255);
300 :
301 16730 : std::stringstream ss;
302 16730 : ss << std::hex << std::setfill('0')
303 16730 : << std::setw(2) << static_cast<int>(r)
304 16730 : << std::setw(2) << static_cast<int>(g)
305 16730 : << std::setw(2) << static_cast<int>(b);
306 :
307 16730 : csspp::color c;
308 16730 : CATCH_REQUIRE(c.set_color(ss.str(), false));
309 :
310 16730 : CATCH_REQUIRE(c.get_color() == (r * 0x1) + (g * 0x100) + (b * 0x10000) + 0xFF000000);
311 16730 : CATCH_REQUIRE(c.is_solid());
312 16730 : CATCH_REQUIRE(!c.is_transparent());
313 :
314 16730 : csspp::color_component_t cr;
315 16730 : csspp::color_component_t cg;
316 16730 : csspp::color_component_t cb;
317 16730 : csspp::color_component_t ca;
318 16730 : c.get_color(cr, cg, cb, ca);
319 16730 : CATCH_REQUIRE((fabs(cr - r / 255.0) < 0.0001));
320 16730 : CATCH_REQUIRE((fabs(cg - g / 255.0) < 0.0001));
321 16730 : CATCH_REQUIRE((fabs(cb - b / 255.0) < 0.0001));
322 16730 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(ca, 1.0f, 0.0f));
323 16730 : }
324 1 : }
325 :
326 1 : CATCH_TEST_CASE("Verify named colors", "[color] [parse]")
327 : {
328 : // we got raw data here, parse it and make sure it is equal to
329 : // what our library produces
330 1 : const char *s(test_colors);
331 148 : while(*s != '\0')
332 : {
333 147 : std::string name;
334 147 : std::string hash;
335 :
336 : // read the name
337 1456 : for(; *s != ' '; ++s)
338 : {
339 1309 : name += *s;
340 : }
341 :
342 : // skip the spaces
343 441 : for(; *s == ' '; ++s);
344 :
345 : // read the hash
346 147 : CATCH_REQUIRE(*s == '#');
347 : // we do ++s at the start to skip the '#'
348 1029 : for(++s; *s != ' '; ++s)
349 : {
350 882 : hash += *s;
351 : }
352 :
353 : // covert the hash to a color
354 147 : csspp::byte_component_t const r(csspp::lexer::hex_to_dec(hash[0]) * 16 + csspp::lexer::hex_to_dec(hash[1]));
355 147 : csspp::byte_component_t const g(csspp::lexer::hex_to_dec(hash[2]) * 16 + csspp::lexer::hex_to_dec(hash[3]));
356 147 : csspp::byte_component_t const b(csspp::lexer::hex_to_dec(hash[4]) * 16 + csspp::lexer::hex_to_dec(hash[5]));
357 :
358 : // skip to the next line (or EOS)
359 1911 : for(; *s != '\n'; ++s);
360 147 : ++s; // skip the '\n'
361 :
362 147 : csspp::color c;
363 147 : CATCH_REQUIRE(c.set_color(name, false));
364 147 : CATCH_REQUIRE(c.is_solid());
365 147 : CATCH_REQUIRE(!c.is_transparent());
366 147 : CATCH_REQUIRE(c.get_color() == (r << 0) + (g << 8) + (b << 16) + 0xFF000000);
367 :
368 147 : csspp::color_component_t cr;
369 147 : csspp::color_component_t cg;
370 147 : csspp::color_component_t cb;
371 147 : csspp::color_component_t ca;
372 147 : c.get_color(cr, cg, cb, ca);
373 147 : CATCH_REQUIRE((fabs(cr - r / 255.0) < 0.0001));
374 147 : CATCH_REQUIRE((fabs(cg - g / 255.0) < 0.0001));
375 147 : CATCH_REQUIRE((fabs(cb - b / 255.0) < 0.0001));
376 147 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(ca, 1.0f, 0.0f));
377 147 : }
378 :
379 : // verify the transparent color
380 : {
381 1 : csspp::color c;
382 1 : CATCH_REQUIRE(c.set_color("transparent", false));
383 1 : CATCH_REQUIRE(!c.is_solid());
384 1 : CATCH_REQUIRE(c.is_transparent());
385 1 : CATCH_REQUIRE(c.get_color() == 0);
386 :
387 1 : csspp::color_component_t cr;
388 1 : csspp::color_component_t cg;
389 1 : csspp::color_component_t cb;
390 1 : csspp::color_component_t ca;
391 1 : c.get_color(cr, cg, cb, ca);
392 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(cr, 0.0f, 0.0f));
393 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(cg, 0.0f, 0.0f));
394 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(cb, 0.0f, 0.0f));
395 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(ca, 0.0f, 0.0f));
396 : }
397 1 : }
398 :
399 1 : CATCH_TEST_CASE("Direct colors", "[color]")
400 : {
401 1001 : for(int i(0); i < 1000; ++i)
402 : {
403 1000 : csspp::byte_component_t const r(rand() & 255);
404 1000 : csspp::byte_component_t const g(rand() & 255);
405 1000 : csspp::byte_component_t const b(rand() & 255);
406 1000 : csspp::byte_component_t const a(rand() & 255);
407 :
408 1000 : csspp::color c;
409 1000 : c.set_color(r, g, b, a);
410 1000 : CATCH_REQUIRE(c.get_color() == (r * 0x1U) + (g * 0x100U) + (b * 0x10000U) + (a * 0x1000000U));
411 :
412 1000 : if(a == 255U)
413 : {
414 7 : CATCH_REQUIRE(c.is_solid());
415 : }
416 : else
417 : {
418 993 : CATCH_REQUIRE(!c.is_solid());
419 : }
420 1000 : if(a == 0U)
421 : {
422 1 : CATCH_REQUIRE(c.is_transparent());
423 : }
424 : else
425 : {
426 999 : CATCH_REQUIRE(!c.is_transparent());
427 : }
428 :
429 1000 : csspp::color_component_t cr;
430 1000 : csspp::color_component_t cg;
431 1000 : csspp::color_component_t cb;
432 1000 : csspp::color_component_t ca;
433 1000 : c.get_color(cr, cg, cb, ca);
434 1000 : CATCH_REQUIRE((fabs(cr - r / 255.0) < 0.0001));
435 1000 : CATCH_REQUIRE((fabs(cg - g / 255.0) < 0.0001));
436 1000 : CATCH_REQUIRE((fabs(cb - b / 255.0) < 0.0001));
437 1000 : CATCH_REQUIRE((fabs(ca - a / 255.0) < 0.0001));
438 :
439 : // try again with one uint32_t value
440 1000 : c.set_color((r * 0x1U) + (g * 0x100U) + (b * 0x10000U) + (a * 0x1000000U));
441 1000 : CATCH_REQUIRE(c.get_color() == (r * 0x1U) + (g * 0x100U) + (b * 0x10000U) + (a * 0x1000000U));
442 :
443 1000 : if(a == 255U)
444 : {
445 7 : CATCH_REQUIRE(c.is_solid());
446 : }
447 : else
448 : {
449 993 : CATCH_REQUIRE(!c.is_solid());
450 : }
451 1000 : if(a == 0U)
452 : {
453 1 : CATCH_REQUIRE(c.is_transparent());
454 : }
455 : else
456 : {
457 999 : CATCH_REQUIRE(!c.is_transparent());
458 : }
459 :
460 1000 : c.get_color(cr, cg, cb, ca);
461 1000 : CATCH_REQUIRE((fabs(cr - r / 255.0) < 0.0001));
462 1000 : CATCH_REQUIRE((fabs(cg - g / 255.0) < 0.0001));
463 1000 : CATCH_REQUIRE((fabs(cb - b / 255.0) < 0.0001));
464 1000 : CATCH_REQUIRE((fabs(ca - a / 255.0) < 0.0001));
465 :
466 : // try again with component values
467 1000 : c.set_color(static_cast<csspp::color_component_t>(r / 255.0),
468 1000 : static_cast<csspp::color_component_t>(g / 255.0),
469 1000 : static_cast<csspp::color_component_t>(b / 255.0),
470 1000 : static_cast<csspp::color_component_t>(a / 255.0));
471 1000 : CATCH_REQUIRE(c.get_color() == (r * 0x1U) + (g * 0x100U) + (b * 0x10000U) + (a * 0x1000000U));
472 :
473 1000 : if(a == 255U)
474 : {
475 7 : CATCH_REQUIRE(c.is_solid());
476 : }
477 : else
478 : {
479 993 : CATCH_REQUIRE(!c.is_solid());
480 : }
481 1000 : if(a == 0U)
482 : {
483 1 : CATCH_REQUIRE(c.is_transparent());
484 : }
485 : else
486 : {
487 999 : CATCH_REQUIRE(!c.is_transparent());
488 : }
489 :
490 1000 : c.get_color(cr, cg, cb, ca);
491 1000 : CATCH_REQUIRE((fabs(cr - r / 255.0) < 0.0001));
492 1000 : CATCH_REQUIRE((fabs(cg - g / 255.0) < 0.0001));
493 1000 : CATCH_REQUIRE((fabs(cb - b / 255.0) < 0.0001));
494 1000 : CATCH_REQUIRE((fabs(ca - a / 255.0) < 0.0001));
495 :
496 : // try again with doubles
497 1000 : c.set_color(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
498 1000 : CATCH_REQUIRE(c.get_color() == (r * 0x1U) + (g * 0x100U) + (b * 0x10000U) + (a * 0x1000000U));
499 :
500 1000 : if(a == 255U)
501 : {
502 7 : CATCH_REQUIRE(c.is_solid());
503 : }
504 : else
505 : {
506 993 : CATCH_REQUIRE(!c.is_solid());
507 : }
508 1000 : if(a == 0U)
509 : {
510 1 : CATCH_REQUIRE(c.is_transparent());
511 : }
512 : else
513 : {
514 999 : CATCH_REQUIRE(!c.is_transparent());
515 : }
516 :
517 1000 : c.get_color(cr, cg, cb, ca);
518 1000 : CATCH_REQUIRE((fabs(cr - r / 255.0) < 0.0001));
519 1000 : CATCH_REQUIRE((fabs(cg - g / 255.0) < 0.0001));
520 1000 : CATCH_REQUIRE((fabs(cb - b / 255.0) < 0.0001));
521 1000 : CATCH_REQUIRE((fabs(ca - a / 255.0) < 0.0001));
522 :
523 : // make sure no clamping happens on the floating point numbers
524 1000 : c.set_color(r / -255.0, g + 265.0, b / 255.0, a / 255.0);
525 1000 : CATCH_REQUIRE(c.get_color() == (0 * 0x1U) + (0xFF00U) + (b * 0x10000U) + (a * 0x1000000U));
526 :
527 1000 : if(a == 255U)
528 : {
529 7 : CATCH_REQUIRE(c.is_solid());
530 : }
531 : else
532 : {
533 993 : CATCH_REQUIRE(!c.is_solid());
534 : }
535 1000 : if(a == 0U)
536 : {
537 1 : CATCH_REQUIRE(c.is_transparent());
538 : }
539 : else
540 : {
541 999 : CATCH_REQUIRE(!c.is_transparent());
542 : }
543 :
544 1000 : c.get_color(cr, cg, cb, ca);
545 1000 : CATCH_REQUIRE((fabs(cr - r / -255.0) < 0.0001));
546 1000 : CATCH_REQUIRE((fabs(cg - (g + 265.0)) < 0.0001));
547 1000 : CATCH_REQUIRE((fabs(cb - b / 255.0) < 0.0001));
548 1000 : CATCH_REQUIRE((fabs(ca - a / 255.0) < 0.0001));
549 : }
550 1 : }
551 :
552 1 : CATCH_TEST_CASE("HSLA colors", "[color]")
553 : {
554 1 : csspp::color c;
555 :
556 : // red
557 1 : c.set_hsl(0.0 * M_PI / 180.0, 1.0, 0.5, 1.0);
558 1 : CATCH_REQUIRE(c.get_color() == 0xFF0000FFU);
559 :
560 : // lime
561 1 : c.set_hsl(120.0 * M_PI / 180.0, 1.0, 0.5, 1.0);
562 1 : CATCH_REQUIRE(c.get_color() == 0xFF00FF00U);
563 :
564 : // darkgreen
565 1 : c.set_hsl(120.0 * M_PI / 180.0, 1.0, 0.25, 1.0);
566 1 : CATCH_REQUIRE(c.get_color() == 0xFF008000U);
567 :
568 : // lightgreen
569 1 : c.set_hsl(120.0 * M_PI / 180.0, 1.0, 0.75, 1.0);
570 1 : CATCH_REQUIRE(c.get_color() == 0xFF80FF80U);
571 :
572 : // blue
573 1 : c.set_hsl(120.0 * M_PI / 180.0, 1.0, 0.5, 0.5);
574 1 : CATCH_REQUIRE(c.get_color() == 0x8000FF00U);
575 :
576 : // orange
577 1 : c.set_hsl(30.0 * M_PI / 180.0, 1.0, 0.5, 0.5);
578 1 : CATCH_REQUIRE(c.get_color() == 0x800080FFU);
579 :
580 101 : for(int i(0); i < 100; ++i)
581 : {
582 : // black
583 100 : c.set_hsl(rand() % 3600 * M_PI / 180.0, 0.0, 0.0, 0.5);
584 100 : CATCH_REQUIRE(c.get_color() == 0x80000000U);
585 :
586 : // white
587 100 : c.set_hsl(rand() % 3600 * M_PI / 180.0, 0.0, 1.0, 0.5);
588 100 : CATCH_REQUIRE(c.get_color() == 0x80FFFFFFU);
589 :
590 : // gray
591 100 : c.set_hsl(rand() % 3600 * M_PI / 180.0, 0.0, 0.5, 0.5);
592 100 : CATCH_REQUIRE(c.get_color() == 0x80808080U);
593 : }
594 :
595 : // ...
596 1 : c.set_hsl(61.8 * M_PI / 180.0, 0.638, 0.393, 0.25);
597 1 : CATCH_REQUIRE(c.get_color() == 0x4024A4A0U);
598 :
599 : // ...
600 1 : c.set_hsl(162.4 * M_PI / 180.0, 0.779, 0.447, 0.25);
601 1 : CATCH_REQUIRE(c.get_color() == 0x4097CB19U);
602 :
603 : // ...
604 1 : c.set_hsl(180.0 * M_PI / 180.0, 1.0, 0.75, 0.75);
605 1 : CATCH_REQUIRE(c.get_color() == 0xBFFFFF80U);
606 :
607 : // ...
608 1 : c.set_hsl(251.1 * M_PI / 180.0, 0.832, 0.511, 0.75);
609 1 : CATCH_REQUIRE(c.get_color() == 0xBFEA1B41U);
610 :
611 : // ...
612 : // helper computation to make sure the assembler tests work as expected
613 1 : c.set_color(0xf7, 0xd0, 0xcf, 0xff);
614 : {
615 1 : csspp::color_component_t hue;
616 1 : csspp::color_component_t saturation;
617 1 : csspp::color_component_t lightness;
618 1 : csspp::color_component_t alpha;
619 1 : c.get_hsl(hue, saturation, lightness, alpha);
620 :
621 : // add 180deg to the hue
622 1 : c.set_hsl(hue + M_PI, saturation, lightness, alpha);
623 1 : CATCH_REQUIRE(c.get_color() == 0xFFF7F6CFU);
624 :
625 : // darken by 3%
626 1 : c.set_hsl(hue, saturation, lightness - 0.03, alpha);
627 1 : CATCH_REQUIRE(c.get_color() == 0xFFC2C3F5U);
628 :
629 : // desaturate by 5%
630 1 : c.set_hsl(hue, saturation - 0.05, lightness, alpha);
631 1 : CATCH_REQUIRE(c.get_color() == 0xFFD0D1F6U);
632 : }
633 :
634 : // ...
635 : // helper computation to make sure the unary expression tests work as expected
636 1 : c.set_color(0x56, 0xaf, 0x9b, 0xff);
637 : {
638 1 : csspp::color_component_t hue;
639 1 : csspp::color_component_t saturation;
640 1 : csspp::color_component_t lightness;
641 1 : csspp::color_component_t alpha;
642 1 : c.get_hsl(hue, saturation, lightness, alpha);
643 :
644 : // add 180deg to the hue
645 1 : c.set_hsl(hue + M_PI, saturation, lightness, alpha);
646 1 : CATCH_REQUIRE(c.get_color() == 0xFF6A56AFU);
647 : }
648 :
649 : // ...
650 1 : c.set_hsl(-251.1 * M_PI / 180.0, 0.832, 0.511, 0.75);
651 1 : CATCH_REQUIRE(c.get_color() == 0xBF1B1B1BU);
652 : {
653 1 : csspp::color_component_t hue;
654 1 : csspp::color_component_t saturation;
655 1 : csspp::color_component_t lightness;
656 1 : csspp::color_component_t alpha;
657 1 : c.get_hsl(hue, saturation, lightness, alpha);
658 : }
659 :
660 20001 : for(int i(0); i < 20000; ++i)
661 : {
662 : int red;
663 : int green;
664 : int blue;
665 20000 : int alpha(rand() & 255);
666 : // to make sure we hit all the lines we check the get_hsl()
667 : // with a few specific colors
668 20000 : switch(i)
669 : {
670 1 : case 0:
671 : // check black
672 1 : red = 0;
673 1 : green = 0;
674 1 : blue = 0;
675 1 : break;
676 :
677 1 : case 1:
678 : // check white
679 1 : red = 255;
680 1 : green = 255;
681 1 : blue = 255;
682 1 : break;
683 :
684 1 : case 2:
685 : // check red
686 1 : red = 255;
687 1 : green = 0;
688 1 : blue = 0;
689 1 : break;
690 :
691 1 : case 3:
692 : // check green
693 1 : red = 0;
694 1 : green = 255;
695 1 : blue = 0;
696 1 : break;
697 :
698 1 : case 4:
699 : // check blue
700 1 : red = 0;
701 1 : green = 0;
702 1 : blue = 255;
703 1 : break;
704 :
705 1 : case 5:
706 : // check gray
707 1 : red = 128;
708 1 : green = 128;
709 1 : blue = 128;
710 1 : break;
711 :
712 19994 : default:
713 19994 : red = rand() & 255;
714 19994 : green = rand() & 255;
715 19994 : blue = rand() & 255;
716 19994 : break;
717 :
718 : }
719 20000 : c.set_color(red, green, blue, alpha);
720 :
721 20000 : csspp::color_component_t hue;
722 20000 : csspp::color_component_t saturation;
723 20000 : csspp::color_component_t lightness;
724 20000 : csspp::color_component_t hsl_alpha;
725 20000 : c.get_hsl(hue, saturation, lightness, hsl_alpha);
726 20000 : CATCH_REQUIRE(fabs(hsl_alpha - alpha / 255.0) < 0.00001);
727 :
728 : // setting those values back must resolve to the
729 : // exact same RGBA as what we defined earlier
730 20000 : c.set_hsl(hue, saturation, lightness, hsl_alpha);
731 :
732 20000 : csspp::rgba_color_t col(c.get_color());
733 20000 : csspp::byte_component_t r((col >> 0) & 255);
734 20000 : csspp::byte_component_t g((col >> 8) & 255);
735 20000 : csspp::byte_component_t b((col >> 16) & 255);
736 20000 : csspp::byte_component_t a((col >> 24) & 255);
737 20000 : CATCH_REQUIRE(r == red );
738 20000 : CATCH_REQUIRE(g == green);
739 20000 : CATCH_REQUIRE(b == blue );
740 20000 : CATCH_REQUIRE(a == alpha);
741 :
742 : // if(red - green >= 10
743 : // || red - blue >= 10
744 : // || green - blue >= 10)
745 : // {
746 : // c.adjust_hue(180.0);// * M_PI / 180.0);
747 : // csspp::color_component_t new_hue;
748 : // csspp::color_component_t new_saturation;
749 : // csspp::color_component_t new_lightness;
750 : // c.get_hsl(new_hue, new_saturation, new_lightness, hsl_alpha);
751 : // CATCH_REQUIRE(fabs(hsl_alpha - alpha / 255.0) < 0.00001);
752 : //
753 : // // hue is not considered valid when RGB are equal
754 : // double hue_diff(fabs(fabs(hue - new_hue) - 180.0));
755 : ////if(hue_diff > 3.0)
756 : ////{
757 : ////std::cerr << "rgb: " << static_cast<int>(r) << ", " << static_cast<int>(g) << ", " << static_cast<int>(b)
758 : //// << " old hue: " << hue << " & new hue: " << new_hue << " diff = " << fabs(new_hue - hue) << " delta " << fabs(fabs(new_hue - hue) - 180.0) << "\n";
759 : ////}
760 : // CATCH_REQUIRE(hue_diff <= 0.0001);
761 : //
762 : // // restore the color to test the adjust_hue() function
763 : // c.set_hsl(hue, saturation, lightness, hsl_alpha);
764 : // c.adjust_saturation(0.2); // +20%
765 : // c.get_hsl(new_hue, new_saturation, new_lightness, hsl_alpha);
766 : // double saturation_diff(fabs(fabs(saturation - new_saturation) - 0.2));
767 : ////if(saturation_diff > 0.0001)
768 : ////{
769 : ////std::cerr << "old saturation: " << saturation << " -> " << new_saturation << " diff = " << fabs(new_saturation - saturation) << "\n";
770 : ////}
771 : // CATCH_REQUIRE(saturation_diff < 0.0001);
772 : //
773 : // // restore the color to test the adjust_lightness() function
774 : // c.set_hsl(hue, saturation, lightness, hsl_alpha);
775 : // c.adjust_lightness(0.2); // +20%
776 : // c.get_hsl(new_hue, new_saturation, new_lightness, hsl_alpha);
777 : // double lightness_diff(fabs(fabs(lightness - new_lightness) - 0.2));
778 : ////if(lightness_diff > 0.0001)
779 : ////{
780 : ////std::cerr << "old lightness: " << lightness << " -> " << new_lightness << " diff = " << fabs(new_lightness - lightness) << "\n";
781 : ////}
782 : // CATCH_REQUIRE(lightness_diff < 0.0001);
783 : // }
784 : }
785 1 : }
786 :
787 1 : CATCH_TEST_CASE("Color to string", "[color] [output]")
788 : {
789 1 : csspp::color c;
790 :
791 : // a few special cases
792 : {
793 1 : c.set_color(static_cast<csspp::byte_component_t>(0xC0),
794 : static_cast<csspp::byte_component_t>(0xC0),
795 : static_cast<csspp::byte_component_t>(0xC0),
796 : static_cast<csspp::byte_component_t>(0xFF));
797 1 : CATCH_REQUIRE(c.to_string() == "silver");
798 :
799 1 : c.set_color(static_cast<csspp::byte_component_t>(0x80),
800 : static_cast<csspp::byte_component_t>(0x80),
801 : static_cast<csspp::byte_component_t>(0x80),
802 : static_cast<csspp::byte_component_t>(0xFF));
803 1 : CATCH_REQUIRE(c.to_string() == "gray");
804 :
805 1 : c.set_color(static_cast<csspp::byte_component_t>(0x80),
806 : static_cast<csspp::byte_component_t>(0x00),
807 : static_cast<csspp::byte_component_t>(0x00),
808 : static_cast<csspp::byte_component_t>(0xFF));
809 1 : CATCH_REQUIRE(c.to_string() == "maroon");
810 :
811 1 : c.set_color(static_cast<csspp::byte_component_t>(0xFF),
812 : static_cast<csspp::byte_component_t>(0x00),
813 : static_cast<csspp::byte_component_t>(0x00),
814 : static_cast<csspp::byte_component_t>(0xFF));
815 1 : CATCH_REQUIRE(c.to_string() == "red");
816 :
817 1 : c.set_color(static_cast<csspp::byte_component_t>(0x80),
818 : static_cast<csspp::byte_component_t>(0x00),
819 : static_cast<csspp::byte_component_t>(0x80),
820 : static_cast<csspp::byte_component_t>(0xFF));
821 1 : CATCH_REQUIRE(c.to_string() == "purple");
822 :
823 1 : c.set_color(static_cast<csspp::byte_component_t>(0x00),
824 : static_cast<csspp::byte_component_t>(0x80),
825 : static_cast<csspp::byte_component_t>(0x00),
826 : static_cast<csspp::byte_component_t>(0xFF));
827 1 : CATCH_REQUIRE(c.to_string() == "green");
828 :
829 1 : c.set_color(static_cast<csspp::byte_component_t>(0x00),
830 : static_cast<csspp::byte_component_t>(0xFF),
831 : static_cast<csspp::byte_component_t>(0x00),
832 : static_cast<csspp::byte_component_t>(0xFF));
833 1 : CATCH_REQUIRE(c.to_string() == "lime");
834 :
835 1 : c.set_color(static_cast<csspp::byte_component_t>(0x80),
836 : static_cast<csspp::byte_component_t>(0x80),
837 : static_cast<csspp::byte_component_t>(0x00),
838 : static_cast<csspp::byte_component_t>(0xFF));
839 1 : CATCH_REQUIRE(c.to_string() == "olive");
840 :
841 1 : c.set_color(static_cast<csspp::byte_component_t>(0x00),
842 : static_cast<csspp::byte_component_t>(0x00),
843 : static_cast<csspp::byte_component_t>(0x80),
844 : static_cast<csspp::byte_component_t>(0xFF));
845 1 : CATCH_REQUIRE(c.to_string() == "navy");
846 :
847 1 : c.set_color(static_cast<csspp::byte_component_t>(0x00),
848 : static_cast<csspp::byte_component_t>(0x00),
849 : static_cast<csspp::byte_component_t>(0xFF),
850 : static_cast<csspp::byte_component_t>(0xFF));
851 1 : CATCH_REQUIRE(c.to_string() == "blue");
852 :
853 1 : c.set_color(static_cast<csspp::byte_component_t>(0x00),
854 : static_cast<csspp::byte_component_t>(0x80),
855 : static_cast<csspp::byte_component_t>(0x80),
856 : static_cast<csspp::byte_component_t>(0xFF));
857 1 : CATCH_REQUIRE(c.to_string() == "teal");
858 :
859 1 : c.set_color(static_cast<csspp::byte_component_t>(0x00),
860 : static_cast<csspp::byte_component_t>(0xFF),
861 : static_cast<csspp::byte_component_t>(0xFF),
862 : static_cast<csspp::byte_component_t>(0xFF));
863 1 : CATCH_REQUIRE(c.to_string() == "aqua");
864 : }
865 :
866 : // #XXX cases -- none are special cases
867 4097 : for(uint32_t i(0); i < 0x1000; ++i)
868 : {
869 4096 : c.set_color(static_cast<csspp::byte_component_t>(((i >> 0) & 15) * 0x11),
870 4096 : static_cast<csspp::byte_component_t>(((i >> 4) & 15) * 0x11),
871 4096 : static_cast<csspp::byte_component_t>(((i >> 8) & 15) * 0x11),
872 : static_cast<csspp::byte_component_t>(0xFF));
873 4096 : switch(c.get_color())
874 : {
875 1 : case (255U << 0) | (0U << 8) | (0U << 16) | (255U << 24):
876 1 : CATCH_REQUIRE(c.to_string() == "red");
877 1 : break;
878 :
879 1 : case (0U << 0) | (255U << 8) | (0U << 16) | (255U << 24):
880 1 : CATCH_REQUIRE(c.to_string() == "lime");
881 1 : break;
882 :
883 1 : case (0U << 0) | (0U << 8) | (255U << 16) | (255U << 24):
884 1 : CATCH_REQUIRE(c.to_string() == "blue");
885 1 : break;
886 :
887 1 : case (0U << 0) | (255U << 8) | (255U << 16) | (255U << 24):
888 1 : CATCH_REQUIRE(c.to_string() == "aqua");
889 1 : break;
890 :
891 4092 : default:
892 : {
893 4092 : std::stringstream ss;
894 4092 : ss << std::hex << "#"
895 4092 : << static_cast<int>((i >> 0) & 15)
896 4092 : << static_cast<int>((i >> 4) & 15)
897 4092 : << static_cast<int>((i >> 8) & 15);
898 4092 : CATCH_REQUIRE(c.to_string() == ss.str());
899 4092 : }
900 : break;
901 :
902 : }
903 : }
904 :
905 : // #XXXXXX cases -- make sure to skip the special cases
906 10001 : for(uint32_t i(0); i < 10000; ++i)
907 : {
908 : csspp::byte_component_t r, g, b;
909 :
910 10000 : bool valid(false);
911 : do
912 : {
913 10001 : r = rand() % 255;
914 10001 : g = rand() % 255;
915 10001 : b = rand() % 255;
916 10001 : switch((r << 16) | (g << 8) | (b << 0))
917 : {
918 0 : case 0xc0c0c0:
919 : case 0x808080:
920 : case 0x800000:
921 : case 0xff0000:
922 : case 0x800080:
923 : case 0x008000:
924 : case 0x00ff00:
925 : case 0x808000:
926 : case 0x000080:
927 : case 0x0000ff:
928 : case 0x008080:
929 : case 0x00ffff:
930 : // since we randomize the colors we hit these very few case
931 : // rather rarely (we could test all the colors too, but that
932 : // 16 million so a tad bit slow, that being said, I tried
933 : // once just in case)
934 : valid = false; // LCOV_EXCL_LINE
935 : break; // LCOV_EXCL_LINE
936 :
937 10001 : default:
938 20002 : valid = (r >> 4) != (r & 15)
939 585 : || (g >> 4) != (g & 15)
940 10586 : || (b >> 4) != (b & 15);
941 10001 : break;
942 :
943 : }
944 : }
945 10001 : while(!valid);
946 :
947 10000 : c.set_color(r, g, b, static_cast<csspp::byte_component_t>(0xFF));
948 :
949 20000 : std::stringstream ss;
950 10000 : ss << "#" << std::hex << std::setfill('0')
951 10000 : << std::setw(2) << static_cast<int>(r)
952 10000 : << std::setw(2) << static_cast<int>(g)
953 10000 : << std::setw(2) << static_cast<int>(b);
954 10000 : CATCH_REQUIRE(c.to_string() == ss.str());
955 : }
956 :
957 : // transparent special case
958 : {
959 1 : c.set_color(static_cast<csspp::byte_component_t>(0),
960 : static_cast<csspp::byte_component_t>(0),
961 : static_cast<csspp::byte_component_t>(0),
962 : static_cast<csspp::byte_component_t>(0));
963 1 : CATCH_REQUIRE(c.to_string() == "transparent");
964 : }
965 :
966 : // rgba()
967 67157 : for(uint32_t i(0); i < 0x1000000U; i += rand() % 500 + 1)
968 : {
969 67156 : csspp::byte_component_t const r((i >> 0) & 255);
970 67156 : csspp::byte_component_t const g((i >> 0) & 255);
971 67156 : csspp::byte_component_t const b((i >> 0) & 255);
972 67156 : csspp::byte_component_t const a((rand() % 254) + 1); // avoid 0 and 255
973 :
974 67156 : c.set_color(r, g, b, a);
975 67156 : csspp::safe_precision_t precision(2);
976 67156 : std::stringstream ss;
977 67156 : ss << "rgba(" << static_cast<int>(r)
978 67156 : << "," << static_cast<int>(g)
979 67156 : << "," << static_cast<int>(b)
980 134312 : << "," << csspp::decimal_number_to_string(static_cast<int>(a) / 255.0, true)
981 134312 : << ")";
982 67156 : CATCH_REQUIRE(c.to_string() == ss.str());
983 67156 : }
984 1 : }
985 :
986 : // vim: ts=4 sw=4 et
|