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 expression.cpp file for all possible unary expressions.
22 : *
23 : * This test runs a battery of tests agains the expression.cpp unary
24 : * expressions to ensure full coverage and that all possible input types
25 : * are checked for the unary CSS Preprocessor extensions.
26 : *
27 : * Note that all the tests use the full chain: lexer, parser, compiler,
28 : * and assembler to make sure the results are correct. So these tests
29 : * exercise the assembler even more than the assembler tests, except that
30 : * it only checks that compressed results are correct instead of all
31 : * output modes, since its only goal is covering all the possible
32 : * expression cases and not the assembler, compiler, parser, and lexer
33 : * classes.
34 : */
35 :
36 : // csspp
37 : //
38 : #include <csspp/assembler.h>
39 : #include <csspp/compiler.h>
40 : #include <csspp/exception.h>
41 : #include <csspp/parser.h>
42 :
43 :
44 : // self
45 : //
46 : #include "catch_main.h"
47 :
48 :
49 : // C++
50 : //
51 : #include <sstream>
52 :
53 :
54 : // last include
55 : //
56 : #include <snapdev/poison.h>
57 :
58 :
59 :
60 3 : CATCH_TEST_CASE("Unary expressions", "[expression] [unary]")
61 : {
62 3 : CATCH_START_SECTION("integer, identifier, hash color, color")
63 : {
64 1 : std::stringstream ss;
65 : ss << "$zzzrv: $_csspp_major > 0;\n"
66 : << "$zzzempty: null;\n"
67 : << "div {\n"
68 : << " border: 3px solid #f1a932;\n" // unary hash color
69 : << " z-index: red(complement(#56af9b));\n" // direct unary color
70 : << " content: \"\\201c\";\n" // open quotation
71 : << " width: 13%;\n"
72 : << " height: 12.5px;\n"
73 : << " color: if($zzzrv, #341109, white);\n"
74 : << " background-x: ( 32px + 44px );\n"
75 : << " background-y: + 44 * 1px;\n"
76 : << " border-top-left-radius: (- 33 + 57) * 2;\n"
77 : << " border-top-right-radius: (- 33.5 + 5.7) * 2;\n"
78 : << " unicode-range: U+410-417;\n"
79 : << " font-size: if(true, 12pt, 12px);\n"
80 : << " font-weight: if(false, bold, thin);\n"
81 : << " margin-left: calc(5% - 5px);\n"
82 : << " margin-right: expression(2.5% + 2px);\n"
83 : << " margin-top: 1.5%;\n"
84 : << " margin-bottom: - 3.2%;\n"
85 1 : << "}\n";
86 3 : csspp::position pos("test.css");
87 1 : csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
88 :
89 2 : csspp::parser p(l);
90 :
91 1 : csspp::node::pointer_t n(p.stylesheet());
92 :
93 1 : csspp::compiler c;
94 1 : c.set_root(n);
95 1 : c.set_date_time_variables(csspp_test::get_now());
96 1 : c.add_path(csspp_test::get_script_path());
97 1 : c.add_path(csspp_test::get_version_script_path());
98 :
99 1 : c.compile(false);
100 :
101 : //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
102 :
103 : // to verify that the result is still an INTEGER we have to
104 : // test the root node here
105 1 : std::stringstream compiler_out;
106 1 : compiler_out << *n;
107 1 : VERIFY_TREES(compiler_out.str(),
108 :
109 : "LIST\n"
110 : + csspp_test::get_default_variables() +
111 : " V:zzzempty\n"
112 : " LIST\n"
113 : " VARIABLE \"zzzempty\"\n"
114 : " NULL_TOKEN\n"
115 : " V:zzzrv\n"
116 : " LIST\n"
117 : " VARIABLE \"zzzrv\"\n"
118 : " LIST\n"
119 : " INTEGER \"\" I:1\n"
120 : " WHITESPACE\n"
121 : " GREATER_THAN\n"
122 : " WHITESPACE\n"
123 : " INTEGER \"\" I:0\n"
124 : " COMPONENT_VALUE\n"
125 : " ARG\n"
126 : " IDENTIFIER \"div\"\n"
127 : " OPEN_CURLYBRACKET B:true\n"
128 : " LIST\n"
129 : " DECLARATION \"border\"\n"
130 : " ARG\n"
131 : " INTEGER \"px\" I:3\n"
132 : " WHITESPACE\n"
133 : " IDENTIFIER \"solid\"\n"
134 : " WHITESPACE\n"
135 : " COLOR H:ff32a9f1\n"
136 : " DECLARATION \"z-index\"\n"
137 : " ARG\n"
138 : " INTEGER \"\" I:175\n"
139 : " DECLARATION \"content\"\n"
140 : " ARG\n"
141 : " STRING \"\xe2\x80\x9c\"\n"
142 : " DECLARATION \"width\"\n"
143 : " ARG\n"
144 : " PERCENT D:0.13\n"
145 : " DECLARATION \"height\"\n"
146 : " ARG\n"
147 : " DECIMAL_NUMBER \"px\" D:12.5\n"
148 : " DECLARATION \"color\"\n"
149 : " ARG\n"
150 : " COLOR H:ff091134\n"
151 : " DECLARATION \"background-x\"\n"
152 : " ARG\n"
153 : " INTEGER \"px\" I:76\n"
154 : " DECLARATION \"background-y\"\n"
155 : " ARG\n"
156 : " INTEGER \"px\" I:44\n"
157 : " DECLARATION \"border-top-left-radius\"\n"
158 : " ARG\n"
159 : " INTEGER \"\" I:48\n"
160 : " DECLARATION \"border-top-right-radius\"\n"
161 : " ARG\n"
162 : " DECIMAL_NUMBER \"\" D:-55.6\n"
163 : " DECLARATION \"unicode-range\"\n"
164 : " ARG\n"
165 : " UNICODE_RANGE I:4496830759952\n"
166 : " DECLARATION \"font-size\"\n"
167 : " ARG\n"
168 : " INTEGER \"pt\" I:12\n"
169 : " DECLARATION \"font-weight\"\n"
170 : " ARG\n"
171 : " IDENTIFIER \"thin\"\n"
172 : " DECLARATION \"margin-left\"\n"
173 : " ARG\n"
174 : " FUNCTION \"calc\"\n"
175 : " ARG\n"
176 : " PERCENT D:0.05\n"
177 : " WHITESPACE\n"
178 : " SUBTRACT\n"
179 : " WHITESPACE\n"
180 : " INTEGER \"px\" I:5\n"
181 : " DECLARATION \"margin-right\"\n"
182 : " ARG\n"
183 : " FUNCTION \"expression\"\n"
184 : " ARG\n"
185 : " PERCENT D:0.025\n"
186 : " WHITESPACE\n"
187 : " ADD\n"
188 : " WHITESPACE\n"
189 : " INTEGER \"px\" I:2\n"
190 : " DECLARATION \"margin-top\"\n"
191 : " ARG\n"
192 : " PERCENT D:0.015\n"
193 : " DECLARATION \"margin-bottom\"\n"
194 : " ARG\n"
195 : " PERCENT D:-0.032\n"
196 : + csspp_test::get_close_comment(true)
197 :
198 : );
199 :
200 1 : std::stringstream assembler_out;
201 1 : csspp::assembler a(assembler_out);
202 1 : a.output(n, csspp::output_mode_t::COMPRESSED);
203 :
204 : //std::cerr << "----------------- Result is " << static_cast<csspp::output_mode_t>(i) << "\n[" << out.str() << "]\n";
205 :
206 1 : CATCH_REQUIRE(assembler_out.str() ==
207 : "div{"
208 : "border:3px solid #f1a932;"
209 : "z-index:175;"
210 : "content:\"\xe2\x80\x9c\";"
211 : "width:13%;height:12.5px;"
212 : "color:#341109;"
213 : "background-x:76px;"
214 : "background-y:44px;"
215 : "border-top-left-radius:48;"
216 : "border-top-right-radius:-55.6;"
217 : "unicode-range:U+410-417;"
218 : "font-size:12pt;"
219 : "font-weight:thin;"
220 : "margin-left:calc(5% - 5px);"
221 : "margin-right:expression(2.5% + 2px);"
222 : "margin-top:1.5%;"
223 : "margin-bottom:-3.2%"
224 : "}\n"
225 : + csspp_test::get_close_comment()
226 : );
227 :
228 1 : CATCH_REQUIRE(c.get_root() == n);
229 1 : }
230 3 : CATCH_END_SECTION()
231 :
232 3 : CATCH_START_SECTION("null token (can't output)")
233 : {
234 1 : std::stringstream ss;
235 1 : ss << "div{width:null}";
236 3 : csspp::position pos("test.css");
237 1 : csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
238 :
239 2 : csspp::parser p(l);
240 :
241 1 : csspp::node::pointer_t n(p.stylesheet());
242 :
243 1 : csspp::compiler c;
244 1 : c.set_root(n);
245 1 : c.set_date_time_variables(csspp_test::get_now());
246 1 : c.add_path(csspp_test::get_script_path());
247 1 : c.add_path(csspp_test::get_version_script_path());
248 :
249 1 : c.compile(false);
250 :
251 : //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
252 :
253 : // to verify that the result is still an INTEGER we have to
254 : // test the root node here
255 1 : std::stringstream compiler_out;
256 1 : compiler_out << *n;
257 1 : VERIFY_TREES(compiler_out.str(),
258 :
259 : "LIST\n"
260 : + csspp_test::get_default_variables() +
261 : " COMPONENT_VALUE\n"
262 : " ARG\n"
263 : " IDENTIFIER \"div\"\n"
264 : " OPEN_CURLYBRACKET B:true\n"
265 : " DECLARATION \"width\"\n"
266 : " ARG\n"
267 : " NULL_TOKEN\n"
268 : + csspp_test::get_close_comment(true)
269 :
270 : );
271 :
272 1 : CATCH_REQUIRE(c.get_root() == n);
273 1 : }
274 3 : CATCH_END_SECTION()
275 :
276 3 : CATCH_START_SECTION("important width")
277 : {
278 1 : std::stringstream ss;
279 1 : ss << "div{width:3px !important}";
280 3 : csspp::position pos("test.css");
281 1 : csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
282 :
283 2 : csspp::parser p(l);
284 :
285 1 : csspp::node::pointer_t n(p.stylesheet());
286 :
287 1 : csspp::compiler c;
288 1 : c.set_root(n);
289 1 : c.set_date_time_variables(csspp_test::get_now());
290 1 : c.add_path(csspp_test::get_script_path());
291 1 : c.add_path(csspp_test::get_version_script_path());
292 :
293 1 : c.compile(false);
294 :
295 : //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
296 :
297 : // to verify that the result is still an INTEGER we have to
298 : // test the root node here
299 1 : std::stringstream compiler_out;
300 1 : compiler_out << *n;
301 1 : VERIFY_TREES(compiler_out.str(),
302 :
303 : "LIST\n"
304 : + csspp_test::get_default_variables() +
305 : " COMPONENT_VALUE\n"
306 : " ARG\n"
307 : " IDENTIFIER \"div\"\n"
308 : " OPEN_CURLYBRACKET B:true\n"
309 : " DECLARATION \"width\" F:important\n"
310 : " ARG\n"
311 : " INTEGER \"px\" I:3\n"
312 : + csspp_test::get_close_comment(true)
313 :
314 : );
315 :
316 1 : CATCH_REQUIRE(c.get_root() == n);
317 1 : }
318 3 : CATCH_END_SECTION()
319 :
320 : // no error left over
321 3 : VERIFY_ERRORS("");
322 3 : }
323 :
324 1 : CATCH_TEST_CASE("Variables in expressions", "[expression] [unary] [variable]")
325 : {
326 1 : CATCH_START_SECTION("set expression variable and reuse")
327 : {
328 1 : std::stringstream ss;
329 : ss << "div {\n"
330 : << " border: (w := 54px, w / 2.7)[-1] solid #f1a932;\n"
331 1 : << "}\n";
332 3 : csspp::position pos("test.css");
333 1 : csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
334 :
335 2 : csspp::parser p(l);
336 :
337 1 : csspp::node::pointer_t n(p.stylesheet());
338 :
339 1 : csspp::compiler c;
340 1 : c.set_root(n);
341 1 : c.set_date_time_variables(csspp_test::get_now());
342 1 : c.add_path(csspp_test::get_script_path());
343 1 : c.add_path(csspp_test::get_version_script_path());
344 :
345 1 : c.compile(false);
346 :
347 : //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
348 :
349 : // to verify that the result is still an INTEGER we have to
350 : // test the root node here
351 1 : std::stringstream compiler_out;
352 1 : compiler_out << *n;
353 1 : VERIFY_TREES(compiler_out.str(),
354 :
355 : "LIST\n"
356 : + csspp_test::get_default_variables() +
357 : " COMPONENT_VALUE\n"
358 : " ARG\n"
359 : " IDENTIFIER \"div\"\n"
360 : " OPEN_CURLYBRACKET B:true\n"
361 : " DECLARATION \"border\"\n"
362 : " ARG\n"
363 : " DECIMAL_NUMBER \"px\" D:20\n"
364 : " WHITESPACE\n"
365 : " IDENTIFIER \"solid\"\n"
366 : " WHITESPACE\n"
367 : " COLOR H:ff32a9f1\n"
368 : + csspp_test::get_close_comment(true)
369 :
370 : );
371 :
372 1 : std::stringstream assembler_out;
373 1 : csspp::assembler a(assembler_out);
374 1 : a.output(n, csspp::output_mode_t::COMPRESSED);
375 :
376 : //std::cerr << "----------------- Result is " << static_cast<csspp::output_mode_t>(i) << "\n[" << out.str() << "]\n";
377 :
378 1 : CATCH_REQUIRE(assembler_out.str() ==
379 :
380 : "div{"
381 : "border:20px solid #f1a932"
382 : "}\n"
383 : + csspp_test::get_close_comment()
384 :
385 : );
386 :
387 1 : CATCH_REQUIRE(c.get_root() == n);
388 1 : }
389 1 : CATCH_END_SECTION()
390 :
391 : // no error left over
392 1 : VERIFY_ERRORS("");
393 1 : }
394 :
395 6 : CATCH_TEST_CASE("Invalid unary expressions", "[expression] [unary] [invalid]")
396 : {
397 6 : CATCH_START_SECTION("not a unary token")
398 : {
399 1 : std::stringstream ss;
400 1 : ss << "div { border: ?; }\n";
401 3 : csspp::position pos("test.css");
402 1 : csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
403 :
404 2 : csspp::parser p(l);
405 :
406 1 : csspp::node::pointer_t n(p.stylesheet());
407 :
408 1 : csspp::compiler c;
409 1 : c.set_root(n);
410 1 : c.set_date_time_variables(csspp_test::get_now());
411 1 : c.add_path(csspp_test::get_script_path());
412 1 : c.add_path(csspp_test::get_version_script_path());
413 :
414 1 : c.compile(false);
415 :
416 : //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
417 :
418 1 : VERIFY_ERRORS("test.css(1): error: unsupported type CONDITIONAL as a unary expression token.\n");
419 :
420 1 : CATCH_REQUIRE(c.get_root() == n);
421 1 : }
422 6 : CATCH_END_SECTION()
423 :
424 6 : CATCH_START_SECTION("invalid # color")
425 : {
426 1 : std::stringstream ss;
427 1 : ss << "div { border: #identifier; }\n";
428 3 : csspp::position pos("test.css");
429 1 : csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
430 :
431 2 : csspp::parser p(l);
432 :
433 1 : csspp::node::pointer_t n(p.stylesheet());
434 :
435 1 : csspp::compiler c;
436 1 : c.set_root(n);
437 1 : c.set_date_time_variables(csspp_test::get_now());
438 1 : c.add_path(csspp_test::get_script_path());
439 1 : c.add_path(csspp_test::get_version_script_path());
440 :
441 1 : c.compile(false);
442 :
443 : //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
444 :
445 1 : VERIFY_ERRORS("test.css(1): error: the color in #identifier is not valid.\n");
446 :
447 1 : CATCH_REQUIRE(c.get_root() == n);
448 1 : }
449 6 : CATCH_END_SECTION()
450 :
451 6 : CATCH_START_SECTION("not a valid token for minus")
452 : {
453 1 : std::stringstream ss;
454 1 : ss << "div { border: - \"test\"; }\n";
455 3 : csspp::position pos("test.css");
456 1 : csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
457 :
458 2 : csspp::parser p(l);
459 :
460 1 : csspp::node::pointer_t n(p.stylesheet());
461 :
462 1 : csspp::compiler c;
463 1 : c.set_root(n);
464 1 : c.set_date_time_variables(csspp_test::get_now());
465 1 : c.add_path(csspp_test::get_script_path());
466 1 : c.add_path(csspp_test::get_version_script_path());
467 :
468 1 : c.compile(false);
469 :
470 : //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
471 :
472 1 : VERIFY_ERRORS("test.css(1): error: unsupported type STRING for operator '-'.\n");
473 :
474 1 : CATCH_REQUIRE(c.get_root() == n);
475 1 : }
476 6 : CATCH_END_SECTION()
477 :
478 6 : CATCH_START_SECTION("improper initialization of an expression object")
479 : {
480 1 : csspp::node::pointer_t null_node;
481 4 : CATCH_REQUIRE_THROWS_AS(new csspp::expression(null_node), csspp::csspp_exception_logic);
482 1 : }
483 6 : CATCH_END_SECTION()
484 :
485 6 : CATCH_START_SECTION("important width, wrong order")
486 : {
487 1 : std::stringstream ss;
488 1 : ss << "div { width: !important 3px; }";
489 3 : csspp::position pos("test.css");
490 1 : csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
491 :
492 2 : csspp::parser p(l);
493 :
494 1 : csspp::node::pointer_t n(p.stylesheet());
495 :
496 1 : csspp::compiler c;
497 1 : c.set_root(n);
498 1 : c.set_date_time_variables(csspp_test::get_now());
499 1 : c.add_path(csspp_test::get_script_path());
500 1 : c.add_path(csspp_test::get_version_script_path());
501 :
502 1 : c.compile(false);
503 :
504 : //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
505 :
506 1 : VERIFY_ERRORS("test.css(1): warning: A special flag, !important in this case, must only appear at the end of a declaration.\n");
507 :
508 1 : CATCH_REQUIRE(c.get_root() == n);
509 1 : }
510 6 : CATCH_END_SECTION()
511 :
512 6 : CATCH_START_SECTION("minus by itself")
513 : {
514 1 : std::stringstream ss;
515 1 : ss << "div { width: -; }";
516 3 : csspp::position pos("test.css");
517 1 : csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
518 :
519 2 : csspp::parser p(l);
520 :
521 1 : csspp::node::pointer_t n(p.stylesheet());
522 :
523 1 : csspp::compiler c;
524 1 : c.set_root(n);
525 1 : c.set_date_time_variables(csspp_test::get_now());
526 1 : c.add_path(csspp_test::get_script_path());
527 1 : c.add_path(csspp_test::get_version_script_path());
528 :
529 1 : c.compile(false);
530 :
531 : //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
532 :
533 1 : VERIFY_ERRORS("test.css(1): error: unsupported type EOF_TOKEN as a unary expression token.\n");
534 :
535 1 : CATCH_REQUIRE(c.get_root() == n);
536 1 : }
537 6 : CATCH_END_SECTION()
538 :
539 : // no error left over
540 6 : VERIFY_ERRORS("");
541 6 : }
542 :
543 : // vim: ts=4 sw=4 et
|