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 lexer.cpp file.
22 : *
23 : * This test runs a battery of tests agains the lexer.cpp file to ensure
24 : * full coverage and many edge cases as expected by CSS 3.
25 : *
26 : * Note that CSS 3 is fully compatible with CSS 1 and 2.1. However, it does
27 : * not support exactly the same character sets. Also our version only supports
28 : * UTF-8 as input.
29 : */
30 :
31 : // csspp
32 : //
33 : #include <csspp/exception.h>
34 : #include <csspp/lexer.h>
35 : #include <csspp/unicode_range.h>
36 :
37 :
38 : // self
39 : //
40 : #include "catch_main.h"
41 :
42 :
43 : // C++
44 : //
45 : #include <iomanip>
46 : #include <iostream>
47 : #include <sstream>
48 :
49 :
50 : // C
51 : //
52 : #include <math.h>
53 : #include <string.h>
54 :
55 :
56 : // last include
57 : //
58 : #include <snapdev/poison.h>
59 :
60 :
61 :
62 : namespace
63 : {
64 :
65 : } // no name namespace
66 :
67 :
68 :
69 :
70 1 : CATCH_TEST_CASE("UTF-8 conversions", "[lexer] [unicode]")
71 : {
72 1 : std::stringstream ss;
73 3 : csspp::position pos("test.css");
74 1 : csspp::lexer l(ss, pos);
75 :
76 : // first check all valid characters encoding
77 1114113 : for(csspp::wide_char_t i(0); i < 0x110000; ++i)
78 : {
79 1114112 : if((i >= 0xD000 && i <= 0xDFFF) // surrogate
80 1110016 : || (i & 0xFFFF) == 0xFFFE // invalid
81 1109999 : || (i & 0xFFFF) == 0xFFFF) // invalid
82 : {
83 4130 : continue;
84 : }
85 1109982 : std::string const str(l.wctomb(i));
86 1109982 : csspp::wide_char_t const wc(l.mbtowc(str.c_str()));
87 :
88 1109982 : CATCH_REQUIRE(wc == i);
89 1109982 : }
90 :
91 : // make sure the test for the buffer size works as expected
92 6 : for(size_t i(0); i < 5; ++i)
93 : {
94 5 : char buf[6];
95 5 : csspp::wide_char_t const wc(rand() % 0x1FFFFF);
96 5 : CATCH_REQUIRE_THROWS_AS(l.wctomb(wc, buf, i), csspp::csspp_exception_overflow);
97 : }
98 :
99 : // make sure surrogates are not allowed
100 2049 : for(csspp::wide_char_t i(0xD800); i <= 0xDFFF; ++i)
101 : {
102 2048 : char buf[6];
103 2048 : buf[0] = '?';
104 2048 : l.wctomb(i, buf, sizeof(buf) / sizeof(buf[0]));
105 2048 : CATCH_REQUIRE(buf[0] == '\0'); // make sure we get an empty string on errors
106 2048 : VERIFY_ERRORS("test.css(1): error: surrogate characters cannot be encoded in UTF-8.\n");
107 : }
108 :
109 : // page 0 -- error is slightly different
110 : {
111 1 : char buf[6];
112 : // test FFFE
113 1 : buf[0] = '?';
114 1 : l.wctomb(0xFFFE, buf, sizeof(buf) / sizeof(buf[0]));
115 1 : CATCH_REQUIRE(buf[0] == '\0'); // make sure we get an empty string on errors
116 1 : VERIFY_ERRORS("test.css(1): error: characters 0xFFFE and 0xFFFF are not valid.\n");
117 :
118 : // test FFFF
119 1 : buf[0] = '?';
120 1 : l.wctomb(0xFFFF, buf, sizeof(buf) / sizeof(buf[0]));
121 1 : CATCH_REQUIRE(buf[0] == '\0'); // make sure we get an empty string on errors
122 1 : VERIFY_ERRORS("test.css(1): error: characters 0xFFFE and 0xFFFF are not valid.\n");
123 : }
124 :
125 : // page 1 to 16
126 17 : for(csspp::wide_char_t page(1); page <= 0x10; ++page)
127 : {
128 16 : char buf[6];
129 : // test <page>FFFE
130 16 : csspp::wide_char_t wc((page << 16) | 0xFFFE);
131 16 : buf[0] = '?';
132 16 : l.wctomb(wc, buf, sizeof(buf) / sizeof(buf[0]));
133 16 : CATCH_REQUIRE(buf[0] == '\0'); // make sure we get an empty string on errors
134 16 : VERIFY_ERRORS("test.css(1): error: any characters that end with 0xFFFE or 0xFFFF are not valid.\n");
135 :
136 : // test <page>FFFF
137 16 : wc = (page << 16) | 0xFFFF;
138 16 : buf[0] = '?';
139 16 : l.wctomb(wc, buf, sizeof(buf) / sizeof(buf[0]));
140 16 : CATCH_REQUIRE(buf[0] == '\0'); // make sure we get an empty string on errors
141 16 : VERIFY_ERRORS("test.css(1): error: any characters that end with 0xFFFE or 0xFFFF are not valid.\n");
142 : }
143 :
144 : // test 1,000 characters with a number that's too large
145 1001 : for(int i(0); i < 1000; ++i)
146 : {
147 1000 : csspp::wide_char_t wc(0);
148 : do
149 : {
150 : // make sure we get a 32 bit value, hitting all possible bits
151 1000 : wc = rand() ^ (rand() << 16);
152 : }
153 1000 : while(static_cast<csspp::wide_uchar_t>(wc) < 0x110000);
154 1000 : char buf[6];
155 1000 : buf[0] = '?';
156 1000 : l.wctomb(wc, buf, sizeof(buf) / sizeof(buf[0]));
157 1000 : CATCH_REQUIRE(buf[0] == '\0'); // make sure we get an empty string on errors
158 1000 : VERIFY_ERRORS("test.css(1): error: character too large, it cannot be encoded in UTF-8.\n");
159 : }
160 :
161 : // check that bytes 0xF8 and over generate an error
162 9 : for(int i(0xF8); i < 0x100; ++i)
163 : {
164 8 : char buf[6];
165 8 : buf[0] = i;
166 8 : buf[1] = static_cast<char>(0x80);
167 8 : buf[2] = static_cast<char>(0x80);
168 8 : buf[3] = static_cast<char>(0x80);
169 8 : buf[4] = static_cast<char>(0x80);
170 8 : buf[5] = 0;
171 8 : CATCH_REQUIRE(l.mbtowc(buf) == 0xFFFD);
172 8 : std::stringstream errmsg;
173 8 : errmsg << "test.css(1): error: byte U+" << std::hex << i << " not valid in a UTF-8 stream.\n";
174 8 : VERIFY_ERRORS(errmsg.str());
175 8 : }
176 :
177 : // continuation bytes at the start
178 65 : for(int i(0x80); i < 0xC0; ++i)
179 : {
180 64 : char buf[6];
181 64 : buf[0] = i;
182 64 : buf[1] = static_cast<char>(0x80);
183 64 : buf[2] = static_cast<char>(0x80);
184 64 : buf[3] = static_cast<char>(0x80);
185 64 : buf[4] = static_cast<char>(0x80);
186 64 : buf[5] = 0;
187 64 : CATCH_REQUIRE(l.mbtowc(buf) == 0xFFFD);
188 64 : std::stringstream errmsg;
189 64 : errmsg << "test.css(1): error: byte U+" << std::hex << i << " not valid to introduce a UTF-8 encoded character.\n";
190 64 : VERIFY_ERRORS(errmsg.str());
191 64 : }
192 :
193 : // not enough bytes ('\0' too soon)
194 57 : for(int i(0xC0); i < 0xF8; ++i)
195 : {
196 56 : char buf[6];
197 56 : buf[0] = i;
198 56 : buf[1] = 0;
199 56 : CATCH_REQUIRE(l.mbtowc(buf) == 0xFFFD);
200 56 : std::stringstream errmsg;
201 56 : errmsg << "test.css(1): error: sequence of bytes too short to represent a valid UTF-8 encoded character.\n";
202 56 : VERIFY_ERRORS(errmsg.str());
203 56 : }
204 :
205 : // too many bytes ('\0' missing), and
206 : // invalid sequence (a char replace with an invalid code)
207 1113985 : for(csspp::wide_char_t i(128); i < 0x110000; ++i)
208 : {
209 1113984 : if((i >= 0xD000 && i <= 0xDFFF) // surrogate
210 1109888 : || (i & 0xFFFF) == 0xFFFE // invalid
211 1109871 : || (i & 0xFFFF) == 0xFFFF) // invalid
212 : {
213 4130 : continue;
214 : }
215 1109854 : std::string const str(l.wctomb(i));
216 :
217 : // the sequence is one too many bytes
218 : {
219 1109854 : std::string const too_long(str + static_cast<char>(rand() % 64 + 0x80)); // add one byte
220 1109854 : CATCH_REQUIRE(l.mbtowc(too_long.c_str()) == 0xFFFD);
221 1109854 : std::stringstream errmsg;
222 1109854 : errmsg << "test.css(1): error: sequence of bytes too long, it cannot represent a valid UTF-8 encoded character.\n";
223 1109854 : VERIFY_ERRORS(errmsg.str());
224 1109854 : }
225 :
226 : // one of the bytes in the sequence is not between 0x80 and 0xBF
227 : // this only works if the sequence is at least 2 bytes
228 : // (i.e. that starts when 'i' is 128 or more)
229 : {
230 1109854 : size_t const p(rand() % (str.length() - 1));
231 1109854 : if(p + 1 >= str.length())
232 : {
233 0 : std::cerr << "computed " << p + 1 << " for a string of length " << str.length() << "\n";
234 0 : throw std::logic_error("test computed a position that's out of range.");
235 : }
236 1109854 : std::string wrong_sequence(str);
237 1109854 : int c(rand() % (255 - 64) + 1); // '\0' is not good for this test
238 1109854 : if(c >= 0x80)
239 : {
240 371475 : c += 64;
241 : }
242 1109854 : wrong_sequence[p + 1] = static_cast<char>(c);
243 1109854 : CATCH_REQUIRE(l.mbtowc(wrong_sequence.c_str()) == 0xFFFD);
244 1109854 : std::stringstream errmsg;
245 1109854 : errmsg << "test.css(1): error: invalid sequence of bytes, it cannot represent a valid UTF-8 encoded character.\n";
246 1109854 : VERIFY_ERRORS(errmsg.str());
247 1109854 : }
248 1109854 : }
249 :
250 : // no error left over
251 1 : VERIFY_ERRORS("");
252 2 : }
253 :
254 1 : CATCH_TEST_CASE("Invalid characters", "[lexer] [invalid]")
255 : {
256 : // 0xFFFD
257 : {
258 1 : std::stringstream ss;
259 3 : csspp::position pos("test.css");
260 1 : csspp::lexer l(ss, pos);
261 1 : ss << l.wctomb(0xFFFD);
262 :
263 : // so far, no error
264 1 : VERIFY_ERRORS("");
265 :
266 : // EOF
267 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
268 :
269 : // make sure we got the expected error
270 1 : VERIFY_ERRORS("test.css(1): error: invalid input character: U+fffd.\n");
271 1 : }
272 :
273 : // '\0'
274 : {
275 1 : std::stringstream ss;
276 1 : ss << '\0';
277 3 : csspp::position pos("test.css");
278 1 : csspp::lexer l(ss, pos);
279 :
280 : // so far, no error
281 1 : VERIFY_ERRORS("");
282 :
283 : // EOF
284 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
285 :
286 : // make sure we got the expected error
287 1 : VERIFY_ERRORS("test.css(1): error: invalid input character: U+fffd.\n");
288 1 : }
289 :
290 : // '^', '<', etc.
291 128 : for(int i(1); i < 128; ++i)
292 : {
293 : // test all that are invalid so we have an if to skip on all
294 : // characters that can represent the beginning of a valid token
295 127 : if(
296 : // whitespace
297 : i != ' '
298 126 : && i != '\t'
299 125 : && i != '\n'
300 124 : && i != '\r'
301 123 : && i != '\f'
302 : // identifiers / numbers
303 122 : && (i < '0' || i > '9')
304 112 : && (i < 'A' || i > 'Z')
305 86 : && (i < 'a' || i > 'z')
306 60 : && i != '_'
307 59 : && i != '-'
308 58 : && i != '+'
309 57 : && i != '.'
310 56 : && i != '\\'
311 55 : && i != '@'
312 54 : && i != '#'
313 : // delimiters
314 53 : && i != '*'
315 52 : && i != '/'
316 51 : && i != '='
317 50 : && i != '('
318 49 : && i != ')'
319 48 : && i != '{'
320 47 : && i != '}'
321 46 : && i != '['
322 45 : && i != ']'
323 44 : && i != ','
324 43 : && i != ';'
325 42 : && i != ':'
326 41 : && i != '<'
327 40 : && i != '>'
328 39 : && i != '$'
329 38 : && i != '!'
330 37 : && i != '|'
331 36 : && i != '&'
332 35 : && i != '~'
333 34 : && i != '%'
334 33 : && i != '?'
335 : // string
336 32 : && i != '"'
337 31 : && i != '\''
338 : )
339 : {
340 30 : std::stringstream ss;
341 30 : ss << static_cast<char>(i);
342 90 : csspp::position pos("test.css");
343 30 : csspp::lexer l(ss, pos);
344 :
345 : // so far, no error
346 30 : VERIFY_ERRORS("");
347 :
348 : // EOF
349 30 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
350 :
351 : // make sure we got the expected error
352 30 : std::stringstream errmsg;
353 30 : errmsg << "test.css(1): error: invalid input character: U+" << std::hex << static_cast<int>(i) << "." << std::endl;
354 30 : VERIFY_ERRORS(errmsg.str());
355 30 : }
356 : }
357 :
358 : // invalid UTF-8 sequence (i.e. too long)
359 : {
360 1 : std::stringstream ss;
361 : ss << static_cast<char>(0xF7)
362 : << static_cast<char>(0x80)
363 : << static_cast<char>(0x80)
364 : << static_cast<char>(0x80)
365 : << static_cast<char>(0x80)
366 : << static_cast<char>(0x80)
367 : << static_cast<char>(0x80)
368 : << static_cast<char>(0x80)
369 1 : << static_cast<char>(0x80);
370 3 : csspp::position pos("test.css");
371 1 : csspp::lexer l(ss, pos);
372 :
373 : // so far, no error
374 1 : VERIFY_ERRORS("");
375 :
376 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
377 :
378 : // make sure we got the expected errors
379 1 : VERIFY_ERRORS(
380 : "test.css(1): error: too many follow bytes, it cannot represent a valid UTF-8 character.\n"
381 : "test.css(1): error: invalid input character: U+fffd.\n"
382 : );
383 1 : }
384 :
385 : // invalid UTF-8 sequence (i.e. too long, followed by a comment and a string)
386 : {
387 1 : std::stringstream ss;
388 : ss << static_cast<char>(0xF7)
389 : << static_cast<char>(0x80)
390 : << static_cast<char>(0x80)
391 : << static_cast<char>(0x80)
392 : << static_cast<char>(0x80)
393 : << static_cast<char>(0x80)
394 : << static_cast<char>(0x80)
395 : << static_cast<char>(0x80)
396 : << static_cast<char>(0x80)
397 : << "// plus a comment to @preserve\r\n"
398 1 : << "' and a string '";
399 3 : csspp::position pos("test.css");
400 1 : csspp::lexer l(ss, pos);
401 :
402 : // so far, no error
403 1 : VERIFY_ERRORS("");
404 :
405 : // comment
406 : {
407 1 : csspp::node::pointer_t comment(l.next_token());
408 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
409 1 : CATCH_REQUIRE(comment->get_string() == "plus a comment to @preserve");
410 1 : CATCH_REQUIRE(comment->get_integer() == 0); // C++ comment
411 1 : csspp::position const & npos(comment->get_position());
412 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
413 1 : CATCH_REQUIRE(npos.get_page() == 1);
414 1 : CATCH_REQUIRE(npos.get_line() == 1);
415 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
416 :
417 : // make sure we got the expected errors
418 1 : VERIFY_ERRORS(
419 : "test.css(1): error: too many follow bytes, it cannot represent a valid UTF-8 character.\n"
420 : "test.css(1): error: invalid input character: U+fffd.\n"
421 : "test.css(1): warning: C++ comments should not be preserved as they are not supported by most CSS parsers.\n"
422 : );
423 1 : }
424 :
425 : // whitespace
426 : {
427 1 : csspp::node::pointer_t whitespace(l.next_token());
428 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
429 1 : csspp::position const & npos(whitespace->get_position());
430 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
431 1 : CATCH_REQUIRE(npos.get_page() == 1);
432 1 : CATCH_REQUIRE(npos.get_line() == 2);
433 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
434 1 : }
435 :
436 : // string
437 : {
438 1 : csspp::node::pointer_t string(l.next_token());
439 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
440 1 : CATCH_REQUIRE(string->get_string() == " and a string ");
441 1 : csspp::position const & npos(string->get_position());
442 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
443 1 : CATCH_REQUIRE(npos.get_page() == 1);
444 1 : CATCH_REQUIRE(npos.get_line() == 2);
445 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
446 1 : }
447 :
448 : // EOF
449 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
450 1 : }
451 :
452 : // invalid UTF-8 sequence (i.e. incorrect introducer)
453 66 : for(int i(0x80); i <= 0xC0; ++i)
454 : {
455 : // ends with EOF
456 : {
457 65 : std::stringstream ss;
458 64 : ss << static_cast<char>(i == 0xC0 ? 0xFF : i)
459 : << static_cast<char>(0x80)
460 : << static_cast<char>(0x80)
461 : << static_cast<char>(0x80)
462 : << static_cast<char>(0x80)
463 : << static_cast<char>(0x80)
464 : << static_cast<char>(0x80)
465 : << static_cast<char>(0x80)
466 65 : << static_cast<char>(0x80);
467 195 : csspp::position pos("test.css");
468 65 : csspp::lexer l(ss, pos);
469 :
470 : // so far, no error
471 65 : VERIFY_ERRORS("");
472 :
473 65 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
474 :
475 : // make sure we got the expected errors
476 65 : std::stringstream errmsg;
477 65 : errmsg << "test.css(1): error: unexpected byte in input buffer: U+"
478 65 : << std::hex << (i == 0xC0 ? 0xFF : i)
479 65 : << ".\ntest.css(1): error: invalid input character: U+fffd.\n";
480 65 : VERIFY_ERRORS(errmsg.str());
481 65 : }
482 :
483 : // ends with comment and string
484 : {
485 65 : std::stringstream ss;
486 64 : ss << static_cast<char>(i == 0xC0 ? 0xFF : i)
487 : << static_cast<char>(0x80)
488 : << static_cast<char>(0x80)
489 : << static_cast<char>(0x80)
490 : << static_cast<char>(0x80)
491 : << static_cast<char>(0x80)
492 : << static_cast<char>(0x80)
493 : << static_cast<char>(0x80)
494 : << static_cast<char>(0x80)
495 : << "// plus one comment to @preserve\r\n"
496 65 : << "' and that string '";
497 195 : csspp::position pos("test.css");
498 65 : csspp::lexer l(ss, pos);
499 :
500 : // so far, no error
501 65 : VERIFY_ERRORS("");
502 :
503 : // comment
504 : {
505 65 : csspp::node::pointer_t comment(l.next_token());
506 65 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
507 65 : CATCH_REQUIRE(comment->get_string() == "plus one comment to @preserve");
508 65 : CATCH_REQUIRE(comment->get_integer() == 0); // C++ comment
509 65 : csspp::position const & npos(comment->get_position());
510 65 : CATCH_REQUIRE(npos.get_filename() == "test.css");
511 65 : CATCH_REQUIRE(npos.get_page() == 1);
512 65 : CATCH_REQUIRE(npos.get_line() == 1);
513 65 : CATCH_REQUIRE(npos.get_total_line() == 1);
514 65 : }
515 :
516 : // whitespace
517 : {
518 65 : csspp::node::pointer_t whitespace(l.next_token());
519 65 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
520 65 : csspp::position const & npos(whitespace->get_position());
521 65 : CATCH_REQUIRE(npos.get_filename() == "test.css");
522 65 : CATCH_REQUIRE(npos.get_page() == 1);
523 65 : CATCH_REQUIRE(npos.get_line() == 2);
524 65 : CATCH_REQUIRE(npos.get_total_line() == 2);
525 65 : }
526 :
527 : // string
528 : {
529 65 : csspp::node::pointer_t string(l.next_token());
530 65 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
531 65 : CATCH_REQUIRE(string->get_string() == " and that string ");
532 65 : csspp::position const & npos(string->get_position());
533 65 : CATCH_REQUIRE(npos.get_filename() == "test.css");
534 65 : CATCH_REQUIRE(npos.get_page() == 1);
535 65 : CATCH_REQUIRE(npos.get_line() == 2);
536 65 : CATCH_REQUIRE(npos.get_total_line() == 2);
537 65 : }
538 :
539 : // EOF
540 65 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
541 :
542 : // make sure we got the expected errors
543 65 : std::stringstream errmsg;
544 65 : errmsg << "test.css(1): error: unexpected byte in input buffer: U+"
545 65 : << std::hex << (i == 0xC0 ? 0xFF : i)
546 : << ".\ntest.css(1): error: invalid input character: U+fffd.\n"
547 65 : << "test.css(1): warning: C++ comments should not be preserved as they are not supported by most CSS parsers.\n";
548 65 : VERIFY_ERRORS(errmsg.str());
549 65 : }
550 : }
551 :
552 : // no error left over
553 1 : VERIFY_ERRORS("");
554 1 : }
555 :
556 1 : CATCH_TEST_CASE("Simple tokens", "[lexer] [basics] [delimiters]")
557 : {
558 : // ' ' -> WHITESPACE
559 : {
560 1 : char const * whitespaces = " \t\n\r\f";
561 1 : size_t len(strlen(whitespaces));
562 :
563 : // try evey single whitespace by itself
564 6 : for(size_t i(0); i < len; ++i)
565 : {
566 5 : std::stringstream ss;
567 15 : csspp::position pos("test.css");
568 5 : csspp::lexer l(ss, pos);
569 5 : ss << whitespaces[i];
570 :
571 : // so far, no error
572 5 : VERIFY_ERRORS("");
573 :
574 5 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::WHITESPACE));
575 5 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
576 :
577 : // make sure we got the expected error
578 5 : VERIFY_ERRORS("");
579 5 : }
580 :
581 : // try 1,000 combo of 3 to 12 whitespaces
582 1001 : for(size_t i(0); i < 1000; ++i)
583 : {
584 1000 : std::stringstream ss;
585 3000 : csspp::position pos("test.css");
586 1000 : csspp::lexer l(ss, pos);
587 1000 : size_t const count(rand() % 10 + 3);
588 8542 : for(size_t j(0); j < count; ++j)
589 : {
590 7542 : int const k(rand() % len);
591 7542 : ss << whitespaces[k];
592 : }
593 :
594 : // so far, no error
595 1000 : VERIFY_ERRORS("");
596 :
597 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::WHITESPACE));
598 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
599 :
600 : // make sure we got the expected error
601 1000 : VERIFY_ERRORS("");
602 1000 : }
603 : }
604 :
605 : // '=' -> EQUAL
606 : {
607 1 : std::stringstream ss;
608 3 : csspp::position pos("test.css");
609 1 : csspp::lexer l(ss, pos);
610 1 : ss << "=";
611 :
612 : // so far, no error
613 1 : VERIFY_ERRORS("");
614 :
615 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EQUAL));
616 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
617 :
618 : // make sure we got the expected error
619 1 : VERIFY_ERRORS("");
620 1 : }
621 :
622 : // '==' -> EQUAL + warning
623 : {
624 1 : std::stringstream ss;
625 3 : csspp::position pos("test.css");
626 1 : csspp::lexer l(ss, pos);
627 1 : ss << "==";
628 :
629 : // so far, no error
630 1 : VERIFY_ERRORS("");
631 :
632 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EQUAL));
633 1 : VERIFY_ERRORS("test.css(1): warning: we accepted '==' instead of '=' in an expression, you probably want to change the operator to just '=', though.\n");
634 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
635 :
636 : // make sure we got the expected error
637 1 : VERIFY_ERRORS("");
638 1 : }
639 :
640 : // ',' -> COMMA
641 : {
642 1 : std::stringstream ss;
643 3 : csspp::position pos("test.css");
644 1 : csspp::lexer l(ss, pos);
645 1 : ss << ",";
646 :
647 : // so far, no error
648 1 : VERIFY_ERRORS("");
649 :
650 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::COMMA));
651 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
652 :
653 : // make sure we got the expected error
654 1 : VERIFY_ERRORS("");
655 1 : }
656 :
657 : // ':' -> COLON
658 : {
659 1 : std::stringstream ss;
660 3 : csspp::position pos("test.css");
661 1 : csspp::lexer l(ss, pos);
662 1 : ss << ":";
663 :
664 : // so far, no error
665 1 : VERIFY_ERRORS("");
666 :
667 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::COLON));
668 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
669 :
670 : // make sure we got the expected error
671 1 : VERIFY_ERRORS("");
672 1 : }
673 :
674 : // ';' -> SEMICOLON
675 : {
676 1 : std::stringstream ss;
677 3 : csspp::position pos("test.css");
678 1 : csspp::lexer l(ss, pos);
679 1 : ss << ";";
680 :
681 : // so far, no error
682 1 : VERIFY_ERRORS("");
683 :
684 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::SEMICOLON));
685 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
686 :
687 : // make sure we got the expected error
688 1 : VERIFY_ERRORS("");
689 1 : }
690 :
691 : // '.' -> PERIOD
692 : {
693 1 : std::stringstream ss;
694 3 : csspp::position pos("test.css");
695 1 : csspp::lexer l(ss, pos);
696 1 : ss << ".";
697 :
698 : // so far, no error
699 1 : VERIFY_ERRORS("");
700 :
701 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::PERIOD));
702 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
703 :
704 : // make sure we got the expected error
705 1 : VERIFY_ERRORS("");
706 1 : }
707 :
708 : // '$' -> DOLLAR
709 : {
710 1 : std::stringstream ss;
711 3 : csspp::position pos("test.css");
712 1 : csspp::lexer l(ss, pos);
713 1 : ss << "$";
714 :
715 : // so far, no error
716 1 : VERIFY_ERRORS("");
717 :
718 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::DOLLAR));
719 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
720 :
721 : // make sure we got the expected error
722 1 : VERIFY_ERRORS("");
723 1 : }
724 :
725 : // '?' -> CONDITIONAL
726 : {
727 1 : std::stringstream ss;
728 3 : csspp::position pos("test.css");
729 1 : csspp::lexer l(ss, pos);
730 1 : ss << "?";
731 :
732 : // so far, no error
733 1 : VERIFY_ERRORS("");
734 :
735 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::CONDITIONAL));
736 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
737 :
738 : // make sure we got the expected error
739 1 : VERIFY_ERRORS("");
740 1 : }
741 :
742 : // '%' -> MODULO
743 : {
744 1 : std::stringstream ss;
745 3 : csspp::position pos("test.css");
746 1 : csspp::lexer l(ss, pos);
747 1 : ss << "%";
748 :
749 : // so far, no error
750 1 : VERIFY_ERRORS("");
751 :
752 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::MODULO));
753 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
754 :
755 : // make sure we got the expected error
756 1 : VERIFY_ERRORS("");
757 1 : }
758 :
759 : // '/' -> DIVIDE
760 : {
761 1 : std::stringstream ss;
762 3 : csspp::position pos("test.css");
763 1 : csspp::lexer l(ss, pos);
764 1 : ss << "/";
765 :
766 : // so far, no error
767 1 : VERIFY_ERRORS("");
768 :
769 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::DIVIDE));
770 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
771 :
772 : // make sure we got the expected error
773 1 : VERIFY_ERRORS("");
774 1 : }
775 :
776 : // '*' -> MULTIPLY
777 : {
778 1 : std::stringstream ss;
779 3 : csspp::position pos("test.css");
780 1 : csspp::lexer l(ss, pos);
781 1 : ss << "*";
782 :
783 : // so far, no error
784 1 : VERIFY_ERRORS("");
785 :
786 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::MULTIPLY));
787 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
788 :
789 : // make sure we got the expected error
790 1 : VERIFY_ERRORS("");
791 1 : }
792 :
793 : // '**' -> POWER
794 : {
795 1 : std::stringstream ss;
796 3 : csspp::position pos("test.css");
797 1 : csspp::lexer l(ss, pos);
798 1 : ss << '*' << '*';
799 :
800 : // so far, no error
801 1 : VERIFY_ERRORS("");
802 :
803 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::POWER));
804 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
805 :
806 : // make sure we got the expected error
807 1 : VERIFY_ERRORS("");
808 1 : }
809 :
810 : // '&' -> REFERENCE
811 : {
812 1 : std::stringstream ss;
813 3 : csspp::position pos("test.css");
814 1 : csspp::lexer l(ss, pos);
815 1 : ss << "&";
816 :
817 : // so far, no error
818 1 : VERIFY_ERRORS("");
819 :
820 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::REFERENCE));
821 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
822 :
823 : // make sure we got the expected error
824 1 : VERIFY_ERRORS("");
825 1 : }
826 :
827 : // '&&' -> AND
828 : {
829 1 : std::stringstream ss;
830 3 : csspp::position pos("test.css");
831 1 : csspp::lexer l(ss, pos);
832 1 : ss << '&' << '&';
833 :
834 : // so far, no error
835 1 : VERIFY_ERRORS("");
836 :
837 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::AND));
838 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
839 :
840 : // make sure we got the expected error
841 1 : VERIFY_ERRORS("");
842 1 : }
843 :
844 : // '~' -> PRECEDED
845 : {
846 1 : std::stringstream ss;
847 3 : csspp::position pos("test.css");
848 1 : csspp::lexer l(ss, pos);
849 1 : ss << "~";
850 :
851 : // so far, no error
852 1 : VERIFY_ERRORS("");
853 :
854 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::PRECEDED));
855 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
856 :
857 : // make sure we got the expected error
858 1 : VERIFY_ERRORS("");
859 1 : }
860 :
861 : // '+' -> ADD
862 : {
863 1 : std::stringstream ss;
864 3 : csspp::position pos("test.css");
865 1 : csspp::lexer l(ss, pos);
866 1 : ss << "+";
867 :
868 : // so far, no error
869 1 : VERIFY_ERRORS("");
870 :
871 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::ADD));
872 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
873 :
874 : // make sure we got the expected error
875 1 : VERIFY_ERRORS("");
876 1 : }
877 :
878 : // '-' -> SUBTRACT
879 : {
880 1 : std::stringstream ss;
881 3 : csspp::position pos("test.css");
882 1 : csspp::lexer l(ss, pos);
883 1 : ss << "-";
884 :
885 : // so far, no error
886 1 : VERIFY_ERRORS("");
887 :
888 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::SUBTRACT));
889 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
890 :
891 : // make sure we got the expected error
892 1 : VERIFY_ERRORS("");
893 1 : }
894 :
895 : // '|' -> SCOPE
896 : {
897 1 : std::stringstream ss;
898 3 : csspp::position pos("test.css");
899 1 : csspp::lexer l(ss, pos);
900 1 : ss << "|";
901 :
902 : // so far, no error
903 1 : VERIFY_ERRORS("");
904 :
905 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::SCOPE));
906 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
907 :
908 : // make sure we got the expected error
909 1 : VERIFY_ERRORS("");
910 1 : }
911 :
912 : // '>' -> GREATER_THAN
913 : {
914 1 : std::stringstream ss;
915 3 : csspp::position pos("test.css");
916 1 : csspp::lexer l(ss, pos);
917 1 : ss << ">";
918 :
919 : // so far, no error
920 1 : VERIFY_ERRORS("");
921 :
922 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::GREATER_THAN));
923 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
924 :
925 : // make sure we got the expected error
926 1 : VERIFY_ERRORS("");
927 1 : }
928 :
929 : // '>=' -> GREATER_EQUAL
930 : {
931 1 : std::stringstream ss;
932 3 : csspp::position pos("test.css");
933 1 : csspp::lexer l(ss, pos);
934 1 : ss << ">=";
935 :
936 : // so far, no error
937 1 : VERIFY_ERRORS("");
938 :
939 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::GREATER_EQUAL));
940 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
941 :
942 : // make sure we got the expected error
943 1 : VERIFY_ERRORS("");
944 1 : }
945 :
946 : // "<"
947 : {
948 1 : std::stringstream ss;
949 1 : ss << '<';
950 3 : csspp::position pos("test.css");
951 1 : csspp::lexer l(ss, pos);
952 :
953 : // so far, no error
954 1 : VERIFY_ERRORS("");
955 :
956 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::LESS_THAN));
957 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
958 :
959 : // make sure we got the expected error
960 1 : VERIFY_ERRORS("");
961 1 : }
962 :
963 : // "<="
964 : {
965 1 : std::stringstream ss;
966 1 : ss << '<' << '=';
967 3 : csspp::position pos("test.css");
968 1 : csspp::lexer l(ss, pos);
969 :
970 : // so far, no error
971 1 : VERIFY_ERRORS("");
972 :
973 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::LESS_EQUAL));
974 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
975 :
976 : // make sure we got the expected error
977 1 : VERIFY_ERRORS("");
978 1 : }
979 :
980 : // "<!" -- (special case because of "<!--")
981 : {
982 1 : std::stringstream ss;
983 1 : ss << '<' << '!';
984 3 : csspp::position pos("test.css");
985 1 : csspp::lexer l(ss, pos);
986 :
987 : // so far, no error
988 1 : VERIFY_ERRORS("");
989 :
990 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::LESS_THAN));
991 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EXCLAMATION));
992 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
993 :
994 : // make sure we got the expected error
995 1 : VERIFY_ERRORS("");
996 1 : }
997 :
998 : // "<!-" -- (special case because of "<!--")
999 : {
1000 1 : std::stringstream ss;
1001 1 : ss << '<' << '!' << '-';
1002 3 : csspp::position pos("test.css");
1003 1 : csspp::lexer l(ss, pos);
1004 :
1005 : // so far, no error
1006 1 : VERIFY_ERRORS("");
1007 :
1008 : // The '<' is returned as LESS_THAN
1009 : // The '!' is returned as EXCLAMATION
1010 : // The '-' is returned as SUBTRACT
1011 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::LESS_THAN));
1012 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EXCLAMATION));
1013 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::SUBTRACT));
1014 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1015 :
1016 : // make sure we got the expected error
1017 1 : VERIFY_ERRORS("");
1018 1 : }
1019 :
1020 : // "!"
1021 : {
1022 1 : std::stringstream ss;
1023 1 : ss << '!';
1024 3 : csspp::position pos("test.css");
1025 1 : csspp::lexer l(ss, pos);
1026 :
1027 : // so far, no error
1028 1 : VERIFY_ERRORS("");
1029 :
1030 : // The '!' is returned as EXCLAMATION
1031 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EXCLAMATION));
1032 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1033 :
1034 : // make sure we got the expected error
1035 1 : VERIFY_ERRORS("");
1036 1 : }
1037 :
1038 : // "!="
1039 : {
1040 1 : std::stringstream ss;
1041 1 : ss << '!' << '=';
1042 3 : csspp::position pos("test.css");
1043 1 : csspp::lexer l(ss, pos);
1044 :
1045 : // so far, no error
1046 1 : VERIFY_ERRORS("");
1047 :
1048 : // The '!=' is returned as NOT_EQUAL
1049 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::NOT_EQUAL));
1050 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1051 :
1052 : // make sure we got the expected error
1053 1 : VERIFY_ERRORS("");
1054 1 : }
1055 :
1056 : // '(' -> OPEN_PARENTHESIS
1057 : {
1058 1 : std::stringstream ss;
1059 3 : csspp::position pos("test.css");
1060 1 : csspp::lexer l(ss, pos);
1061 1 : ss << "(";
1062 :
1063 : // so far, no error
1064 1 : VERIFY_ERRORS("");
1065 :
1066 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::OPEN_PARENTHESIS));
1067 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1068 :
1069 : // make sure we got the expected error
1070 1 : VERIFY_ERRORS("");
1071 1 : }
1072 :
1073 : // ')' -> OPEN_PARENTHESIS
1074 : {
1075 1 : std::stringstream ss;
1076 3 : csspp::position pos("test.css");
1077 1 : csspp::lexer l(ss, pos);
1078 1 : ss << ")";
1079 :
1080 : // so far, no error
1081 1 : VERIFY_ERRORS("");
1082 :
1083 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::CLOSE_PARENTHESIS));
1084 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1085 :
1086 : // make sure we got the expected error
1087 1 : VERIFY_ERRORS("");
1088 1 : }
1089 :
1090 : // '{' -> OPEN_CURLYBRACKET
1091 : {
1092 1 : std::stringstream ss;
1093 3 : csspp::position pos("test.css");
1094 1 : csspp::lexer l(ss, pos);
1095 1 : ss << "{";
1096 :
1097 : // so far, no error
1098 1 : VERIFY_ERRORS("");
1099 :
1100 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::OPEN_CURLYBRACKET));
1101 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1102 :
1103 : // make sure we got the expected error
1104 1 : VERIFY_ERRORS("");
1105 1 : }
1106 :
1107 : // '}' -> OPEN_CURLYBRACKET
1108 : {
1109 1 : std::stringstream ss;
1110 3 : csspp::position pos("test.css");
1111 1 : csspp::lexer l(ss, pos);
1112 1 : ss << "}";
1113 :
1114 : // so far, no error
1115 1 : VERIFY_ERRORS("");
1116 :
1117 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::CLOSE_CURLYBRACKET));
1118 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1119 :
1120 : // make sure we got the expected error
1121 1 : VERIFY_ERRORS("");
1122 1 : }
1123 :
1124 : // '[' -> OPEN_SQUAREBRACKET
1125 : {
1126 1 : std::stringstream ss;
1127 3 : csspp::position pos("test.css");
1128 1 : csspp::lexer l(ss, pos);
1129 1 : ss << "[";
1130 :
1131 : // so far, no error
1132 1 : VERIFY_ERRORS("");
1133 :
1134 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::OPEN_SQUAREBRACKET));
1135 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1136 :
1137 : // make sure we got the expected error
1138 1 : VERIFY_ERRORS("");
1139 1 : }
1140 :
1141 : // ']' -> OPEN_SQUAREBRACKET
1142 : {
1143 1 : std::stringstream ss;
1144 3 : csspp::position pos("test.css");
1145 1 : csspp::lexer l(ss, pos);
1146 1 : ss << "]";
1147 :
1148 : // so far, no error
1149 1 : VERIFY_ERRORS("");
1150 :
1151 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::CLOSE_SQUAREBRACKET));
1152 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1153 :
1154 : // make sure we got the expected error
1155 1 : VERIFY_ERRORS("");
1156 1 : }
1157 :
1158 : // '<!--' -> CDO
1159 : {
1160 1 : std::stringstream ss;
1161 3 : csspp::position pos("test.css");
1162 1 : csspp::lexer l(ss, pos);
1163 1 : ss << "<!--";
1164 :
1165 : // so far, no error
1166 1 : VERIFY_ERRORS("");
1167 :
1168 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::CDO));
1169 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1170 :
1171 : // make sure we got the expected error
1172 1 : VERIFY_ERRORS("");
1173 1 : }
1174 :
1175 : // '<!--' -> CDC
1176 : {
1177 1 : std::stringstream ss;
1178 3 : csspp::position pos("test.css");
1179 1 : csspp::lexer l(ss, pos);
1180 1 : ss << "-->";
1181 :
1182 : // so far, no error
1183 1 : VERIFY_ERRORS("");
1184 :
1185 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::CDC));
1186 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1187 :
1188 : // make sure we got the expected error
1189 1 : VERIFY_ERRORS("");
1190 1 : }
1191 :
1192 : // '^=' -> PREFIX_MATCH
1193 : {
1194 1 : std::stringstream ss;
1195 3 : csspp::position pos("test.css");
1196 1 : csspp::lexer l(ss, pos);
1197 1 : ss << "^=";
1198 :
1199 : // so far, no error
1200 1 : VERIFY_ERRORS("");
1201 :
1202 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::PREFIX_MATCH));
1203 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1204 :
1205 : // make sure we got the expected error
1206 1 : VERIFY_ERRORS("");
1207 1 : }
1208 :
1209 : // '|=' -> DASH_MATCH
1210 : {
1211 1 : std::stringstream ss;
1212 3 : csspp::position pos("test.css");
1213 1 : csspp::lexer l(ss, pos);
1214 1 : ss << "|=";
1215 :
1216 : // so far, no error
1217 1 : VERIFY_ERRORS("");
1218 :
1219 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::DASH_MATCH));
1220 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1221 :
1222 : // make sure we got the expected error
1223 1 : VERIFY_ERRORS("");
1224 1 : }
1225 :
1226 : // '$=' -> SUFFIX_MATCH
1227 : {
1228 1 : std::stringstream ss;
1229 3 : csspp::position pos("test.css");
1230 1 : csspp::lexer l(ss, pos);
1231 1 : ss << "$=";
1232 :
1233 : // so far, no error
1234 1 : VERIFY_ERRORS("");
1235 :
1236 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::SUFFIX_MATCH));
1237 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1238 :
1239 : // make sure we got the expected error
1240 1 : VERIFY_ERRORS("");
1241 1 : }
1242 :
1243 : // '~=' -> INCLUDE_MATCH
1244 : {
1245 1 : std::stringstream ss;
1246 3 : csspp::position pos("test.css");
1247 1 : csspp::lexer l(ss, pos);
1248 1 : ss << "~=";
1249 :
1250 : // so far, no error
1251 1 : VERIFY_ERRORS("");
1252 :
1253 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::INCLUDE_MATCH));
1254 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1255 :
1256 : // make sure we got the expected error
1257 1 : VERIFY_ERRORS("");
1258 1 : }
1259 :
1260 : // '*=' -> SUBSTRING_MATCH
1261 : {
1262 1 : std::stringstream ss;
1263 3 : csspp::position pos("test.css");
1264 1 : csspp::lexer l(ss, pos);
1265 1 : ss << "*=";
1266 :
1267 : // so far, no error
1268 1 : VERIFY_ERRORS("");
1269 :
1270 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::SUBSTRING_MATCH));
1271 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1272 :
1273 : // make sure we got the expected error
1274 1 : VERIFY_ERRORS("");
1275 1 : }
1276 :
1277 : // ':=' -> ASSIGNMENT
1278 : {
1279 1 : std::stringstream ss;
1280 3 : csspp::position pos("test.css");
1281 1 : csspp::lexer l(ss, pos);
1282 1 : ss << ":=";
1283 :
1284 : // so far, no error
1285 1 : VERIFY_ERRORS("");
1286 :
1287 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::ASSIGNMENT));
1288 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1289 :
1290 : // make sure we got the expected error
1291 1 : VERIFY_ERRORS("");
1292 1 : }
1293 :
1294 : // '||' -> COLUMN
1295 : {
1296 1 : std::stringstream ss;
1297 3 : csspp::position pos("test.css");
1298 1 : csspp::lexer l(ss, pos);
1299 1 : ss << "||";
1300 :
1301 : // so far, no error
1302 1 : VERIFY_ERRORS("");
1303 :
1304 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::COLUMN));
1305 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1306 :
1307 : // make sure we got the expected error
1308 1 : VERIFY_ERRORS("");
1309 1 : }
1310 :
1311 : // A "special" sequence div+.alpha
1312 : {
1313 1 : std::stringstream ss;
1314 3 : csspp::position pos("test.css");
1315 1 : csspp::lexer l(ss, pos);
1316 1 : ss << "div+.alpha";
1317 :
1318 : // so far, no error
1319 1 : VERIFY_ERRORS("");
1320 :
1321 1 : csspp::node::pointer_t div(l.next_token());
1322 1 : CATCH_REQUIRE(div->is(csspp::node_type_t::IDENTIFIER));
1323 1 : CATCH_REQUIRE(div->get_string() == "div");
1324 :
1325 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::ADD));
1326 :
1327 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::PERIOD));
1328 :
1329 1 : csspp::node::pointer_t alpha(l.next_token());
1330 1 : CATCH_REQUIRE(alpha->is(csspp::node_type_t::IDENTIFIER));
1331 1 : CATCH_REQUIRE(alpha->get_string() == "alpha");
1332 :
1333 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1334 :
1335 : // make sure we got the expected error
1336 1 : VERIFY_ERRORS("");
1337 1 : }
1338 :
1339 : // A "special" sequence div -.alpha
1340 : {
1341 1 : std::stringstream ss;
1342 3 : csspp::position pos("test.css");
1343 1 : csspp::lexer l(ss, pos);
1344 1 : ss << "div -.alpha";
1345 :
1346 : // so far, no error
1347 1 : VERIFY_ERRORS("");
1348 :
1349 1 : csspp::node::pointer_t div(l.next_token());
1350 1 : CATCH_REQUIRE(div->is(csspp::node_type_t::IDENTIFIER));
1351 1 : CATCH_REQUIRE(div->get_string() == "div");
1352 :
1353 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::WHITESPACE));
1354 :
1355 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::SUBTRACT));
1356 :
1357 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::PERIOD));
1358 :
1359 1 : csspp::node::pointer_t alpha(l.next_token());
1360 1 : CATCH_REQUIRE(alpha->is(csspp::node_type_t::IDENTIFIER));
1361 1 : CATCH_REQUIRE(alpha->get_string() == "alpha");
1362 :
1363 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1364 :
1365 : // make sure we got the expected error
1366 1 : VERIFY_ERRORS("");
1367 1 : }
1368 :
1369 : // no error left over
1370 1 : VERIFY_ERRORS("");
1371 1 : }
1372 :
1373 1 : CATCH_TEST_CASE("Newline", "[lexer] [newline] [characters]")
1374 : {
1375 : // we have a special case with '\r' followed by a character
1376 : // other than '\n'
1377 1113985 : for(csspp::wide_char_t i(0x80); i < 0x110000; ++i)
1378 : {
1379 1113984 : switch(i)
1380 : {
1381 35 : case 0xFFFD:
1382 : case 0x00FFFE:
1383 : case 0x00FFFF:
1384 : case 0x01FFFE:
1385 : case 0x01FFFF:
1386 : case 0x02FFFE:
1387 : case 0x02FFFF:
1388 : case 0x03FFFE:
1389 : case 0x03FFFF:
1390 : case 0x04FFFE:
1391 : case 0x04FFFF:
1392 : case 0x05FFFE:
1393 : case 0x05FFFF:
1394 : case 0x06FFFE:
1395 : case 0x06FFFF:
1396 : case 0x07FFFE:
1397 : case 0x07FFFF:
1398 : case 0x08FFFE:
1399 : case 0x08FFFF:
1400 : case 0x09FFFE:
1401 : case 0x09FFFF:
1402 : case 0x0AFFFE:
1403 : case 0x0AFFFF:
1404 : case 0x0BFFFE:
1405 : case 0x0BFFFF:
1406 : case 0x0CFFFE:
1407 : case 0x0CFFFF:
1408 : case 0x0DFFFE:
1409 : case 0x0DFFFF:
1410 : case 0x0EFFFE:
1411 : case 0x0EFFFF:
1412 : case 0x0FFFFE:
1413 : case 0x0FFFFF:
1414 : case 0x10FFFE:
1415 : case 0x10FFFF:
1416 : // skip on characters that are either invalid or generate
1417 : // a "problem" (i.e. spaces get trimmed)
1418 35 : continue;
1419 :
1420 1113949 : default:
1421 1113949 : if(i >= 0xD800 && i <= 0xDFFF)
1422 : {
1423 2048 : continue;
1424 : }
1425 1111901 : break;
1426 :
1427 : }
1428 :
1429 2223802 : std::stringstream ss;
1430 4447604 : csspp::position pos("test.css");
1431 2223802 : csspp::lexer l(ss, pos);
1432 2223802 : ss << '\r' << l.wctomb(i)
1433 2223802 : << '\n' << l.wctomb(i)
1434 2223802 : << '\f' << l.wctomb(i)
1435 2223802 : << "\r\n" << l.wctomb(i)
1436 5559505 : << "\n\r" << l.wctomb(i);
1437 :
1438 2223802 : std::stringstream out;
1439 1111901 : out << l.wctomb(i);
1440 :
1441 : // character on the second line (\r char)
1442 : {
1443 : // check the whitespace
1444 1111901 : csspp::node::pointer_t whitespace(l.next_token());
1445 1111901 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
1446 1111901 : csspp::position const & npos(whitespace->get_position());
1447 1111901 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1448 1111901 : CATCH_REQUIRE(npos.get_page() == 1);
1449 1111901 : CATCH_REQUIRE(npos.get_line() == 1);
1450 1111901 : CATCH_REQUIRE(npos.get_total_line() == 1);
1451 1111901 : }
1452 :
1453 : // make sure the next character is viewed as an identifier
1454 : // just as expected
1455 : {
1456 1111901 : csspp::node::pointer_t identifier(l.next_token());
1457 1111901 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
1458 1111901 : CATCH_REQUIRE(identifier->get_string() == out.str());
1459 1111901 : csspp::position const & npos(identifier->get_position());
1460 1111901 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1461 1111901 : CATCH_REQUIRE(npos.get_page() == 1);
1462 1111901 : CATCH_REQUIRE(npos.get_line() == 2);
1463 1111901 : CATCH_REQUIRE(npos.get_total_line() == 2);
1464 1111901 : }
1465 :
1466 : // character on the second line (\n char)
1467 : {
1468 : // check the whitespace
1469 1111901 : csspp::node::pointer_t whitespace(l.next_token());
1470 1111901 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
1471 1111901 : csspp::position const & npos(whitespace->get_position());
1472 1111901 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1473 1111901 : CATCH_REQUIRE(npos.get_page() == 1);
1474 1111901 : CATCH_REQUIRE(npos.get_line() == 3);
1475 1111901 : CATCH_REQUIRE(npos.get_total_line() == 3);
1476 1111901 : }
1477 :
1478 : // make sure the next character is viewed as an identifier
1479 : // just as expected
1480 : {
1481 1111901 : csspp::node::pointer_t identifier(l.next_token());
1482 1111901 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
1483 1111901 : CATCH_REQUIRE(identifier->get_string() == out.str());
1484 1111901 : csspp::position const & npos(identifier->get_position());
1485 1111901 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1486 1111901 : CATCH_REQUIRE(npos.get_page() == 1);
1487 1111901 : CATCH_REQUIRE(npos.get_line() == 3);
1488 1111901 : CATCH_REQUIRE(npos.get_total_line() == 3);
1489 1111901 : }
1490 :
1491 : // character on the second line (\f char)
1492 : {
1493 : // check the whitespace
1494 1111901 : csspp::node::pointer_t whitespace(l.next_token());
1495 1111901 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
1496 1111901 : csspp::position const & npos(whitespace->get_position());
1497 1111901 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1498 1111901 : CATCH_REQUIRE(npos.get_page() == 2);
1499 1111901 : CATCH_REQUIRE(npos.get_line() == 1);
1500 1111901 : CATCH_REQUIRE(npos.get_total_line() == 3);
1501 1111901 : }
1502 :
1503 : // make sure the next character is viewed as an identifier
1504 : // just as expected
1505 : {
1506 1111901 : csspp::node::pointer_t identifier(l.next_token());
1507 1111901 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
1508 1111901 : CATCH_REQUIRE(identifier->get_string() == out.str());
1509 1111901 : csspp::position const & npos(identifier->get_position());
1510 1111901 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1511 1111901 : CATCH_REQUIRE(npos.get_page() == 2);
1512 1111901 : CATCH_REQUIRE(npos.get_line() == 1);
1513 1111901 : CATCH_REQUIRE(npos.get_total_line() == 3);
1514 1111901 : }
1515 :
1516 : // character on the second line (\r\n char)
1517 : {
1518 : // check the whitespace
1519 1111901 : csspp::node::pointer_t whitespace(l.next_token());
1520 1111901 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
1521 1111901 : csspp::position const & npos(whitespace->get_position());
1522 1111901 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1523 1111901 : CATCH_REQUIRE(npos.get_page() == 2);
1524 1111901 : CATCH_REQUIRE(npos.get_line() == 2);
1525 1111901 : CATCH_REQUIRE(npos.get_total_line() == 4);
1526 1111901 : }
1527 :
1528 : // make sure the next character is viewed as an identifier
1529 : // just as expected
1530 : {
1531 1111901 : csspp::node::pointer_t identifier(l.next_token());
1532 1111901 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
1533 1111901 : CATCH_REQUIRE(identifier->get_string() == out.str());
1534 1111901 : csspp::position const & npos(identifier->get_position());
1535 1111901 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1536 1111901 : CATCH_REQUIRE(npos.get_page() == 2);
1537 1111901 : CATCH_REQUIRE(npos.get_line() == 2);
1538 1111901 : CATCH_REQUIRE(npos.get_total_line() == 4);
1539 1111901 : }
1540 :
1541 : // character on the second line (\n\r char)
1542 : {
1543 : // check the whitespace
1544 1111901 : csspp::node::pointer_t whitespace(l.next_token());
1545 1111901 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
1546 1111901 : csspp::position const & npos(whitespace->get_position());
1547 1111901 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1548 1111901 : CATCH_REQUIRE(npos.get_page() == 2);
1549 1111901 : CATCH_REQUIRE(npos.get_line() == 3);
1550 1111901 : CATCH_REQUIRE(npos.get_total_line() == 5);
1551 1111901 : }
1552 :
1553 : // make sure the next character is viewed as an identifier
1554 : // just as expected
1555 : {
1556 1111901 : csspp::node::pointer_t identifier(l.next_token());
1557 1111901 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
1558 1111901 : CATCH_REQUIRE(identifier->get_string() == out.str());
1559 1111901 : csspp::position const & npos(identifier->get_position());
1560 1111901 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1561 1111901 : CATCH_REQUIRE(npos.get_page() == 2);
1562 1111901 : CATCH_REQUIRE(npos.get_line() == 4);
1563 1111901 : CATCH_REQUIRE(npos.get_total_line() == 6);
1564 1111901 : }
1565 :
1566 1111901 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1567 : }
1568 :
1569 : // no error left over
1570 1 : VERIFY_ERRORS("");
1571 1 : }
1572 :
1573 1 : CATCH_TEST_CASE("C-like comments", "[lexer] [comment]")
1574 : {
1575 : // a comment without @preserve gets lost
1576 : {
1577 1 : std::stringstream ss;
1578 1 : ss << "/* test simple comment */";
1579 3 : csspp::position pos("test.css");
1580 1 : csspp::lexer l(ss, pos);
1581 :
1582 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1583 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1584 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1585 1 : }
1586 :
1587 : // one simple comment
1588 : {
1589 1 : std::stringstream ss;
1590 1 : ss << "/* test simple comment @preserve */";
1591 3 : csspp::position pos("test.css");
1592 1 : csspp::lexer l(ss, pos);
1593 :
1594 : // comment
1595 : {
1596 1 : csspp::node::pointer_t comment(l.next_token());
1597 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
1598 1 : CATCH_REQUIRE(comment->get_string() == "test simple comment @preserve");
1599 1 : CATCH_REQUIRE(comment->get_integer() == 1); // C-like comment
1600 1 : csspp::position const & npos(comment->get_position());
1601 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1602 1 : CATCH_REQUIRE(npos.get_page() == 1);
1603 1 : CATCH_REQUIRE(npos.get_line() == 1);
1604 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
1605 1 : }
1606 :
1607 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1608 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1609 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1610 1 : }
1611 :
1612 : // an unterminated simple comment
1613 : {
1614 1 : std::stringstream ss;
1615 1 : ss << "/* test simple comment @preserve";
1616 3 : csspp::position pos("test.css");
1617 1 : csspp::lexer l(ss, pos);
1618 :
1619 : // comment
1620 : {
1621 1 : csspp::node::pointer_t comment(l.next_token());
1622 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
1623 1 : CATCH_REQUIRE(comment->get_string() == "test simple comment @preserve");
1624 1 : CATCH_REQUIRE(comment->get_integer() == 1); // C-like comment
1625 1 : csspp::position const & npos(comment->get_position());
1626 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1627 1 : CATCH_REQUIRE(npos.get_page() == 1);
1628 1 : CATCH_REQUIRE(npos.get_line() == 1);
1629 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
1630 1 : }
1631 :
1632 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1633 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1634 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1635 :
1636 1 : VERIFY_ERRORS("test.css(1): error: unclosed C-like comment at the end of your document.\n");
1637 1 : }
1638 :
1639 : // a comment on multiple lines
1640 : {
1641 1 : std::stringstream ss;
1642 1 : ss << "/* test\na\r\nmulti-line\fcomment\n\rtoo @preserve */\n";
1643 3 : csspp::position pos("test.css");
1644 1 : csspp::lexer l(ss, pos);
1645 :
1646 : // comment
1647 : {
1648 1 : csspp::node::pointer_t comment(l.next_token());
1649 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
1650 1 : CATCH_REQUIRE(comment->get_string() == "test\na\nmulti-line\ncomment\n\ntoo @preserve");
1651 1 : CATCH_REQUIRE(comment->get_integer() == 1); // C-like comment
1652 1 : csspp::position const & npos(comment->get_position());
1653 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1654 1 : CATCH_REQUIRE(npos.get_page() == 1);
1655 1 : CATCH_REQUIRE(npos.get_line() == 1);
1656 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
1657 1 : }
1658 :
1659 : // whitespace
1660 : {
1661 1 : csspp::node::pointer_t whitespace(l.next_token());
1662 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
1663 1 : csspp::position const & npos(whitespace->get_position());
1664 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1665 1 : CATCH_REQUIRE(npos.get_page() == 2);
1666 1 : CATCH_REQUIRE(npos.get_line() == 3);
1667 1 : CATCH_REQUIRE(npos.get_total_line() == 5);
1668 1 : }
1669 :
1670 : // EOF
1671 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1672 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1673 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1674 1 : }
1675 :
1676 : // one multi-line comment followed by another simple comment
1677 : {
1678 1 : std::stringstream ss;
1679 1 : ss << "/* test\na\r\nmulti-line\fcomment\n\rtoo @preserve */\n/* with a second comment @preserve */";
1680 3 : csspp::position pos("test.css");
1681 1 : csspp::lexer l(ss, pos);
1682 :
1683 : // 1st comment
1684 : {
1685 1 : csspp::node::pointer_t comment1(l.next_token());
1686 1 : CATCH_REQUIRE(comment1->is(csspp::node_type_t::COMMENT));
1687 1 : CATCH_REQUIRE(comment1->get_string() == "test\na\nmulti-line\ncomment\n\ntoo @preserve");
1688 1 : CATCH_REQUIRE(comment1->get_integer() == 1); // C-like comment
1689 1 : csspp::position const & npos(comment1->get_position());
1690 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1691 1 : CATCH_REQUIRE(npos.get_page() == 1);
1692 1 : CATCH_REQUIRE(npos.get_line() == 1);
1693 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
1694 1 : }
1695 :
1696 : // whitespace in between
1697 : {
1698 1 : csspp::node::pointer_t whitespace(l.next_token());
1699 1 : csspp::position const & npos(whitespace->get_position());
1700 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1701 1 : CATCH_REQUIRE(npos.get_page() == 2);
1702 1 : CATCH_REQUIRE(npos.get_line() == 3);
1703 1 : CATCH_REQUIRE(npos.get_total_line() == 5);
1704 1 : }
1705 :
1706 : // 2nd comment
1707 : {
1708 1 : csspp::node::pointer_t comment(l.next_token());
1709 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
1710 1 : CATCH_REQUIRE(comment->get_string() == "with a second comment @preserve");
1711 1 : CATCH_REQUIRE(comment->get_integer() == 1); // C-like comment
1712 1 : csspp::position const & npos(comment->get_position());
1713 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1714 1 : CATCH_REQUIRE(npos.get_page() == 2);
1715 1 : CATCH_REQUIRE(npos.get_line() == 4);
1716 1 : CATCH_REQUIRE(npos.get_total_line() == 6);
1717 1 : }
1718 :
1719 : // EOF
1720 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1721 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1722 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1723 1 : }
1724 :
1725 : // test with all types of characters that are considered valid by
1726 : // our code
1727 : {
1728 1114112 : for(csspp::wide_char_t i(1); i < 0x110000; ++i)
1729 : {
1730 1114111 : switch(i)
1731 : {
1732 40 : case ' ':
1733 : case '\t':
1734 : case '\n':
1735 : case '\r':
1736 : case '\f':
1737 : case '\0':
1738 : case 0xFFFD:
1739 : case 0x00FFFE:
1740 : case 0x00FFFF:
1741 : case 0x01FFFE:
1742 : case 0x01FFFF:
1743 : case 0x02FFFE:
1744 : case 0x02FFFF:
1745 : case 0x03FFFE:
1746 : case 0x03FFFF:
1747 : case 0x04FFFE:
1748 : case 0x04FFFF:
1749 : case 0x05FFFE:
1750 : case 0x05FFFF:
1751 : case 0x06FFFE:
1752 : case 0x06FFFF:
1753 : case 0x07FFFE:
1754 : case 0x07FFFF:
1755 : case 0x08FFFE:
1756 : case 0x08FFFF:
1757 : case 0x09FFFE:
1758 : case 0x09FFFF:
1759 : case 0x0AFFFE:
1760 : case 0x0AFFFF:
1761 : case 0x0BFFFE:
1762 : case 0x0BFFFF:
1763 : case 0x0CFFFE:
1764 : case 0x0CFFFF:
1765 : case 0x0DFFFE:
1766 : case 0x0DFFFF:
1767 : case 0x0EFFFE:
1768 : case 0x0EFFFF:
1769 : case 0x0FFFFE:
1770 : case 0x0FFFFF:
1771 : case 0x10FFFE:
1772 : case 0x10FFFF:
1773 : // skip on characters that are either invalid or generate
1774 : // a "problem" (i.e. spaces get trimmed)
1775 40 : continue;
1776 :
1777 1114071 : default:
1778 1114071 : if(i >= 0xD800 && i <= 0xDFFF)
1779 : {
1780 2048 : continue;
1781 : }
1782 1112023 : break;
1783 :
1784 : }
1785 :
1786 2224046 : std::stringstream ss;
1787 1112023 : char mb[6];
1788 4448092 : csspp::position pos("test.css");
1789 2224046 : csspp::lexer l(ss, pos);
1790 1112023 : l.wctomb(i, mb, sizeof(mb) / sizeof(mb[0]));
1791 : //std::cerr << "testing with " << i << "\n";
1792 : //for(int j(0); mb[j] != '\0'; ++j) std::cerr << " " << j << ". " << std::hex << static_cast<int>(static_cast<unsigned char>(mb[j])) << std::dec << "\n";
1793 3336069 : std::string cmt("character: ");
1794 1112023 : cmt += mb;
1795 1112023 : ss << "/* " << cmt << " @preserve */";
1796 :
1797 : // comment
1798 : {
1799 1112023 : csspp::node::pointer_t comment(l.next_token());
1800 1112023 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
1801 1112023 : CATCH_REQUIRE(comment->get_string() == cmt + " @preserve");
1802 1112023 : CATCH_REQUIRE(comment->get_integer() == 1); // C-like comment
1803 1112023 : csspp::position const & npos(comment->get_position());
1804 1112023 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1805 1112023 : CATCH_REQUIRE(npos.get_page() == 1);
1806 1112023 : CATCH_REQUIRE(npos.get_line() == 1);
1807 1112023 : CATCH_REQUIRE(npos.get_total_line() == 1);
1808 1112023 : }
1809 :
1810 1112023 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1811 1112023 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1812 1112023 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1813 : }
1814 : }
1815 :
1816 : // no error left over
1817 1 : VERIFY_ERRORS("");
1818 1 : }
1819 :
1820 1 : CATCH_TEST_CASE("C++ comments", "[lexer] [comment]")
1821 : {
1822 : // a comment without @preserve gets lost
1823 : {
1824 1 : std::stringstream ss;
1825 1 : ss << "// test simple comment\r\n";
1826 3 : csspp::position pos("test.css");
1827 1 : csspp::lexer l(ss, pos);
1828 :
1829 : // whitespace
1830 : {
1831 1 : csspp::node::pointer_t whitespace(l.next_token());
1832 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
1833 1 : csspp::position const & npos(whitespace->get_position());
1834 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1835 1 : CATCH_REQUIRE(npos.get_page() == 1);
1836 1 : CATCH_REQUIRE(npos.get_line() == 2);
1837 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
1838 1 : }
1839 :
1840 : // EOF
1841 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1842 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1843 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1844 :
1845 : // no error left over
1846 1 : VERIFY_ERRORS("");
1847 1 : }
1848 :
1849 : // one simple comment
1850 : {
1851 1 : std::stringstream ss;
1852 1 : ss << "// test simple comment @preserve\r\n";
1853 3 : csspp::position pos("test.css");
1854 1 : csspp::lexer l(ss, pos);
1855 :
1856 : // comment
1857 : {
1858 1 : csspp::node::pointer_t comment(l.next_token());
1859 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
1860 1 : CATCH_REQUIRE(comment->get_string() == "test simple comment @preserve");
1861 1 : CATCH_REQUIRE(comment->get_integer() == 0); // C++ comment
1862 1 : csspp::position const & npos(comment->get_position());
1863 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1864 1 : CATCH_REQUIRE(npos.get_page() == 1);
1865 1 : CATCH_REQUIRE(npos.get_line() == 1);
1866 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
1867 :
1868 1 : VERIFY_ERRORS("test.css(1): warning: C++ comments should not be preserved as they are not supported by most CSS parsers.\n");
1869 1 : }
1870 :
1871 : // whitespace
1872 : {
1873 1 : csspp::node::pointer_t whitespace(l.next_token());
1874 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
1875 1 : csspp::position const & npos(whitespace->get_position());
1876 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1877 1 : CATCH_REQUIRE(npos.get_page() == 1);
1878 1 : CATCH_REQUIRE(npos.get_line() == 2);
1879 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
1880 1 : }
1881 :
1882 : // EOF
1883 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1884 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1885 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1886 :
1887 : // no error left over
1888 1 : VERIFY_ERRORS("");
1889 1 : }
1890 :
1891 : // a C++ comment on multiple lines is just a comment
1892 : // that is followed by a number of other C++ comments
1893 : {
1894 1 : std::stringstream ss;
1895 1 : ss << "// test\n// a\r\n// multi-line\f//comment\r//\ttoo @preserve\n";
1896 3 : csspp::position pos("test.css");
1897 1 : csspp::lexer l(ss, pos);
1898 :
1899 : // comment
1900 : {
1901 1 : csspp::node::pointer_t comment(l.next_token());
1902 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
1903 1 : CATCH_REQUIRE(comment->get_string() == "test\na\nmulti-line\ncomment\ntoo @preserve");
1904 1 : CATCH_REQUIRE(comment->get_integer() == 0); // C++ comment
1905 1 : csspp::position const & npos(comment->get_position());
1906 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1907 1 : CATCH_REQUIRE(npos.get_page() == 1);
1908 1 : CATCH_REQUIRE(npos.get_line() == 1);
1909 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
1910 :
1911 1 : VERIFY_ERRORS("test.css(1): warning: C++ comments should not be preserved as they are not supported by most CSS parsers.\n");
1912 1 : }
1913 :
1914 : // whitespace
1915 : {
1916 1 : csspp::node::pointer_t whitespace(l.next_token());
1917 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
1918 1 : csspp::position const & npos(whitespace->get_position());
1919 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1920 1 : CATCH_REQUIRE(npos.get_page() == 2);
1921 1 : CATCH_REQUIRE(npos.get_line() == 3);
1922 1 : CATCH_REQUIRE(npos.get_total_line() == 5);
1923 1 : }
1924 :
1925 : // EOF
1926 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1927 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1928 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1929 :
1930 : // no error left over
1931 1 : VERIFY_ERRORS("");
1932 1 : }
1933 :
1934 : // one multi-line comment followed by another simple comment
1935 : {
1936 1 : std::stringstream ss;
1937 1 : ss << "// test\n//\ta\r\n//multi-line\f// comment\r\n// too @preserve\r\n\r\n// with a second comment @preserve";
1938 3 : csspp::position pos("test.css");
1939 1 : csspp::lexer l(ss, pos);
1940 :
1941 : // 1st comment
1942 : {
1943 1 : csspp::node::pointer_t comment(l.next_token());
1944 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
1945 1 : CATCH_REQUIRE(comment->get_string() == "test\na\nmulti-line\ncomment\ntoo @preserve");
1946 1 : CATCH_REQUIRE(comment->get_integer() == 0); // C++ comment
1947 1 : csspp::position const & npos(comment->get_position());
1948 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1949 1 : CATCH_REQUIRE(npos.get_page() == 1);
1950 1 : CATCH_REQUIRE(npos.get_line() == 1);
1951 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
1952 :
1953 1 : VERIFY_ERRORS("test.css(1): warning: C++ comments should not be preserved as they are not supported by most CSS parsers.\n");
1954 1 : }
1955 :
1956 : // whitespace
1957 : {
1958 1 : csspp::node::pointer_t whitespace(l.next_token());
1959 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
1960 1 : csspp::position const & npos(whitespace->get_position());
1961 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1962 1 : CATCH_REQUIRE(npos.get_page() == 2);
1963 1 : CATCH_REQUIRE(npos.get_line() == 4);
1964 1 : CATCH_REQUIRE(npos.get_total_line() == 6);
1965 1 : }
1966 :
1967 : // 2nd comment
1968 : {
1969 1 : csspp::node::pointer_t comment(l.next_token());
1970 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
1971 1 : CATCH_REQUIRE(comment->get_string() == "with a second comment @preserve");
1972 1 : CATCH_REQUIRE(comment->get_integer() == 0); // C++ comment
1973 1 : csspp::position const & npos(comment->get_position());
1974 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
1975 1 : CATCH_REQUIRE(npos.get_page() == 2);
1976 1 : CATCH_REQUIRE(npos.get_line() == 4);
1977 1 : CATCH_REQUIRE(npos.get_total_line() == 6);
1978 :
1979 1 : VERIFY_ERRORS("test.css(4): warning: C++ comments should not be preserved as they are not supported by most CSS parsers.\n");
1980 1 : }
1981 :
1982 : // EOF
1983 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1984 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1985 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
1986 :
1987 : // no error left over
1988 1 : VERIFY_ERRORS("");
1989 1 : }
1990 :
1991 : // one comment nearly multi-line
1992 : {
1993 1 : std::stringstream ss;
1994 1 : ss << "// test comment and @preserve\n/ divide";
1995 3 : csspp::position pos("test.css");
1996 1 : csspp::lexer l(ss, pos);
1997 :
1998 : // comment
1999 : {
2000 1 : csspp::node::pointer_t comment(l.next_token());
2001 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
2002 1 : CATCH_REQUIRE(comment->get_string() == "test comment and @preserve");
2003 1 : CATCH_REQUIRE(comment->get_integer() == 0); // C++ comment
2004 1 : csspp::position const & npos(comment->get_position());
2005 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2006 1 : CATCH_REQUIRE(npos.get_page() == 1);
2007 1 : CATCH_REQUIRE(npos.get_line() == 1);
2008 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2009 :
2010 1 : VERIFY_ERRORS("test.css(1): warning: C++ comments should not be preserved as they are not supported by most CSS parsers.\n");
2011 1 : }
2012 :
2013 : // whitespace
2014 : {
2015 1 : csspp::node::pointer_t whitespace(l.next_token());
2016 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
2017 1 : csspp::position const & npos(whitespace->get_position());
2018 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2019 1 : CATCH_REQUIRE(npos.get_page() == 1);
2020 1 : CATCH_REQUIRE(npos.get_line() == 2);
2021 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2022 1 : }
2023 :
2024 : // divide
2025 : {
2026 1 : csspp::node::pointer_t comment(l.next_token());
2027 1 : CATCH_REQUIRE(comment->is(csspp::node_type_t::DIVIDE));
2028 1 : csspp::position const & npos(comment->get_position());
2029 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2030 1 : CATCH_REQUIRE(npos.get_page() == 1);
2031 1 : CATCH_REQUIRE(npos.get_line() == 2);
2032 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2033 1 : }
2034 :
2035 : // whitespace
2036 : {
2037 1 : csspp::node::pointer_t whitespace(l.next_token());
2038 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
2039 1 : csspp::position const & npos(whitespace->get_position());
2040 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2041 1 : CATCH_REQUIRE(npos.get_page() == 1);
2042 1 : CATCH_REQUIRE(npos.get_line() == 2);
2043 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2044 1 : }
2045 :
2046 : // identifier
2047 : {
2048 1 : csspp::node::pointer_t identifier(l.next_token());
2049 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
2050 1 : CATCH_REQUIRE(identifier->get_string() == "divide");
2051 1 : csspp::position const & npos(identifier->get_position());
2052 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2053 1 : CATCH_REQUIRE(npos.get_page() == 1);
2054 1 : CATCH_REQUIRE(npos.get_line() == 2);
2055 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2056 1 : }
2057 :
2058 : // EOF
2059 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2060 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2061 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2062 :
2063 : // no error left over
2064 1 : VERIFY_ERRORS("");
2065 1 : }
2066 :
2067 : // test with all types of characters that are considered valid by
2068 : // our code
2069 : {
2070 1114112 : for(csspp::wide_char_t i(1); i < 0x110000; ++i)
2071 : {
2072 1114111 : switch(i)
2073 : {
2074 40 : case ' ':
2075 : case '\t':
2076 : case '\n':
2077 : case '\r':
2078 : case '\f':
2079 : case '\0':
2080 : case 0xFFFD:
2081 : case 0x00FFFE:
2082 : case 0x00FFFF:
2083 : case 0x01FFFE:
2084 : case 0x01FFFF:
2085 : case 0x02FFFE:
2086 : case 0x02FFFF:
2087 : case 0x03FFFE:
2088 : case 0x03FFFF:
2089 : case 0x04FFFE:
2090 : case 0x04FFFF:
2091 : case 0x05FFFE:
2092 : case 0x05FFFF:
2093 : case 0x06FFFE:
2094 : case 0x06FFFF:
2095 : case 0x07FFFE:
2096 : case 0x07FFFF:
2097 : case 0x08FFFE:
2098 : case 0x08FFFF:
2099 : case 0x09FFFE:
2100 : case 0x09FFFF:
2101 : case 0x0AFFFE:
2102 : case 0x0AFFFF:
2103 : case 0x0BFFFE:
2104 : case 0x0BFFFF:
2105 : case 0x0CFFFE:
2106 : case 0x0CFFFF:
2107 : case 0x0DFFFE:
2108 : case 0x0DFFFF:
2109 : case 0x0EFFFE:
2110 : case 0x0EFFFF:
2111 : case 0x0FFFFE:
2112 : case 0x0FFFFF:
2113 : case 0x10FFFE:
2114 : case 0x10FFFF:
2115 : // skip on characters that are either invalid or generate
2116 : // a "problem" (i.e. spaces get trimmed)
2117 40 : continue;
2118 :
2119 1114071 : default:
2120 1114071 : if(i >= 0xD800 && i <= 0xDFFF)
2121 : {
2122 2048 : continue;
2123 : }
2124 1112023 : break;
2125 :
2126 : }
2127 :
2128 2224046 : std::stringstream ss;
2129 1112023 : char mb[6];
2130 4448092 : csspp::position pos("test.css");
2131 2224046 : csspp::lexer l(ss, pos);
2132 1112023 : l.wctomb(i, mb, sizeof(mb) / sizeof(mb[0]));
2133 : //std::cerr << "testing with " << i << "\n";
2134 : //for(int j(0); mb[j] != '\0'; ++j) std::cerr << " " << j << ". " << std::hex << static_cast<int>(static_cast<unsigned char>(mb[j])) << std::dec << "\n";
2135 3336069 : std::string cmt("character: ");
2136 1112023 : cmt += mb;
2137 1112023 : ss << "// " << cmt << " @preserve";
2138 :
2139 : // comment
2140 : {
2141 1112023 : csspp::node::pointer_t comment(l.next_token());
2142 1112023 : CATCH_REQUIRE(comment->is(csspp::node_type_t::COMMENT));
2143 1112023 : CATCH_REQUIRE(comment->get_string() == cmt + " @preserve");
2144 1112023 : CATCH_REQUIRE(comment->get_integer() == 0); // C++ comment
2145 1112023 : csspp::position const & npos(comment->get_position());
2146 1112023 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2147 1112023 : CATCH_REQUIRE(npos.get_page() == 1);
2148 1112023 : CATCH_REQUIRE(npos.get_line() == 1);
2149 1112023 : CATCH_REQUIRE(npos.get_total_line() == 1);
2150 :
2151 1112023 : VERIFY_ERRORS("test.css(1): warning: C++ comments should not be preserved as they are not supported by most CSS parsers.\n");
2152 1112023 : }
2153 :
2154 1112023 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2155 1112023 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2156 1112023 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2157 : }
2158 :
2159 : // no error left over
2160 1 : VERIFY_ERRORS("");
2161 : }
2162 1 : }
2163 :
2164 1 : CATCH_TEST_CASE("Strings", "[lexer] [string]")
2165 : {
2166 : // one simple string with "
2167 : {
2168 1 : std::stringstream ss;
2169 1 : ss << "\"";
2170 1 : size_t const len(rand() % 20 + 20);
2171 1 : std::string word;
2172 32 : for(size_t i(0); i < len; ++i)
2173 : {
2174 : // simple ascii letters
2175 31 : int const c(rand() % 26 + 'a');
2176 31 : ss << static_cast<char>(c);
2177 31 : word += static_cast<char>(c);
2178 : }
2179 1 : ss << "\"";
2180 3 : csspp::position pos("test.css");
2181 1 : csspp::lexer l(ss, pos);
2182 :
2183 : // string
2184 : {
2185 1 : csspp::node::pointer_t string(l.next_token());
2186 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2187 1 : CATCH_REQUIRE(string->get_string() == word);
2188 1 : csspp::position const & npos(string->get_position());
2189 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2190 1 : CATCH_REQUIRE(npos.get_page() == 1);
2191 1 : CATCH_REQUIRE(npos.get_line() == 1);
2192 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2193 1 : }
2194 :
2195 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2196 :
2197 : // no error left over
2198 1 : VERIFY_ERRORS("");
2199 1 : }
2200 :
2201 : // one simple string with " and including '
2202 : {
2203 1 : std::stringstream ss;
2204 1 : ss << "\"c'est un teste\"";
2205 3 : csspp::position pos("test.css");
2206 1 : csspp::lexer l(ss, pos);
2207 :
2208 : // string
2209 : {
2210 1 : csspp::node::pointer_t string(l.next_token());
2211 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2212 1 : CATCH_REQUIRE(string->get_string() == "c'est un teste");
2213 1 : csspp::position const & npos(string->get_position());
2214 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2215 1 : CATCH_REQUIRE(npos.get_page() == 1);
2216 1 : CATCH_REQUIRE(npos.get_line() == 1);
2217 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2218 1 : }
2219 :
2220 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2221 :
2222 : // no error left over
2223 1 : VERIFY_ERRORS("");
2224 1 : }
2225 :
2226 : // one simple string with '
2227 : {
2228 1 : std::stringstream ss;
2229 1 : ss << "'";
2230 1 : size_t const len(rand() % 20 + 20);
2231 1 : std::string word;
2232 23 : for(size_t i(0); i < len; ++i)
2233 : {
2234 : // simple ascii letters
2235 22 : int const c(rand() % 26 + 'a');
2236 22 : ss << static_cast<char>(c);
2237 22 : word += static_cast<char>(c);
2238 : }
2239 1 : ss << "'";
2240 3 : csspp::position pos("test.css");
2241 1 : csspp::lexer l(ss, pos);
2242 :
2243 : // string
2244 : {
2245 1 : csspp::node::pointer_t string(l.next_token());
2246 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2247 1 : CATCH_REQUIRE(string->get_string() == word);
2248 1 : csspp::position const & npos(string->get_position());
2249 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2250 1 : CATCH_REQUIRE(npos.get_page() == 1);
2251 1 : CATCH_REQUIRE(npos.get_line() == 1);
2252 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2253 1 : }
2254 :
2255 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2256 :
2257 : // no error left over
2258 1 : VERIFY_ERRORS("");
2259 1 : }
2260 :
2261 : // one simple string with ' including "
2262 : {
2263 1 : std::stringstream ss;
2264 1 : ss << "'This \"word\" sounds wrong!'";
2265 3 : csspp::position pos("test.css");
2266 1 : csspp::lexer l(ss, pos);
2267 :
2268 : // string
2269 : {
2270 1 : csspp::node::pointer_t string(l.next_token());
2271 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2272 1 : CATCH_REQUIRE(string->get_string() == "This \"word\" sounds wrong!");
2273 1 : csspp::position const & npos(string->get_position());
2274 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2275 1 : CATCH_REQUIRE(npos.get_page() == 1);
2276 1 : CATCH_REQUIRE(npos.get_line() == 1);
2277 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2278 1 : }
2279 :
2280 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2281 :
2282 : // no error left over
2283 1 : VERIFY_ERRORS("");
2284 1 : }
2285 :
2286 : // string with escaped characters
2287 : {
2288 1114113 : for(csspp::wide_char_t i(0); i < 0x110000; ++i)
2289 : {
2290 1114112 : switch(i)
2291 : {
2292 41 : case '\0':
2293 : case ' ':
2294 : case '\t':
2295 : case '\n':
2296 : case '\r':
2297 : case '\f':
2298 : case 0xFFFD:
2299 : case 0x00FFFE:
2300 : case 0x00FFFF:
2301 : case 0x01FFFE:
2302 : case 0x01FFFF:
2303 : case 0x02FFFE:
2304 : case 0x02FFFF:
2305 : case 0x03FFFE:
2306 : case 0x03FFFF:
2307 : case 0x04FFFE:
2308 : case 0x04FFFF:
2309 : case 0x05FFFE:
2310 : case 0x05FFFF:
2311 : case 0x06FFFE:
2312 : case 0x06FFFF:
2313 : case 0x07FFFE:
2314 : case 0x07FFFF:
2315 : case 0x08FFFE:
2316 : case 0x08FFFF:
2317 : case 0x09FFFE:
2318 : case 0x09FFFF:
2319 : case 0x0AFFFE:
2320 : case 0x0AFFFF:
2321 : case 0x0BFFFE:
2322 : case 0x0BFFFF:
2323 : case 0x0CFFFE:
2324 : case 0x0CFFFF:
2325 : case 0x0DFFFE:
2326 : case 0x0DFFFF:
2327 : case 0x0EFFFE:
2328 : case 0x0EFFFF:
2329 : case 0x0FFFFE:
2330 : case 0x0FFFFF:
2331 : case 0x10FFFE:
2332 : case 0x10FFFF:
2333 : // skip on characters that are either invalid or generate
2334 : // a "problem" (i.e. spaces get trimmed)
2335 41 : continue;
2336 :
2337 1114071 : default:
2338 1114071 : if(i >= 0xD800 && i <= 0xDFFF)
2339 : {
2340 2048 : continue;
2341 : }
2342 1112023 : break;
2343 :
2344 : }
2345 :
2346 : // note that we test with sensible characters first
2347 :
2348 2224046 : std::stringstream ss;
2349 1112023 : if(rand() % 1 == 0)
2350 : {
2351 : // make sure to also test uppercase once in a while
2352 1112023 : ss << std::uppercase;
2353 : }
2354 1112023 : ss << "'escape character #" << std::dec << i
2355 1112023 : << " as: \\" << std::hex << i
2356 1112023 : << " to see whether it works'";
2357 4448092 : csspp::position pos("test.css");
2358 2224046 : csspp::lexer l(ss, pos);
2359 :
2360 : // string
2361 : {
2362 1112023 : csspp::node::pointer_t string(l.next_token());
2363 1112023 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2364 1112023 : std::stringstream out;
2365 1112023 : out << "escape character #" << std::dec << i
2366 2224046 : << " as: " << l.wctomb(i)
2367 : << (i < 0x100000 ? "" : " ") // space gets eaten if less than 6 characters in escape sequence
2368 2224046 : << "to see whether it works";
2369 1112023 : CATCH_REQUIRE(string->get_string() == out.str());
2370 1112023 : csspp::position const & npos(string->get_position());
2371 1112023 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2372 1112023 : CATCH_REQUIRE(npos.get_page() == 1);
2373 1112023 : CATCH_REQUIRE(npos.get_line() == 1);
2374 1112023 : CATCH_REQUIRE(npos.get_total_line() == 1);
2375 1112023 : }
2376 :
2377 1112023 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2378 :
2379 : // no error left over
2380 1112023 : VERIFY_ERRORS("");
2381 : }
2382 : }
2383 :
2384 : // unterminated string before EOF
2385 : {
2386 1 : std::stringstream ss;
2387 1 : ss << "'No terminator";
2388 3 : csspp::position pos("test.css");
2389 1 : csspp::lexer l(ss, pos);
2390 :
2391 : // string
2392 : {
2393 1 : csspp::node::pointer_t string(l.next_token());
2394 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2395 1 : CATCH_REQUIRE(string->get_string() == "No terminator");
2396 1 : csspp::position const & npos(string->get_position());
2397 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2398 1 : CATCH_REQUIRE(npos.get_page() == 1);
2399 1 : CATCH_REQUIRE(npos.get_line() == 1);
2400 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2401 :
2402 1 : VERIFY_ERRORS("test.css(1): error: found an unterminated string.\n");
2403 1 : }
2404 :
2405 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2406 :
2407 : // no error left over
2408 1 : VERIFY_ERRORS("");
2409 1 : }
2410 :
2411 : // unterminated string before \n
2412 : {
2413 1 : std::stringstream ss;
2414 1 : ss << "'No terminator\nto that string";
2415 3 : csspp::position pos("test.css");
2416 1 : csspp::lexer l(ss, pos);
2417 :
2418 : // string
2419 : {
2420 1 : csspp::node::pointer_t string(l.next_token());
2421 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2422 1 : CATCH_REQUIRE(string->get_string() == "No terminator");
2423 1 : csspp::position const & npos(string->get_position());
2424 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2425 1 : CATCH_REQUIRE(npos.get_page() == 1);
2426 1 : CATCH_REQUIRE(npos.get_line() == 1);
2427 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2428 :
2429 1 : VERIFY_ERRORS("test.css(1): error: found an unterminated string with an unescaped newline.\n");
2430 1 : }
2431 :
2432 : // whitespace
2433 : {
2434 1 : csspp::node::pointer_t string(l.next_token());
2435 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::WHITESPACE));
2436 1 : csspp::position const & npos(string->get_position());
2437 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2438 1 : CATCH_REQUIRE(npos.get_page() == 1);
2439 1 : CATCH_REQUIRE(npos.get_line() == 2);
2440 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2441 1 : }
2442 :
2443 : // identifier
2444 : {
2445 1 : csspp::node::pointer_t string(l.next_token());
2446 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2447 1 : CATCH_REQUIRE(string->get_string() == "to");
2448 1 : csspp::position const & npos(string->get_position());
2449 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2450 1 : CATCH_REQUIRE(npos.get_page() == 1);
2451 1 : CATCH_REQUIRE(npos.get_line() == 2);
2452 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2453 1 : }
2454 :
2455 : // whitespace
2456 : {
2457 1 : csspp::node::pointer_t string(l.next_token());
2458 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::WHITESPACE));
2459 1 : csspp::position const & npos(string->get_position());
2460 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2461 1 : CATCH_REQUIRE(npos.get_page() == 1);
2462 1 : CATCH_REQUIRE(npos.get_line() == 2);
2463 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2464 1 : }
2465 :
2466 : // identifier
2467 : {
2468 1 : csspp::node::pointer_t string(l.next_token());
2469 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2470 1 : CATCH_REQUIRE(string->get_string() == "that");
2471 1 : csspp::position const & npos(string->get_position());
2472 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2473 1 : CATCH_REQUIRE(npos.get_page() == 1);
2474 1 : CATCH_REQUIRE(npos.get_line() == 2);
2475 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2476 1 : }
2477 :
2478 : // whitespace
2479 : {
2480 1 : csspp::node::pointer_t string(l.next_token());
2481 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::WHITESPACE));
2482 1 : csspp::position const & npos(string->get_position());
2483 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2484 1 : CATCH_REQUIRE(npos.get_page() == 1);
2485 1 : CATCH_REQUIRE(npos.get_line() == 2);
2486 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2487 1 : }
2488 :
2489 : // identifier
2490 : {
2491 1 : csspp::node::pointer_t string(l.next_token());
2492 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2493 1 : CATCH_REQUIRE(string->get_string() == "string");
2494 1 : csspp::position const & npos(string->get_position());
2495 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2496 1 : CATCH_REQUIRE(npos.get_page() == 1);
2497 1 : CATCH_REQUIRE(npos.get_line() == 2);
2498 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2499 1 : }
2500 :
2501 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2502 :
2503 : // no error left over
2504 1 : VERIFY_ERRORS("");
2505 1 : }
2506 :
2507 : // special escapes in a string: \ + <EOF>
2508 : // (same as just EOF above: unterminated string)
2509 : {
2510 1 : std::stringstream ss;
2511 1 : ss << "'No terminator\\";
2512 3 : csspp::position pos("test.css");
2513 1 : csspp::lexer l(ss, pos);
2514 :
2515 : // string
2516 : {
2517 1 : csspp::node::pointer_t string(l.next_token());
2518 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2519 1 : CATCH_REQUIRE(string->get_string() == "No terminator");
2520 1 : csspp::position const & npos(string->get_position());
2521 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2522 1 : CATCH_REQUIRE(npos.get_page() == 1);
2523 1 : CATCH_REQUIRE(npos.get_line() == 1);
2524 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2525 :
2526 1 : VERIFY_ERRORS("test.css(1): error: found an unterminated string.\n");
2527 1 : }
2528 :
2529 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2530 :
2531 : // no error left over
2532 1 : VERIFY_ERRORS("");
2533 1 : }
2534 :
2535 : // special escapes in a string: \ + '\n'
2536 : // (this is actually legal!)
2537 : {
2538 1 : std::stringstream ss;
2539 1 : ss << "'Line ncontinues on\\\nthe next line.'";
2540 3 : csspp::position pos("test.css");
2541 1 : csspp::lexer l(ss, pos);
2542 :
2543 : // string
2544 : {
2545 1 : csspp::node::pointer_t string(l.next_token());
2546 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2547 1 : CATCH_REQUIRE(string->get_string() == "Line ncontinues on\nthe next line.");
2548 1 : csspp::position const & npos(string->get_position());
2549 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2550 1 : CATCH_REQUIRE(npos.get_page() == 1);
2551 1 : CATCH_REQUIRE(npos.get_line() == 1);
2552 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2553 1 : }
2554 :
2555 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2556 :
2557 : // no error left over
2558 1 : VERIFY_ERRORS("");
2559 1 : }
2560 :
2561 : // special escapes in a string: \ + <FFFD>
2562 : {
2563 1 : std::stringstream ss;
2564 3 : csspp::position pos("test.css");
2565 1 : csspp::lexer l(ss, pos);
2566 1 : ss << "'Bad Escape \\" << l.wctomb(0xFFFD) << " String'";
2567 :
2568 : // string
2569 : {
2570 1 : csspp::node::pointer_t string(l.next_token());
2571 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2572 1 : CATCH_REQUIRE(string->get_string() == "Bad Escape String");
2573 1 : csspp::position const & npos(string->get_position());
2574 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2575 1 : CATCH_REQUIRE(npos.get_page() == 1);
2576 1 : CATCH_REQUIRE(npos.get_line() == 1);
2577 :
2578 1 : VERIFY_ERRORS("test.css(1): error: invalid character after a \\ character.\n");
2579 1 : }
2580 :
2581 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2582 :
2583 : // no error left over
2584 1 : VERIFY_ERRORS("");
2585 1 : }
2586 :
2587 : // escapes in a string: \ + <number too large>
2588 31352 : for(int i(0x110000); i < 0x01000000; i += rand() % 1000 + 1)
2589 : {
2590 31351 : std::stringstream ss;
2591 94053 : csspp::position pos("test.css");
2592 31351 : csspp::lexer l(ss, pos);
2593 31351 : ss << "'Bad Escape \\" << std::hex << i << " String'";
2594 :
2595 : // string
2596 : {
2597 31351 : csspp::node::pointer_t string(l.next_token());
2598 31351 : CATCH_REQUIRE(string->is(csspp::node_type_t::STRING));
2599 31351 : CATCH_REQUIRE(string->get_string() == "Bad Escape String");
2600 31351 : csspp::position const & npos(string->get_position());
2601 31351 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2602 31351 : CATCH_REQUIRE(npos.get_page() == 1);
2603 31351 : CATCH_REQUIRE(npos.get_line() == 1);
2604 31351 : CATCH_REQUIRE(npos.get_total_line() == 1);
2605 :
2606 31351 : VERIFY_ERRORS("test.css(1): error: escape character too large for Unicode.\n");
2607 31351 : }
2608 :
2609 31351 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2610 :
2611 : // no error left over
2612 31351 : VERIFY_ERRORS("");
2613 31351 : }
2614 1 : }
2615 :
2616 1 : CATCH_TEST_CASE("Identifiers", "[lexer] [identifier]")
2617 : {
2618 : // a few simple identifiers
2619 11 : for(int count(0); count < 10; ++count)
2620 : {
2621 10 : std::stringstream ss;
2622 10 : size_t const len(rand() % 20 + 20);
2623 10 : std::string word;
2624 289 : for(size_t i(0); i < len; ++i)
2625 : {
2626 : // simple ascii letters
2627 279 : int const c(rand() % 26 + 'a');
2628 279 : ss << static_cast<char>(c);
2629 279 : word += static_cast<char>(c);
2630 : }
2631 30 : csspp::position pos("test.css");
2632 10 : csspp::lexer l(ss, pos);
2633 :
2634 : // identifier
2635 : {
2636 10 : csspp::node::pointer_t string(l.next_token());
2637 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2638 10 : CATCH_REQUIRE(string->get_string() == word);
2639 10 : csspp::position const & npos(string->get_position());
2640 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2641 10 : CATCH_REQUIRE(npos.get_page() == 1);
2642 10 : CATCH_REQUIRE(npos.get_line() == 1);
2643 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
2644 10 : }
2645 :
2646 10 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2647 10 : }
2648 :
2649 : // a few simple identifiers starting with '_'
2650 11 : for(int count(0); count < 10; ++count)
2651 : {
2652 10 : std::stringstream ss;
2653 10 : size_t const len(rand() % 20 + 20);
2654 20 : std::string word("_");
2655 10 : ss << '_';
2656 325 : for(size_t i(0); i < len; ++i)
2657 : {
2658 : // simple ascii letters
2659 315 : int const c(rand() % 26 + 'a');
2660 315 : ss << static_cast<char>(c);
2661 315 : word += static_cast<char>(c);
2662 : }
2663 30 : csspp::position pos("test.css");
2664 10 : csspp::lexer l(ss, pos);
2665 :
2666 : // identifier
2667 : {
2668 10 : csspp::node::pointer_t string(l.next_token());
2669 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2670 10 : CATCH_REQUIRE(string->get_string() == word);
2671 10 : csspp::position const & npos(string->get_position());
2672 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2673 10 : CATCH_REQUIRE(npos.get_page() == 1);
2674 10 : CATCH_REQUIRE(npos.get_line() == 1);
2675 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
2676 10 : }
2677 :
2678 10 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2679 10 : }
2680 :
2681 : // a few simple identifiers starting with '@'
2682 11 : for(int count(0); count < 10; ++count)
2683 : {
2684 10 : std::stringstream ss;
2685 10 : size_t const len(rand() % 20 + 20);
2686 10 : std::string word;
2687 10 : ss << '@';
2688 295 : for(size_t i(0); i < len; ++i)
2689 : {
2690 : // simple ascii letters
2691 285 : int const c(rand() % 26 + 'a');
2692 285 : ss << static_cast<char>(c);
2693 285 : word += static_cast<char>(c);
2694 : }
2695 30 : csspp::position pos("test.css");
2696 10 : csspp::lexer l(ss, pos);
2697 :
2698 : // identifier
2699 : {
2700 10 : csspp::node::pointer_t string(l.next_token());
2701 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::AT_KEYWORD));
2702 10 : CATCH_REQUIRE(string->get_string() == word);
2703 10 : csspp::position const & npos(string->get_position());
2704 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2705 10 : CATCH_REQUIRE(npos.get_page() == 1);
2706 10 : CATCH_REQUIRE(npos.get_line() == 1);
2707 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
2708 10 : }
2709 :
2710 10 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2711 10 : }
2712 :
2713 : // try with empty '@' characters (i.e. invalid identifiers)
2714 : {
2715 1 : std::stringstream ss;
2716 1 : ss << "@*@";
2717 3 : csspp::position pos("test.css");
2718 1 : csspp::lexer l(ss, pos);
2719 :
2720 : // prefix-match
2721 : {
2722 1 : csspp::node::pointer_t string(l.next_token());
2723 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::MULTIPLY));
2724 1 : csspp::position const & npos(string->get_position());
2725 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2726 1 : CATCH_REQUIRE(npos.get_page() == 1);
2727 1 : CATCH_REQUIRE(npos.get_line() == 1);
2728 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2729 :
2730 1 : VERIFY_ERRORS("test.css(1): error: found an empty identifier.\n");
2731 1 : }
2732 :
2733 : // EOF
2734 : {
2735 1 : csspp::node::pointer_t eof(l.next_token());
2736 1 : CATCH_REQUIRE(eof->is(csspp::node_type_t::EOF_TOKEN));
2737 :
2738 1 : VERIFY_ERRORS("test.css(1): error: found an empty identifier.\n");
2739 1 : }
2740 1 : }
2741 :
2742 : // identifiers starting with '-'
2743 11 : for(int count(0); count < 10; ++count)
2744 : {
2745 10 : std::stringstream ss;
2746 10 : size_t const len(rand() % 20 + 20);
2747 10 : std::string word;
2748 10 : word += '-';
2749 10 : ss << '-';
2750 300 : for(size_t i(0); i < len; ++i)
2751 : {
2752 : // simple ascii letters
2753 290 : int const c(rand() % 26 + 'a');
2754 290 : ss << static_cast<char>(c);
2755 290 : word += static_cast<char>(c);
2756 : }
2757 30 : csspp::position pos("test.css");
2758 10 : csspp::lexer l(ss, pos);
2759 :
2760 : // identifier
2761 : {
2762 10 : csspp::node::pointer_t string(l.next_token());
2763 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2764 10 : CATCH_REQUIRE(string->get_string() == word);
2765 10 : csspp::position const & npos(string->get_position());
2766 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2767 10 : CATCH_REQUIRE(npos.get_page() == 1);
2768 10 : CATCH_REQUIRE(npos.get_line() == 1);
2769 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
2770 10 : }
2771 :
2772 10 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2773 10 : }
2774 :
2775 : // identifiers cannot start with '--'
2776 : {
2777 1 : std::stringstream ss;
2778 1 : ss << "--not-double-dash\n-\\-double-dash\n-\\----quintuple-dash-----\r\n";
2779 3 : csspp::position pos("test.css");
2780 1 : csspp::lexer l(ss, pos);
2781 :
2782 : // subtract
2783 : {
2784 1 : csspp::node::pointer_t string(l.next_token());
2785 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::SUBTRACT));
2786 1 : csspp::position const & npos(string->get_position());
2787 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2788 1 : CATCH_REQUIRE(npos.get_page() == 1);
2789 1 : CATCH_REQUIRE(npos.get_line() == 1);
2790 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2791 1 : }
2792 :
2793 : // identifier
2794 : {
2795 1 : csspp::node::pointer_t string(l.next_token());
2796 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2797 1 : CATCH_REQUIRE(string->get_string() == "-not-double-dash");
2798 1 : csspp::position const & npos(string->get_position());
2799 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2800 1 : CATCH_REQUIRE(npos.get_page() == 1);
2801 1 : CATCH_REQUIRE(npos.get_line() == 1);
2802 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2803 1 : }
2804 :
2805 : // whitespace
2806 : {
2807 1 : csspp::node::pointer_t whitespace(l.next_token());
2808 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
2809 1 : csspp::position const & npos(whitespace->get_position());
2810 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2811 1 : CATCH_REQUIRE(npos.get_page() == 1);
2812 1 : CATCH_REQUIRE(npos.get_line() == 2);
2813 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2814 1 : }
2815 :
2816 : // identifier
2817 : {
2818 1 : csspp::node::pointer_t string(l.next_token());
2819 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2820 1 : CATCH_REQUIRE(string->get_string() == "--double-dash");
2821 1 : csspp::position const & npos(string->get_position());
2822 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2823 1 : CATCH_REQUIRE(npos.get_page() == 1);
2824 1 : CATCH_REQUIRE(npos.get_line() == 2);
2825 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2826 1 : }
2827 :
2828 : // whitespace
2829 : {
2830 1 : csspp::node::pointer_t whitespace(l.next_token());
2831 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
2832 1 : csspp::position const & npos(whitespace->get_position());
2833 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2834 1 : CATCH_REQUIRE(npos.get_page() == 1);
2835 1 : CATCH_REQUIRE(npos.get_line() == 3);
2836 1 : CATCH_REQUIRE(npos.get_total_line() == 3);
2837 1 : }
2838 :
2839 : // identifier
2840 : {
2841 1 : csspp::node::pointer_t string(l.next_token());
2842 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2843 1 : CATCH_REQUIRE(string->get_string() == "-----quintuple-dash-----");
2844 1 : csspp::position const & npos(string->get_position());
2845 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2846 1 : CATCH_REQUIRE(npos.get_page() == 1);
2847 1 : CATCH_REQUIRE(npos.get_line() == 3);
2848 1 : CATCH_REQUIRE(npos.get_total_line() == 3);
2849 1 : }
2850 :
2851 : // whitespace
2852 : {
2853 1 : csspp::node::pointer_t whitespace(l.next_token());
2854 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
2855 1 : csspp::position const & npos(whitespace->get_position());
2856 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2857 1 : CATCH_REQUIRE(npos.get_page() == 1);
2858 1 : CATCH_REQUIRE(npos.get_line() == 4);
2859 1 : CATCH_REQUIRE(npos.get_total_line() == 4);
2860 1 : }
2861 :
2862 : // EOF
2863 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2864 1 : }
2865 :
2866 : // identifiers starting with an escape (\)
2867 : {
2868 1 : std::stringstream ss;
2869 : ss << "\\41lexis\n"
2870 : << "\\42 abar\n"
2871 1 : << "\\000043arlos\n";
2872 3 : csspp::position pos("test.css");
2873 1 : csspp::lexer l(ss, pos);
2874 :
2875 : // identifier
2876 : {
2877 1 : csspp::node::pointer_t string(l.next_token());
2878 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2879 1 : CATCH_REQUIRE(string->get_string() == "Alexis"); // identifiers are forced to lowercase since they are case insensitive
2880 1 : csspp::position const & npos(string->get_position());
2881 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2882 1 : CATCH_REQUIRE(npos.get_page() == 1);
2883 1 : CATCH_REQUIRE(npos.get_line() == 1);
2884 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2885 1 : }
2886 :
2887 : // whitespace
2888 : {
2889 1 : csspp::node::pointer_t whitespace(l.next_token());
2890 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
2891 1 : csspp::position const & npos(whitespace->get_position());
2892 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2893 1 : CATCH_REQUIRE(npos.get_page() == 1);
2894 1 : CATCH_REQUIRE(npos.get_line() == 2);
2895 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2896 1 : }
2897 :
2898 : // identifier
2899 : {
2900 1 : csspp::node::pointer_t string(l.next_token());
2901 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2902 1 : CATCH_REQUIRE(string->get_string() == "Babar"); // prove the space is eaten as expected
2903 1 : csspp::position const & npos(string->get_position());
2904 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2905 1 : CATCH_REQUIRE(npos.get_page() == 1);
2906 1 : CATCH_REQUIRE(npos.get_line() == 2);
2907 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
2908 1 : }
2909 :
2910 : // whitespace
2911 : {
2912 1 : csspp::node::pointer_t whitespace(l.next_token());
2913 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
2914 1 : csspp::position const & npos(whitespace->get_position());
2915 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2916 1 : CATCH_REQUIRE(npos.get_page() == 1);
2917 1 : CATCH_REQUIRE(npos.get_line() == 3);
2918 1 : CATCH_REQUIRE(npos.get_total_line() == 3);
2919 1 : }
2920 :
2921 : // identifier
2922 : {
2923 1 : csspp::node::pointer_t string(l.next_token());
2924 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2925 1 : CATCH_REQUIRE(string->get_string() == "Carlos"); // prove the space is not required with 6 digits
2926 1 : csspp::position const & npos(string->get_position());
2927 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2928 1 : CATCH_REQUIRE(npos.get_page() == 1);
2929 1 : CATCH_REQUIRE(npos.get_line() == 3);
2930 1 : CATCH_REQUIRE(npos.get_total_line() == 3);
2931 1 : }
2932 :
2933 : // whitespace
2934 : {
2935 1 : csspp::node::pointer_t whitespace(l.next_token());
2936 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
2937 1 : csspp::position const & npos(whitespace->get_position());
2938 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2939 1 : CATCH_REQUIRE(npos.get_page() == 1);
2940 1 : CATCH_REQUIRE(npos.get_line() == 4);
2941 1 : CATCH_REQUIRE(npos.get_total_line() == 4);
2942 1 : }
2943 :
2944 : // EOF
2945 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2946 1 : }
2947 :
2948 : // identifier with an empty escape (\ + <EOF>)
2949 : {
2950 1 : std::stringstream ss;
2951 1 : ss << "This\\";
2952 3 : csspp::position pos("test.css");
2953 1 : csspp::lexer l(ss, pos);
2954 :
2955 : // identifier
2956 : {
2957 1 : csspp::node::pointer_t string(l.next_token());
2958 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2959 1 : CATCH_REQUIRE(string->get_string() == "This");
2960 1 : csspp::position const & npos(string->get_position());
2961 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2962 1 : CATCH_REQUIRE(npos.get_page() == 1);
2963 1 : CATCH_REQUIRE(npos.get_line() == 1);
2964 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2965 :
2966 1 : VERIFY_ERRORS("test.css(1): error: found EOF right after \\.\n");
2967 1 : }
2968 :
2969 : // EOF
2970 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
2971 1 : }
2972 :
2973 : // empty identifier with an empty escape (\ + <EOF>)
2974 : {
2975 1 : std::stringstream ss;
2976 1 : ss << "This \\";
2977 3 : csspp::position pos("test.css");
2978 1 : csspp::lexer l(ss, pos);
2979 :
2980 : // identifier
2981 : {
2982 1 : csspp::node::pointer_t string(l.next_token());
2983 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
2984 1 : CATCH_REQUIRE(string->get_string() == "This");
2985 1 : csspp::position const & npos(string->get_position());
2986 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2987 1 : CATCH_REQUIRE(npos.get_page() == 1);
2988 1 : CATCH_REQUIRE(npos.get_line() == 1);
2989 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
2990 1 : }
2991 :
2992 : // whitespace
2993 : {
2994 1 : csspp::node::pointer_t whitespace(l.next_token());
2995 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
2996 1 : csspp::position const & npos(whitespace->get_position());
2997 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
2998 1 : CATCH_REQUIRE(npos.get_page() == 1);
2999 1 : CATCH_REQUIRE(npos.get_line() == 1);
3000 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3001 1 : }
3002 :
3003 : // EOF
3004 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3005 :
3006 1 : VERIFY_ERRORS(
3007 : "test.css(1): error: found EOF right after \\.\n"
3008 : "test.css(1): error: found an empty identifier.\n"
3009 : );
3010 1 : }
3011 :
3012 : // identifier with an escape followed by a newline (\ + <new-line>)
3013 : {
3014 1 : std::stringstream ss;
3015 1 : ss << "This\\\nThat";
3016 3 : csspp::position pos("test.css");
3017 1 : csspp::lexer l(ss, pos);
3018 :
3019 : // identifier
3020 : {
3021 1 : csspp::node::pointer_t string(l.next_token());
3022 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
3023 1 : CATCH_REQUIRE(string->get_string() == "This");
3024 1 : csspp::position const & npos(string->get_position());
3025 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3026 1 : CATCH_REQUIRE(npos.get_page() == 1);
3027 1 : CATCH_REQUIRE(npos.get_line() == 1);
3028 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3029 :
3030 1 : VERIFY_ERRORS(
3031 : "test.css(1): error: spurious newline character after a \\ character outside of a string.\n"
3032 : );
3033 1 : }
3034 :
3035 : // whitespace -- this one gets lost and we do not care much
3036 : //{
3037 : // csspp::node::pointer_t whitespace(l.next_token());
3038 : // CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
3039 : // csspp::position const & npos(whitespace->get_position());
3040 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
3041 : // CATCH_REQUIRE(npos.get_page() == 1);
3042 : // CATCH_REQUIRE(npos.get_line() == 1);
3043 : // CATCH_REQUIRE(npos.get_total_line() == 1);
3044 : //}
3045 :
3046 : // identifier
3047 : {
3048 1 : csspp::node::pointer_t string(l.next_token());
3049 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
3050 1 : CATCH_REQUIRE(string->get_string() == "That");
3051 1 : csspp::position const & npos(string->get_position());
3052 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3053 1 : CATCH_REQUIRE(npos.get_page() == 1);
3054 1 : CATCH_REQUIRE(npos.get_line() == 2);
3055 1 : CATCH_REQUIRE(npos.get_total_line() == 2);
3056 1 : }
3057 :
3058 : // EOF
3059 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3060 1 : }
3061 :
3062 : // identifiers written between parenthesis and "don't do that"
3063 11 : for(int count(0); count < 10; ++count)
3064 : {
3065 10 : std::stringstream ss;
3066 10 : size_t const len(rand() % 20 + 20);
3067 10 : std::string word;
3068 10 : word += "(";
3069 10 : ss << "\\(";
3070 313 : for(size_t i(0); i < len; ++i)
3071 : {
3072 : // simple ascii letters
3073 303 : int const c(rand() % 26 + 'a');
3074 303 : if(c > 'f' && rand() % 5 == 0)
3075 : {
3076 : // add some random escape characters
3077 51 : ss << "\\";
3078 : }
3079 303 : ss << static_cast<char>(c);
3080 303 : word += static_cast<char>(c);
3081 : }
3082 10 : word += ")";
3083 10 : ss << "\\)\n\\\"don\\'t\\ do\\ that\\\"";
3084 30 : csspp::position pos("test.css");
3085 10 : csspp::lexer l(ss, pos);
3086 :
3087 : // identifier
3088 : {
3089 10 : csspp::node::pointer_t string(l.next_token());
3090 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
3091 10 : CATCH_REQUIRE(string->get_string() == word);
3092 10 : csspp::position const & npos(string->get_position());
3093 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3094 10 : CATCH_REQUIRE(npos.get_page() == 1);
3095 10 : CATCH_REQUIRE(npos.get_line() == 1);
3096 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
3097 10 : }
3098 :
3099 : // whitespace
3100 : {
3101 10 : csspp::node::pointer_t whitespace(l.next_token());
3102 10 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
3103 10 : csspp::position const & npos(whitespace->get_position());
3104 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3105 10 : CATCH_REQUIRE(npos.get_page() == 1);
3106 10 : CATCH_REQUIRE(npos.get_line() == 2);
3107 10 : CATCH_REQUIRE(npos.get_total_line() == 2);
3108 10 : }
3109 :
3110 : // identifier
3111 : {
3112 10 : csspp::node::pointer_t string(l.next_token());
3113 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
3114 10 : CATCH_REQUIRE(string->get_string() == "\"don't do that\""); // yes, it's possible
3115 10 : csspp::position const & npos(string->get_position());
3116 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3117 10 : CATCH_REQUIRE(npos.get_page() == 1);
3118 10 : CATCH_REQUIRE(npos.get_line() == 2);
3119 10 : CATCH_REQUIRE(npos.get_total_line() == 2);
3120 10 : }
3121 :
3122 10 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3123 10 : }
3124 :
3125 : // identifier with an escape followed by 0xFFFD (\ + <FFFD>)
3126 : {
3127 1 : std::stringstream ss;
3128 3 : csspp::position pos("test.css");
3129 1 : csspp::lexer l(ss, pos);
3130 1 : ss << "This\\" << l.wctomb(0xFFFD) << "\\ ID";
3131 :
3132 : // identifier
3133 : {
3134 1 : csspp::node::pointer_t string(l.next_token());
3135 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
3136 1 : CATCH_REQUIRE(string->get_string() == "This");
3137 1 : csspp::position const & npos(string->get_position());
3138 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3139 1 : CATCH_REQUIRE(npos.get_page() == 1);
3140 1 : CATCH_REQUIRE(npos.get_line() == 1);
3141 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3142 :
3143 1 : VERIFY_ERRORS("test.css(1): error: invalid character after a \\ character.\n");
3144 1 : }
3145 :
3146 : // identifier
3147 : {
3148 1 : csspp::node::pointer_t string(l.next_token());
3149 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
3150 1 : CATCH_REQUIRE(string->get_string() == " ID");
3151 1 : csspp::position const & npos(string->get_position());
3152 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3153 1 : CATCH_REQUIRE(npos.get_page() == 1);
3154 1 : CATCH_REQUIRE(npos.get_line() == 1);
3155 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3156 1 : }
3157 :
3158 : // EOF
3159 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3160 1 : }
3161 :
3162 : // identifier with an escape followed by "0" (\0)
3163 : {
3164 1 : std::stringstream ss;
3165 3 : csspp::position pos("test.css");
3166 1 : csspp::lexer l(ss, pos);
3167 1 : ss << "This\\0ID";
3168 :
3169 : // identifier
3170 : {
3171 1 : csspp::node::pointer_t string(l.next_token());
3172 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
3173 1 : CATCH_REQUIRE(string->get_string() == "This");
3174 1 : csspp::position const & npos(string->get_position());
3175 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3176 1 : CATCH_REQUIRE(npos.get_page() == 1);
3177 1 : CATCH_REQUIRE(npos.get_line() == 1);
3178 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3179 :
3180 1 : VERIFY_ERRORS("test.css(1): error: escape character '\\0' is not acceptable in CSS.\n");
3181 1 : }
3182 :
3183 : // identifier
3184 : {
3185 1 : csspp::node::pointer_t string(l.next_token());
3186 1 : CATCH_REQUIRE(string->is(csspp::node_type_t::IDENTIFIER));
3187 1 : CATCH_REQUIRE(string->get_string() == "ID");
3188 1 : csspp::position const & npos(string->get_position());
3189 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3190 1 : CATCH_REQUIRE(npos.get_page() == 1);
3191 1 : CATCH_REQUIRE(npos.get_line() == 1);
3192 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3193 1 : }
3194 :
3195 : // EOF
3196 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3197 1 : }
3198 :
3199 : // no error left over
3200 1 : VERIFY_ERRORS("");
3201 1 : }
3202 :
3203 4 : CATCH_TEST_CASE("Urls", "[lexer] [identifier] [url] [function]")
3204 : {
3205 : // a few simple URLs
3206 4 : CATCH_START_SECTION("simple URLs")
3207 : {
3208 11 : for(int count(0); count < 10; ++count)
3209 : {
3210 10 : std::stringstream ss;
3211 10 : size_t const len(rand() % 20 + 20);
3212 10 : std::string word;
3213 10 : ss << "url(";
3214 10 : size_t const leading(count == 0 ? 0 : rand() % 10);
3215 45 : for(size_t i(0); i < leading; ++i)
3216 : {
3217 35 : ss << ' ';
3218 : }
3219 293 : for(size_t i(0); i < len; ++i)
3220 : {
3221 : // simple ascii letters
3222 283 : int const c(rand() % 26 + 'a');
3223 283 : ss << static_cast<char>(c);
3224 283 : word += static_cast<char>(c);
3225 : }
3226 10 : size_t const trailing(count == 9 ? 0 : rand() % 10);
3227 38 : for(size_t i(0); i < trailing; ++i)
3228 : {
3229 28 : ss << ' ';
3230 : }
3231 10 : ss << ")";
3232 30 : csspp::position pos("test.css");
3233 10 : csspp::lexer l(ss, pos);
3234 :
3235 : // url
3236 : {
3237 10 : csspp::node::pointer_t string(l.next_token());
3238 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::URL));
3239 10 : CATCH_REQUIRE(string->get_string() == word);
3240 10 : csspp::position const & npos(string->get_position());
3241 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3242 10 : CATCH_REQUIRE(npos.get_page() == 1);
3243 10 : CATCH_REQUIRE(npos.get_line() == 1);
3244 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
3245 10 : }
3246 :
3247 10 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3248 10 : }
3249 :
3250 1 : VERIFY_ERRORS("");
3251 : }
3252 4 : CATCH_END_SECTION()
3253 :
3254 : // a few simple quoted URLs
3255 4 : CATCH_START_SECTION("simple quoted URLs")
3256 : {
3257 11 : for(int count(0); count < 10; ++count)
3258 : {
3259 10 : std::stringstream ss;
3260 10 : size_t const len(rand() % 20 + 20);
3261 10 : std::string word;
3262 10 : ss << "url(";
3263 10 : size_t const leading(rand() % 10);
3264 61 : for(size_t i(0); i < leading; ++i)
3265 : {
3266 51 : ss << ' ';
3267 : }
3268 10 : char const quote("\"'"[rand() % 2]);
3269 10 : ss << quote;
3270 308 : for(size_t i(0); i < len; ++i)
3271 : {
3272 : // simple ascii letters
3273 298 : int const c(rand() % 26 + 'a');
3274 298 : ss << static_cast<char>(c);
3275 298 : word += static_cast<char>(c);
3276 : }
3277 10 : ss << quote;
3278 10 : size_t const trailing(rand() % 10);
3279 47 : for(size_t i(0); i < trailing; ++i)
3280 : {
3281 37 : ss << ' ';
3282 : }
3283 10 : ss << ")";
3284 30 : csspp::position pos("test.css");
3285 10 : csspp::lexer l(ss, pos);
3286 :
3287 : // url
3288 : {
3289 10 : csspp::node::pointer_t string(l.next_token());
3290 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::URL));
3291 10 : CATCH_REQUIRE(string->get_string() == word);
3292 10 : csspp::position const & npos(string->get_position());
3293 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3294 10 : CATCH_REQUIRE(npos.get_page() == 1);
3295 10 : CATCH_REQUIRE(npos.get_line() == 1);
3296 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
3297 10 : }
3298 :
3299 10 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3300 10 : }
3301 :
3302 1 : VERIFY_ERRORS("");
3303 : }
3304 4 : CATCH_END_SECTION()
3305 :
3306 : // an invalid URL with EOF too soon
3307 4 : CATCH_START_SECTION("invalid URL with EOF too soon")
3308 : {
3309 11 : for(int count(0); count < 10; ++count)
3310 : {
3311 10 : std::stringstream ss;
3312 10 : size_t const len(rand() % 20 + 20);
3313 10 : std::string word;
3314 10 : ss << "url(";
3315 10 : size_t const leading(count == 0 ? 0 : rand() % 10);
3316 43 : for(size_t i(0); i < leading; ++i)
3317 : {
3318 33 : ss << ' ';
3319 : }
3320 305 : for(size_t i(0); i < len; ++i)
3321 : {
3322 : // simple ascii letters
3323 295 : int const c(rand() % 26 + 'a');
3324 295 : ss << static_cast<char>(c);
3325 295 : word += static_cast<char>(c);
3326 : }
3327 30 : csspp::position pos("test.css");
3328 10 : csspp::lexer l(ss, pos);
3329 :
3330 : // url
3331 : {
3332 10 : csspp::node::pointer_t string(l.next_token());
3333 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::URL));
3334 10 : CATCH_REQUIRE(string->get_string() == word);
3335 10 : csspp::position const & npos(string->get_position());
3336 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3337 10 : CATCH_REQUIRE(npos.get_page() == 1);
3338 10 : CATCH_REQUIRE(npos.get_line() == 1);
3339 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
3340 :
3341 10 : VERIFY_ERRORS(
3342 : "test.css(1): error: found an invalid URL, one with forbidden characters.\n"
3343 : );
3344 10 : }
3345 :
3346 10 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3347 10 : }
3348 :
3349 1 : VERIFY_ERRORS("");
3350 : }
3351 4 : CATCH_END_SECTION()
3352 :
3353 : // an invalid URL with '"', "'", '(', and non-printable
3354 4 : CATCH_START_SECTION("invalid URL with various unacceptable characters")
3355 : {
3356 1 : char const invalid_chars[] = "\"'(\x8\xb\xe\xf\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f";
3357 26 : for(size_t ic(0); ic < sizeof(invalid_chars) / sizeof(invalid_chars[0]); ++ic)
3358 : {
3359 275 : for(int count(0); count < 10; ++count)
3360 : {
3361 250 : std::stringstream ss;
3362 750 : csspp::position pos("test.css");
3363 250 : csspp::lexer l(ss, pos);
3364 250 : std::string word;
3365 250 : ss << "url(";
3366 250 : size_t const leading(count == 0 ? 0 : rand() % 10);
3367 1224 : for(size_t i(0); i < leading; ++i)
3368 : {
3369 974 : ss << ' ';
3370 : }
3371 250 : size_t const len(rand() % 20 + 20);
3372 7674 : for(size_t i(0); i < len; ++i)
3373 : {
3374 : // simple ascii letters
3375 7424 : int const c(rand() % 26 + 'a');
3376 7424 : ss << static_cast<char>(c);
3377 7424 : word += static_cast<char>(c);
3378 : }
3379 250 : size_t const trailing(count & 1 ? 0 : rand() % 10);
3380 838 : for(size_t i(0); i < trailing; ++i)
3381 : {
3382 588 : ss << ' ';
3383 : }
3384 250 : if(invalid_chars[ic])
3385 : {
3386 240 : ss << invalid_chars[ic];
3387 : }
3388 : else
3389 : {
3390 : // we reached the NULL, insert 0xFFFD instead
3391 10 : ss << l.wctomb(0xFFFD);
3392 : }
3393 :
3394 : // url
3395 : {
3396 250 : csspp::node::pointer_t string(l.next_token());
3397 250 : CATCH_REQUIRE(string->is(csspp::node_type_t::URL));
3398 250 : CATCH_REQUIRE(string->get_string() == word);
3399 250 : csspp::position const & npos(string->get_position());
3400 250 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3401 250 : CATCH_REQUIRE(npos.get_page() == 1);
3402 250 : CATCH_REQUIRE(npos.get_line() == 1);
3403 250 : CATCH_REQUIRE(npos.get_total_line() == 1);
3404 :
3405 250 : VERIFY_ERRORS(
3406 : trailing == 0
3407 : ? "test.css(1): error: found an invalid URL, one with forbidden characters.\n"
3408 : : "test.css(1): error: found an invalid URL, one which includes spaces or has a missing ')'.\n"
3409 : );
3410 250 : }
3411 :
3412 250 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3413 250 : }
3414 : }
3415 :
3416 1 : VERIFY_ERRORS("");
3417 : }
3418 4 : CATCH_END_SECTION()
3419 :
3420 : // no error left over
3421 4 : VERIFY_ERRORS("");
3422 4 : }
3423 :
3424 1 : CATCH_TEST_CASE("Functions", "[lexer] [identifier] [function]")
3425 : {
3426 : // a few simple functions
3427 11 : for(int count(0); count < 10; ++count)
3428 : {
3429 10 : std::stringstream ss;
3430 10 : size_t const len(rand() % 20 + 20);
3431 10 : std::string word;
3432 307 : for(size_t i(0); i < len; ++i)
3433 : {
3434 : // simple ascii letters
3435 297 : int const c(rand() % 26 + 'a');
3436 297 : ss << static_cast<char>(c);
3437 297 : word += static_cast<char>(c);
3438 : }
3439 10 : ss << "(123)";
3440 30 : csspp::position pos("test.css");
3441 10 : csspp::lexer l(ss, pos);
3442 :
3443 : // function
3444 : {
3445 10 : csspp::node::pointer_t string(l.next_token());
3446 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::FUNCTION));
3447 10 : CATCH_REQUIRE(string->get_string() == word);
3448 10 : csspp::position const & npos(string->get_position());
3449 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3450 10 : CATCH_REQUIRE(npos.get_page() == 1);
3451 10 : CATCH_REQUIRE(npos.get_line() == 1);
3452 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
3453 10 : }
3454 :
3455 : // number
3456 : {
3457 10 : csspp::node::pointer_t string(l.next_token());
3458 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::INTEGER));
3459 10 : CATCH_REQUIRE(string->get_integer() == 123);
3460 10 : csspp::position const & npos(string->get_position());
3461 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3462 10 : CATCH_REQUIRE(npos.get_page() == 1);
3463 10 : CATCH_REQUIRE(npos.get_line() == 1);
3464 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
3465 10 : }
3466 :
3467 : // parenthesis
3468 : {
3469 10 : csspp::node::pointer_t string(l.next_token());
3470 10 : CATCH_REQUIRE(string->is(csspp::node_type_t::CLOSE_PARENTHESIS));
3471 10 : csspp::position const & npos(string->get_position());
3472 10 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3473 10 : CATCH_REQUIRE(npos.get_page() == 1);
3474 10 : CATCH_REQUIRE(npos.get_line() == 1);
3475 10 : CATCH_REQUIRE(npos.get_total_line() == 1);
3476 10 : }
3477 :
3478 10 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3479 10 : }
3480 :
3481 : // no error left over
3482 1 : VERIFY_ERRORS("");
3483 1 : }
3484 :
3485 1 : CATCH_TEST_CASE("Numbers", "[lexer] [number]")
3486 : {
3487 : // a few simple integers
3488 20002 : for(int i(-10000); i <= 10000; ++i)
3489 : {
3490 20001 : std::stringstream ss;
3491 20001 : ss << i;
3492 60003 : csspp::position pos("test.css");
3493 20001 : csspp::lexer l(ss, pos);
3494 :
3495 : // sign
3496 : //if(i < 0)
3497 : //{
3498 : // csspp::node::pointer_t integer(l.next_token());
3499 : // CATCH_REQUIRE(integer->is(csspp::node_type_t::SUBTRACT));
3500 : // csspp::position const & npos(integer->get_position());
3501 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
3502 : // CATCH_REQUIRE(npos.get_page() == 1);
3503 : // CATCH_REQUIRE(npos.get_line() == 1);
3504 : // CATCH_REQUIRE(npos.get_total_line() == 1);
3505 : //}
3506 :
3507 : // integer
3508 : {
3509 20001 : csspp::node::pointer_t integer(l.next_token());
3510 20001 : CATCH_REQUIRE(integer->is(csspp::node_type_t::INTEGER));
3511 20001 : CATCH_REQUIRE(integer->get_integer() == i);
3512 20001 : csspp::position const & npos(integer->get_position());
3513 20001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3514 20001 : CATCH_REQUIRE(npos.get_page() == 1);
3515 20001 : CATCH_REQUIRE(npos.get_line() == 1);
3516 20001 : CATCH_REQUIRE(npos.get_total_line() == 1);
3517 20001 : }
3518 :
3519 20001 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3520 20001 : }
3521 :
3522 : // a few simple numbers (decimal / decimal)
3523 : // no exponent, but uses a sign
3524 199477 : for(int i(0); i < 1000000000; i += rand() % 10000 + 1)
3525 : {
3526 199476 : std::stringstream ss;
3527 199476 : bool const negative(rand() % 1 == 0);
3528 199476 : char const *sign(negative ? "-" : (rand() % 5 == 0 ? "+" : ""));
3529 199476 : ss << sign << i / 1000;
3530 199476 : bool const floating_point(i % 1000 != 0);
3531 199476 : if(floating_point)
3532 : {
3533 199274 : ss << "." << std::setw(3) << std::setfill('0') << i % 1000;
3534 : }
3535 598428 : csspp::position pos("test.css");
3536 199476 : csspp::lexer l(ss, pos);
3537 :
3538 : //if(negative)
3539 : //{
3540 : // csspp::node::pointer_t subtract(l.next_token());
3541 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
3542 : // csspp::position const & npos(subtract->get_position());
3543 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
3544 : // CATCH_REQUIRE(npos.get_page() == 1);
3545 : // CATCH_REQUIRE(npos.get_line() == 1);
3546 : // CATCH_REQUIRE(npos.get_total_line() == 1);
3547 : //}
3548 : //else if(*sign == '+')
3549 : //{
3550 : // csspp::node::pointer_t subtract(l.next_token());
3551 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::ADD));
3552 : // csspp::position const & npos(subtract->get_position());
3553 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
3554 : // CATCH_REQUIRE(npos.get_page() == 1);
3555 : // CATCH_REQUIRE(npos.get_line() == 1);
3556 : // CATCH_REQUIRE(npos.get_total_line() == 1);
3557 : //}
3558 :
3559 199476 : if(floating_point)
3560 : {
3561 : // decimal number
3562 199274 : csspp::node::pointer_t string(l.next_token());
3563 199274 : CATCH_REQUIRE(string->is(csspp::node_type_t::DECIMAL_NUMBER));
3564 : //std::cerr << "*** from [" << ss.str()
3565 : // << "] or [" << static_cast<csspp::decimal_number_t>(i) / 1000.0
3566 : // << "] we got [" << string->get_decimal_number()
3567 : // << "] |" << fabs(string->get_decimal_number())
3568 : // << "| (sign: " << (negative ? "-" : "+") << ")\n";
3569 199274 : CATCH_REQUIRE(fabs(fabs(string->get_decimal_number()) - static_cast<csspp::decimal_number_t>(i) / 1000.0) < 0.00001);
3570 199274 : if(negative)
3571 : {
3572 199274 : CATCH_REQUIRE(string->get_decimal_number() <= 0.0);
3573 : }
3574 : else
3575 : {
3576 0 : CATCH_REQUIRE(string->get_decimal_number() >= 0.0);
3577 : }
3578 199274 : csspp::position const & npos(string->get_position());
3579 199274 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3580 199274 : CATCH_REQUIRE(npos.get_page() == 1);
3581 199274 : CATCH_REQUIRE(npos.get_line() == 1);
3582 199274 : CATCH_REQUIRE(npos.get_total_line() == 1);
3583 199274 : }
3584 : else
3585 : {
3586 : // integer
3587 202 : csspp::node::pointer_t string(l.next_token());
3588 202 : CATCH_REQUIRE(string->is(csspp::node_type_t::INTEGER));
3589 202 : CATCH_REQUIRE(string->get_integer() == (negative ? -1 : 1) * i / 1000);
3590 202 : csspp::position const & npos(string->get_position());
3591 202 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3592 202 : CATCH_REQUIRE(npos.get_page() == 1);
3593 202 : CATCH_REQUIRE(npos.get_line() == 1);
3594 202 : CATCH_REQUIRE(npos.get_total_line() == 1);
3595 202 : }
3596 :
3597 199476 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3598 199476 : }
3599 :
3600 : // a few simple decimals with an exponent
3601 20002 : for(int i(-10000); i <= 10000; ++i)
3602 : {
3603 : // numbers starting with a digit (-0.3e5)
3604 : {
3605 20001 : std::stringstream ss;
3606 20001 : auto generate_sign = [](){
3607 20001 : switch(rand() % 3)
3608 : {
3609 6756 : case 0:
3610 6756 : return "-";
3611 :
3612 6716 : case 1:
3613 6716 : return "+";
3614 :
3615 6529 : default: // case 2:
3616 6529 : return "";
3617 :
3618 : }
3619 : };
3620 20001 : char const *exponent_sign(generate_sign());
3621 20001 : int const e(rand() % 100);
3622 20001 : char const *sign(i < 0 ? "-" : (rand() % 5 == 0 ? "+" : ""));
3623 20001 : ss << sign
3624 20001 : << abs(i) / 1000
3625 20001 : << "." << std::setw(3) << std::setfill('0') << abs(i) % 1000
3626 20001 : << std::setw(0) << std::setfill('\0') << "e" << exponent_sign << e;
3627 60003 : csspp::position pos("test.css");
3628 20001 : csspp::lexer l(ss, pos);
3629 20001 : csspp::decimal_number_t our_number(static_cast<csspp::decimal_number_t>(i) / 1000.0 * pow(10.0, e * (strcmp(exponent_sign, "-") == 0 ? -1 : 1)));
3630 : //std::cerr << "*** from [" << ss.str()
3631 : // << "] or [" << our_number
3632 : // << "] sign & exponent [" << exponent_sign << "|" << e
3633 : // << "] ... ";
3634 :
3635 : // sign
3636 : //if(i < 0)
3637 : //{
3638 : // csspp::node::pointer_t subtract(l.next_token());
3639 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
3640 : // csspp::position const & npos(subtract->get_position());
3641 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
3642 : // CATCH_REQUIRE(npos.get_page() == 1);
3643 : // CATCH_REQUIRE(npos.get_line() == 1);
3644 : // CATCH_REQUIRE(npos.get_total_line() == 1);
3645 : //}
3646 : //else if(*sign == '+')
3647 : //{
3648 : // csspp::node::pointer_t subtract(l.next_token());
3649 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::ADD));
3650 : // csspp::position const & npos(subtract->get_position());
3651 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
3652 : // CATCH_REQUIRE(npos.get_page() == 1);
3653 : // CATCH_REQUIRE(npos.get_line() == 1);
3654 : // CATCH_REQUIRE(npos.get_total_line() == 1);
3655 : //}
3656 :
3657 : // decimal number
3658 : {
3659 20001 : csspp::node::pointer_t decimal_number(l.next_token());
3660 : //std::cerr << "*** type is " << static_cast<int>(decimal_number->get_type()) << " ***\n";
3661 20001 : CATCH_REQUIRE(decimal_number->is(csspp::node_type_t::DECIMAL_NUMBER));
3662 20001 : csspp::decimal_number_t const result(fabs(decimal_number->get_decimal_number()));
3663 20001 : csspp::decimal_number_t const abs_number(fabs(our_number));
3664 20001 : csspp::decimal_number_t const delta(fabs(result - abs_number));
3665 20001 : csspp::decimal_number_t const diff(delta / pow(10.0, e * (strcmp(exponent_sign, "-") == 0 ? -1 : 1)));
3666 :
3667 : //std::cerr << "we got [" << result
3668 : // << "| vs |" << abs_number
3669 : // << "| diff = " << diff
3670 : // << "\n";
3671 : //csspp::decimal_number_t r(fabs(decimal_number->get_decimal_number()));
3672 : //csspp::decimal_number_t q(fabs(our_number));
3673 : //std::cerr << std::hex
3674 : // << *reinterpret_cast<int64_t *>(&r) << "\n"
3675 : // << *reinterpret_cast<int64_t *>(&q) << " " << (r - q) << " -> " << diff << "\n";
3676 20001 : CATCH_REQUIRE(diff < 0.00001);
3677 20001 : if(*sign == '-')
3678 : {
3679 10000 : CATCH_REQUIRE(decimal_number->get_decimal_number() <= 0);
3680 : }
3681 : else
3682 : {
3683 10001 : CATCH_REQUIRE(decimal_number->get_decimal_number() >= 0);
3684 : }
3685 20001 : csspp::position const & npos(decimal_number->get_position());
3686 20001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3687 20001 : CATCH_REQUIRE(npos.get_page() == 1);
3688 20001 : CATCH_REQUIRE(npos.get_line() == 1);
3689 20001 : CATCH_REQUIRE(npos.get_total_line() == 1);
3690 20001 : }
3691 :
3692 20001 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3693 20001 : }
3694 :
3695 : // numbers starting with a period (.25e3)
3696 20001 : if(i >= -999 && i <= 999)
3697 : {
3698 1999 : std::stringstream ss;
3699 1999 : auto generate_sign = [](){
3700 1999 : switch(rand() % 3)
3701 : {
3702 651 : case 0:
3703 651 : return "-";
3704 :
3705 707 : case 1:
3706 707 : return "+";
3707 :
3708 641 : default: // case 2:
3709 641 : return "";
3710 :
3711 : }
3712 : };
3713 1999 : char const *exponent_sign(generate_sign());
3714 1999 : int const e(rand() % 100);
3715 1999 : char const *sign(i < 0 ? "-" : (rand() % 5 == 0 ? "+" : ""));
3716 : ss << sign
3717 : //<< abs(i) / 1000 -- this would always be '0' here
3718 1999 : << "." << std::setw(3) << std::setfill('0') << abs(i) % 1000
3719 1999 : << std::setw(0) << std::setfill('\0') << "e" << exponent_sign << e;
3720 5997 : csspp::position pos("test.css");
3721 1999 : csspp::lexer l(ss, pos);
3722 1999 : csspp::decimal_number_t our_number(static_cast<csspp::decimal_number_t>(i) / 1000.0 * pow(10.0, e * (strcmp(exponent_sign, "-") == 0 ? -1 : 1)));
3723 : //std::cerr << "*** from [" << ss.str()
3724 : // << "] or [" << our_number
3725 : // << "] sign & exponent [" << exponent_sign << "|" << e
3726 : // << "] ... ";
3727 :
3728 : // sign
3729 : //if(i < 0)
3730 : //{
3731 : // csspp::node::pointer_t subtract(l.next_token());
3732 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
3733 : // csspp::position const & npos(subtract->get_position());
3734 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
3735 : // CATCH_REQUIRE(npos.get_page() == 1);
3736 : // CATCH_REQUIRE(npos.get_line() == 1);
3737 : // CATCH_REQUIRE(npos.get_total_line() == 1);
3738 : //}
3739 : //else if(*sign == '+')
3740 : //{
3741 : // csspp::node::pointer_t subtract(l.next_token());
3742 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::ADD));
3743 : // csspp::position const & npos(subtract->get_position());
3744 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
3745 : // CATCH_REQUIRE(npos.get_page() == 1);
3746 : // CATCH_REQUIRE(npos.get_line() == 1);
3747 : // CATCH_REQUIRE(npos.get_total_line() == 1);
3748 : //}
3749 :
3750 : // decimal number
3751 : {
3752 1999 : csspp::node::pointer_t decimal_number(l.next_token());
3753 1999 : CATCH_REQUIRE(decimal_number->is(csspp::node_type_t::DECIMAL_NUMBER));
3754 1999 : csspp::decimal_number_t const result(fabs(decimal_number->get_decimal_number()));
3755 1999 : csspp::decimal_number_t const abs_number(fabs(our_number));
3756 1999 : csspp::decimal_number_t const delta(fabs(result - abs_number));
3757 1999 : csspp::decimal_number_t const diff(delta / pow(10.0, e * (strcmp(exponent_sign, "-") == 0 ? -1 : 1)));
3758 :
3759 : //std::cerr << "we got [" << result
3760 : // << "| vs |" << abs_number
3761 : // << "| diff = " << diff
3762 : // << "\n";
3763 : //csspp::decimal_number_t r(fabs(decimal_number->get_decimal_number()));
3764 : //csspp::decimal_number_t q(fabs(our_number));
3765 : //std::cerr << std::hex
3766 : // << *reinterpret_cast<int64_t *>(&r) << "\n"
3767 : // << *reinterpret_cast<int64_t *>(&q) << " " << (r - q) << " -> " << diff << "\n";
3768 1999 : CATCH_REQUIRE(diff < 0.00001);
3769 1999 : if(*sign == '-')
3770 : {
3771 999 : CATCH_REQUIRE(decimal_number->get_decimal_number() <= 0);
3772 : }
3773 : else
3774 : {
3775 1000 : CATCH_REQUIRE(decimal_number->get_decimal_number() >= 0);
3776 : }
3777 1999 : csspp::position const & npos(decimal_number->get_position());
3778 1999 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3779 1999 : CATCH_REQUIRE(npos.get_page() == 1);
3780 1999 : CATCH_REQUIRE(npos.get_line() == 1);
3781 1999 : CATCH_REQUIRE(npos.get_total_line() == 1);
3782 1999 : }
3783 :
3784 1999 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3785 1999 : }
3786 : }
3787 :
3788 : // check maximum 64 bit number
3789 : {
3790 1 : std::stringstream ss;
3791 : // largest 64 bit positive number is 9223372036854775807
3792 1 : ss << "perfect: 9223372036854775807";
3793 3 : csspp::position pos("test.css");
3794 1 : csspp::lexer l(ss, pos);
3795 :
3796 : // identifier
3797 : {
3798 1 : csspp::node::pointer_t identifier(l.next_token());
3799 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
3800 1 : CATCH_REQUIRE(identifier->get_string() == "perfect");
3801 1 : csspp::position const & npos(identifier->get_position());
3802 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3803 1 : CATCH_REQUIRE(npos.get_page() == 1);
3804 1 : CATCH_REQUIRE(npos.get_line() == 1);
3805 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3806 1 : }
3807 :
3808 : // colon
3809 : {
3810 1 : csspp::node::pointer_t colon(l.next_token());
3811 1 : CATCH_REQUIRE(colon->is(csspp::node_type_t::COLON));
3812 1 : csspp::position const & npos(colon->get_position());
3813 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3814 1 : CATCH_REQUIRE(npos.get_page() == 1);
3815 1 : CATCH_REQUIRE(npos.get_line() == 1);
3816 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3817 1 : }
3818 :
3819 : // whitespace
3820 : {
3821 1 : csspp::node::pointer_t whitespace(l.next_token());
3822 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
3823 1 : csspp::position const & npos(whitespace->get_position());
3824 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3825 1 : CATCH_REQUIRE(npos.get_page() == 1);
3826 1 : CATCH_REQUIRE(npos.get_line() == 1);
3827 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3828 1 : }
3829 :
3830 : // decimal number
3831 : {
3832 1 : csspp::node::pointer_t integer(l.next_token());
3833 1 : CATCH_REQUIRE(integer->is(csspp::node_type_t::INTEGER));
3834 1 : CATCH_REQUIRE(integer->get_integer() == 9223372036854775807LL);
3835 1 : csspp::position const & npos(integer->get_position());
3836 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3837 1 : CATCH_REQUIRE(npos.get_page() == 1);
3838 1 : CATCH_REQUIRE(npos.get_line() == 1);
3839 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3840 1 : }
3841 :
3842 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3843 1 : }
3844 :
3845 : // check a number so large that it fails
3846 : {
3847 1 : std::stringstream ss;
3848 : // largest 64 bit positive number is 9223372036854775807
3849 1 : ss << "too\\ large: 10000000000000000000";
3850 3 : csspp::position pos("test.css");
3851 1 : csspp::lexer l(ss, pos);
3852 :
3853 : // identifier
3854 : {
3855 1 : csspp::node::pointer_t identifier(l.next_token());
3856 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
3857 1 : CATCH_REQUIRE(identifier->get_string() == "too large");
3858 1 : csspp::position const & npos(identifier->get_position());
3859 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3860 1 : CATCH_REQUIRE(npos.get_page() == 1);
3861 1 : CATCH_REQUIRE(npos.get_line() == 1);
3862 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3863 1 : }
3864 :
3865 : // colon
3866 : {
3867 1 : csspp::node::pointer_t colon(l.next_token());
3868 1 : CATCH_REQUIRE(colon->is(csspp::node_type_t::COLON));
3869 1 : csspp::position const & npos(colon->get_position());
3870 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3871 1 : CATCH_REQUIRE(npos.get_page() == 1);
3872 1 : CATCH_REQUIRE(npos.get_line() == 1);
3873 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3874 1 : }
3875 :
3876 : // whitespace
3877 : {
3878 1 : csspp::node::pointer_t whitespace(l.next_token());
3879 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
3880 1 : csspp::position const & npos(whitespace->get_position());
3881 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3882 1 : CATCH_REQUIRE(npos.get_page() == 1);
3883 1 : CATCH_REQUIRE(npos.get_line() == 1);
3884 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3885 1 : }
3886 :
3887 : // integer
3888 : {
3889 1 : csspp::node::pointer_t integer(l.next_token());
3890 1 : CATCH_REQUIRE(integer->is(csspp::node_type_t::INTEGER));
3891 : //CATCH_REQUIRE(integer->get_integer() == ???); -- there is an overflow so we decide not to replicate it here
3892 1 : csspp::position const & npos(integer->get_position());
3893 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3894 1 : CATCH_REQUIRE(npos.get_page() == 1);
3895 1 : CATCH_REQUIRE(npos.get_line() == 1);
3896 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3897 :
3898 1 : VERIFY_ERRORS("test.css(1): error: integral part too large for a number.\n");
3899 1 : }
3900 :
3901 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3902 1 : }
3903 :
3904 : // check a decimal part that's too large
3905 : // (we limit those to 8 digits at this time)
3906 : {
3907 1 : std::stringstream ss;
3908 1 : ss << "decimal_part_too_long: 1.000000000000000000000";
3909 3 : csspp::position pos("test.css");
3910 1 : csspp::lexer l(ss, pos);
3911 :
3912 : // identifier
3913 : {
3914 1 : csspp::node::pointer_t identifier(l.next_token());
3915 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
3916 1 : CATCH_REQUIRE(identifier->get_string() == "decimal_part_too_long");
3917 1 : csspp::position const & npos(identifier->get_position());
3918 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3919 1 : CATCH_REQUIRE(npos.get_page() == 1);
3920 1 : CATCH_REQUIRE(npos.get_line() == 1);
3921 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3922 1 : }
3923 :
3924 : // colon
3925 : {
3926 1 : csspp::node::pointer_t colon(l.next_token());
3927 1 : CATCH_REQUIRE(colon->is(csspp::node_type_t::COLON));
3928 1 : csspp::position const & npos(colon->get_position());
3929 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3930 1 : CATCH_REQUIRE(npos.get_page() == 1);
3931 1 : CATCH_REQUIRE(npos.get_line() == 1);
3932 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3933 1 : }
3934 :
3935 : // whitespace
3936 : {
3937 1 : csspp::node::pointer_t whitespace(l.next_token());
3938 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
3939 1 : csspp::position const & npos(whitespace->get_position());
3940 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3941 1 : CATCH_REQUIRE(npos.get_page() == 1);
3942 1 : CATCH_REQUIRE(npos.get_line() == 1);
3943 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3944 1 : }
3945 :
3946 : // decimal number
3947 : {
3948 1 : csspp::node::pointer_t decimal_number(l.next_token());
3949 1 : CATCH_REQUIRE(decimal_number->is(csspp::node_type_t::DECIMAL_NUMBER));
3950 : //CATCH_REQUIRE(decimal_number->get_decimal_number() == ???); -- there may be an overflow so we decide not to replicate it here
3951 1 : csspp::position const & npos(decimal_number->get_position());
3952 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3953 1 : CATCH_REQUIRE(npos.get_page() == 1);
3954 1 : CATCH_REQUIRE(npos.get_line() == 1);
3955 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3956 :
3957 1 : VERIFY_ERRORS("test.css(1): error: fraction too large for a decimal number.\n");
3958 1 : }
3959 :
3960 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
3961 1 : }
3962 :
3963 : // decimal number with no digits in the decimal fraction part is an error
3964 : {
3965 1 : std::stringstream ss;
3966 1 : ss << "font-size: 154.;";
3967 3 : csspp::position pos("test.css");
3968 1 : csspp::lexer l(ss, pos);
3969 :
3970 : // identifier
3971 : {
3972 1 : csspp::node::pointer_t identifier(l.next_token());
3973 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
3974 1 : CATCH_REQUIRE(identifier->get_string() == "font-size");
3975 1 : csspp::position const & npos(identifier->get_position());
3976 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3977 1 : CATCH_REQUIRE(npos.get_page() == 1);
3978 1 : CATCH_REQUIRE(npos.get_line() == 1);
3979 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3980 1 : }
3981 :
3982 : // colon
3983 : {
3984 1 : csspp::node::pointer_t colon(l.next_token());
3985 1 : CATCH_REQUIRE(colon->is(csspp::node_type_t::COLON));
3986 1 : csspp::position const & npos(colon->get_position());
3987 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3988 1 : CATCH_REQUIRE(npos.get_page() == 1);
3989 1 : CATCH_REQUIRE(npos.get_line() == 1);
3990 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
3991 1 : }
3992 :
3993 : // whitespace
3994 : {
3995 1 : csspp::node::pointer_t whitespace(l.next_token());
3996 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
3997 1 : csspp::position const & npos(whitespace->get_position());
3998 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
3999 1 : CATCH_REQUIRE(npos.get_page() == 1);
4000 1 : CATCH_REQUIRE(npos.get_line() == 1);
4001 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4002 1 : }
4003 :
4004 : // decimal number
4005 : {
4006 1 : csspp::node::pointer_t decimal_number(l.next_token());
4007 1 : CATCH_REQUIRE(decimal_number->is(csspp::node_type_t::DECIMAL_NUMBER));
4008 1 : CATCH_REQUIRE(decimal_number->get_decimal_number() == 154.0_a);
4009 1 : csspp::position const & npos(decimal_number->get_position());
4010 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4011 1 : CATCH_REQUIRE(npos.get_page() == 1);
4012 1 : CATCH_REQUIRE(npos.get_line() == 1);
4013 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4014 :
4015 1 : VERIFY_ERRORS("test.css(1): error: decimal number must have at least one digit after the decimal point.\n");
4016 1 : }
4017 :
4018 : // semi-colon
4019 : {
4020 1 : csspp::node::pointer_t whitespace(l.next_token());
4021 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::SEMICOLON));
4022 1 : csspp::position const & npos(whitespace->get_position());
4023 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4024 1 : CATCH_REQUIRE(npos.get_page() == 1);
4025 1 : CATCH_REQUIRE(npos.get_line() == 1);
4026 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4027 1 : }
4028 :
4029 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
4030 1 : }
4031 :
4032 : // try parsing an expression
4033 : {
4034 1 : std::stringstream ss;
4035 1 : ss << "font-size: 154*3;";
4036 3 : csspp::position pos("test.css");
4037 1 : csspp::lexer l(ss, pos);
4038 :
4039 : // identifier
4040 : {
4041 1 : csspp::node::pointer_t identifier(l.next_token());
4042 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
4043 1 : CATCH_REQUIRE(identifier->get_string() == "font-size");
4044 1 : csspp::position const & npos(identifier->get_position());
4045 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4046 1 : CATCH_REQUIRE(npos.get_page() == 1);
4047 1 : CATCH_REQUIRE(npos.get_line() == 1);
4048 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4049 1 : }
4050 :
4051 : // colon
4052 : {
4053 1 : csspp::node::pointer_t colon(l.next_token());
4054 1 : CATCH_REQUIRE(colon->is(csspp::node_type_t::COLON));
4055 1 : csspp::position const & npos(colon->get_position());
4056 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4057 1 : CATCH_REQUIRE(npos.get_page() == 1);
4058 1 : CATCH_REQUIRE(npos.get_line() == 1);
4059 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4060 1 : }
4061 :
4062 : // whitespace
4063 : {
4064 1 : csspp::node::pointer_t whitespace(l.next_token());
4065 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
4066 1 : csspp::position const & npos(whitespace->get_position());
4067 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4068 1 : CATCH_REQUIRE(npos.get_page() == 1);
4069 1 : CATCH_REQUIRE(npos.get_line() == 1);
4070 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4071 1 : }
4072 :
4073 : // integer
4074 : {
4075 1 : csspp::node::pointer_t integer(l.next_token());
4076 1 : CATCH_REQUIRE(integer->is(csspp::node_type_t::INTEGER));
4077 1 : CATCH_REQUIRE(integer->get_integer() == 154);
4078 1 : csspp::position const & npos(integer->get_position());
4079 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4080 1 : CATCH_REQUIRE(npos.get_page() == 1);
4081 1 : CATCH_REQUIRE(npos.get_line() == 1);
4082 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4083 1 : }
4084 :
4085 : // multiply
4086 : {
4087 1 : csspp::node::pointer_t integer(l.next_token());
4088 1 : CATCH_REQUIRE(integer->is(csspp::node_type_t::MULTIPLY));
4089 1 : csspp::position const & npos(integer->get_position());
4090 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4091 1 : CATCH_REQUIRE(npos.get_page() == 1);
4092 1 : CATCH_REQUIRE(npos.get_line() == 1);
4093 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4094 1 : }
4095 :
4096 : // integer
4097 : {
4098 1 : csspp::node::pointer_t integer(l.next_token());
4099 1 : CATCH_REQUIRE(integer->is(csspp::node_type_t::INTEGER));
4100 1 : CATCH_REQUIRE(integer->get_integer() == 3);
4101 1 : csspp::position const & npos(integer->get_position());
4102 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4103 1 : CATCH_REQUIRE(npos.get_page() == 1);
4104 1 : CATCH_REQUIRE(npos.get_line() == 1);
4105 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4106 1 : }
4107 :
4108 : // semi-colon
4109 : {
4110 1 : csspp::node::pointer_t whitespace(l.next_token());
4111 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::SEMICOLON));
4112 1 : csspp::position const & npos(whitespace->get_position());
4113 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4114 1 : CATCH_REQUIRE(npos.get_page() == 1);
4115 1 : CATCH_REQUIRE(npos.get_line() == 1);
4116 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4117 1 : }
4118 :
4119 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
4120 1 : }
4121 :
4122 : // test with an exponent that's too large
4123 : {
4124 1 : std::stringstream ss;
4125 1 : ss << "font-size: 154e-1024;";
4126 3 : csspp::position pos("test.css");
4127 1 : csspp::lexer l(ss, pos);
4128 :
4129 : // identifier
4130 : {
4131 1 : csspp::node::pointer_t identifier(l.next_token());
4132 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
4133 1 : CATCH_REQUIRE(identifier->get_string() == "font-size");
4134 1 : csspp::position const & npos(identifier->get_position());
4135 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4136 1 : CATCH_REQUIRE(npos.get_page() == 1);
4137 1 : CATCH_REQUIRE(npos.get_line() == 1);
4138 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4139 1 : }
4140 :
4141 : // colon
4142 : {
4143 1 : csspp::node::pointer_t colon(l.next_token());
4144 1 : CATCH_REQUIRE(colon->is(csspp::node_type_t::COLON));
4145 1 : csspp::position const & npos(colon->get_position());
4146 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4147 1 : CATCH_REQUIRE(npos.get_page() == 1);
4148 1 : CATCH_REQUIRE(npos.get_line() == 1);
4149 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4150 1 : }
4151 :
4152 : // whitespace
4153 : {
4154 1 : csspp::node::pointer_t whitespace(l.next_token());
4155 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
4156 1 : csspp::position const & npos(whitespace->get_position());
4157 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4158 1 : CATCH_REQUIRE(npos.get_page() == 1);
4159 1 : CATCH_REQUIRE(npos.get_line() == 1);
4160 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4161 1 : }
4162 :
4163 : // decimal number
4164 : {
4165 1 : csspp::node::pointer_t decimal_number(l.next_token());
4166 1 : CATCH_REQUIRE(decimal_number->is(csspp::node_type_t::DECIMAL_NUMBER));
4167 : //CATCH_REQUIRE(decimal_number->get_decimal_number() == ...); -- this is not a valid number
4168 1 : csspp::position const & npos(decimal_number->get_position());
4169 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4170 1 : CATCH_REQUIRE(npos.get_page() == 1);
4171 1 : CATCH_REQUIRE(npos.get_line() == 1);
4172 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4173 :
4174 1 : VERIFY_ERRORS("test.css(1): error: exponent too large for a decimal number.\n");
4175 1 : }
4176 :
4177 : // semi-colon
4178 : {
4179 1 : csspp::node::pointer_t whitespace(l.next_token());
4180 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::SEMICOLON));
4181 1 : csspp::position const & npos(whitespace->get_position());
4182 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4183 1 : CATCH_REQUIRE(npos.get_page() == 1);
4184 1 : CATCH_REQUIRE(npos.get_line() == 1);
4185 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4186 1 : }
4187 :
4188 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
4189 1 : }
4190 :
4191 : // no error left over
4192 1 : VERIFY_ERRORS("");
4193 1 : }
4194 :
4195 1 : CATCH_TEST_CASE("Dimensions", "[lexer] [number] [dimension] [identifier]")
4196 : {
4197 : // well known dimensions with integers
4198 : {
4199 1 : char const *dimensions[] = {
4200 : "em", // character em
4201 : "px", // pixel
4202 : "pt" // point
4203 : };
4204 20002 : for(int i(-10000); i <= 10000; ++i)
4205 : {
4206 80004 : for(size_t j(0); j < sizeof(dimensions) / sizeof(dimensions[0]); ++j)
4207 : {
4208 60003 : std::stringstream ss;
4209 60003 : ss << i << dimensions[j];
4210 : // direct escape?
4211 60003 : if(dimensions[j][0] > 'f')
4212 : {
4213 40002 : ss << "," << i << "\\" << dimensions[j];
4214 : }
4215 180009 : ss << "," << i << "\\" << std::hex << static_cast<int>(dimensions[j][0]) << " " << std::string(dimensions[j]).substr(1)
4216 120006 : << "," << std::dec << i << " " << dimensions[j]; // prove it does not work when we have a space
4217 180009 : csspp::position pos("test.css");
4218 60003 : csspp::lexer l(ss, pos);
4219 :
4220 : // sign
4221 : //if(i < 0)
4222 : //{
4223 : // csspp::node::pointer_t integer(l.next_token());
4224 : // CATCH_REQUIRE(integer->is(csspp::node_type_t::SUBTRACT));
4225 : // csspp::position const & npos(integer->get_position());
4226 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4227 : // CATCH_REQUIRE(npos.get_page() == 1);
4228 : // CATCH_REQUIRE(npos.get_line() == 1);
4229 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4230 : //}
4231 :
4232 : // dimension
4233 : {
4234 : // a dimension is an integer or a decimal number
4235 : // with a string expressing the dimension
4236 60003 : csspp::node::pointer_t dimension(l.next_token());
4237 60003 : CATCH_REQUIRE(dimension->is(csspp::node_type_t::INTEGER));
4238 60003 : CATCH_REQUIRE(dimension->get_integer() == i);
4239 60003 : CATCH_REQUIRE(dimension->get_string() == dimensions[j]);
4240 60003 : csspp::position const & npos(dimension->get_position());
4241 60003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4242 60003 : CATCH_REQUIRE(npos.get_page() == 1);
4243 60003 : CATCH_REQUIRE(npos.get_line() == 1);
4244 60003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4245 60003 : }
4246 :
4247 : // direct escape?
4248 60003 : if(dimensions[j][0] > 'f')
4249 : {
4250 : // comma
4251 : {
4252 40002 : csspp::node::pointer_t comma(l.next_token());
4253 40002 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
4254 40002 : csspp::position const & npos(comma->get_position());
4255 40002 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4256 40002 : CATCH_REQUIRE(npos.get_page() == 1);
4257 40002 : CATCH_REQUIRE(npos.get_line() == 1);
4258 40002 : CATCH_REQUIRE(npos.get_total_line() == 1);
4259 40002 : }
4260 :
4261 : // sign
4262 : //if(i < 0)
4263 : //{
4264 : // csspp::node::pointer_t integer(l.next_token());
4265 : // CATCH_REQUIRE(integer->is(csspp::node_type_t::SUBTRACT));
4266 : // csspp::position const & npos(integer->get_position());
4267 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4268 : // CATCH_REQUIRE(npos.get_page() == 1);
4269 : // CATCH_REQUIRE(npos.get_line() == 1);
4270 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4271 : //}
4272 :
4273 : // dimension
4274 : {
4275 : // a dimension is an integer or a decimal number
4276 : // with a string expressing the dimension
4277 40002 : csspp::node::pointer_t dimension(l.next_token());
4278 40002 : CATCH_REQUIRE(dimension->is(csspp::node_type_t::INTEGER));
4279 40002 : CATCH_REQUIRE(dimension->get_integer() == i);
4280 40002 : CATCH_REQUIRE(dimension->get_string() == dimensions[j]);
4281 40002 : csspp::position const & npos(dimension->get_position());
4282 40002 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4283 40002 : CATCH_REQUIRE(npos.get_page() == 1);
4284 40002 : CATCH_REQUIRE(npos.get_line() == 1);
4285 40002 : CATCH_REQUIRE(npos.get_total_line() == 1);
4286 40002 : }
4287 : }
4288 :
4289 : // comma
4290 : {
4291 60003 : csspp::node::pointer_t comma(l.next_token());
4292 60003 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
4293 60003 : csspp::position const & npos(comma->get_position());
4294 60003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4295 60003 : CATCH_REQUIRE(npos.get_page() == 1);
4296 60003 : CATCH_REQUIRE(npos.get_line() == 1);
4297 60003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4298 60003 : }
4299 :
4300 : // sign
4301 : //if(i < 0)
4302 : //{
4303 : // csspp::node::pointer_t integer(l.next_token());
4304 : // CATCH_REQUIRE(integer->is(csspp::node_type_t::SUBTRACT));
4305 : // csspp::position const & npos(integer->get_position());
4306 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4307 : // CATCH_REQUIRE(npos.get_page() == 1);
4308 : // CATCH_REQUIRE(npos.get_line() == 1);
4309 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4310 : //}
4311 :
4312 : // dimension
4313 : {
4314 : // a dimension is an integer or a decimal number
4315 : // with a string expressing the dimension
4316 60003 : csspp::node::pointer_t dimension(l.next_token());
4317 60003 : CATCH_REQUIRE(dimension->is(csspp::node_type_t::INTEGER));
4318 60003 : CATCH_REQUIRE(dimension->get_integer() == i);
4319 60003 : CATCH_REQUIRE(dimension->get_string() == dimensions[j]);
4320 60003 : csspp::position const & npos(dimension->get_position());
4321 60003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4322 60003 : CATCH_REQUIRE(npos.get_page() == 1);
4323 60003 : CATCH_REQUIRE(npos.get_line() == 1);
4324 60003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4325 60003 : }
4326 :
4327 : // comma
4328 : {
4329 60003 : csspp::node::pointer_t comma(l.next_token());
4330 60003 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
4331 60003 : csspp::position const & npos(comma->get_position());
4332 60003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4333 60003 : CATCH_REQUIRE(npos.get_page() == 1);
4334 60003 : CATCH_REQUIRE(npos.get_line() == 1);
4335 60003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4336 60003 : }
4337 :
4338 : // sign
4339 : //if(i < 0)
4340 : //{
4341 : // csspp::node::pointer_t integer(l.next_token());
4342 : // CATCH_REQUIRE(integer->is(csspp::node_type_t::SUBTRACT));
4343 : // csspp::position const & npos(integer->get_position());
4344 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4345 : // CATCH_REQUIRE(npos.get_page() == 1);
4346 : // CATCH_REQUIRE(npos.get_line() == 1);
4347 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4348 : //}
4349 :
4350 : // integer (separated!)
4351 : {
4352 60003 : csspp::node::pointer_t integer(l.next_token());
4353 60003 : CATCH_REQUIRE(integer->is(csspp::node_type_t::INTEGER));
4354 60003 : CATCH_REQUIRE(integer->get_integer() == i);
4355 60003 : CATCH_REQUIRE(integer->get_string() == "");
4356 60003 : csspp::position const & npos(integer->get_position());
4357 60003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4358 60003 : CATCH_REQUIRE(npos.get_page() == 1);
4359 60003 : CATCH_REQUIRE(npos.get_line() == 1);
4360 60003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4361 60003 : }
4362 :
4363 : // whitespace
4364 : {
4365 60003 : csspp::node::pointer_t whitespace(l.next_token());
4366 60003 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
4367 60003 : csspp::position const & npos(whitespace->get_position());
4368 60003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4369 60003 : CATCH_REQUIRE(npos.get_page() == 1);
4370 60003 : CATCH_REQUIRE(npos.get_line() == 1);
4371 60003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4372 60003 : }
4373 :
4374 : // "dimension" (as a separate identifier)
4375 : {
4376 : // a dimension is an integer or a decimal number
4377 : // with a string expressing the dimension
4378 60003 : csspp::node::pointer_t dimension(l.next_token());
4379 60003 : CATCH_REQUIRE(dimension->is(csspp::node_type_t::IDENTIFIER));
4380 60003 : CATCH_REQUIRE(dimension->get_string() == dimensions[j]);
4381 60003 : csspp::position const & npos(dimension->get_position());
4382 60003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4383 60003 : CATCH_REQUIRE(npos.get_page() == 1);
4384 60003 : CATCH_REQUIRE(npos.get_line() == 1);
4385 60003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4386 60003 : }
4387 60003 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
4388 60003 : }
4389 : }
4390 : }
4391 :
4392 : // well known dimensions with decimal numbers
4393 : {
4394 1 : char const *dimensions[] = {
4395 : "em", // character em
4396 : "px", // pixel
4397 : "pt" // point
4398 : };
4399 2002 : for(int i(-1000); i <= 1000; ++i)
4400 : {
4401 8004 : for(size_t j(0); j < sizeof(dimensions) / sizeof(dimensions[0]); ++j)
4402 : {
4403 6003 : std::stringstream ss;
4404 6003 : ss << (i < 0 ? "-" : "") << abs(i) / 100 << "." << std::setw(2) << std::setfill('0') << abs(i % 100) << dimensions[j]
4405 6003 : << "," << (i < 0 ? "-" : "") << abs(i) / 100 << "." << std::setw(2) << abs(i % 100) << " " << dimensions[j]; // prove it does not work when we have a space
4406 18009 : csspp::position pos("test.css");
4407 6003 : csspp::lexer l(ss, pos);
4408 :
4409 : // sign
4410 : //if(i < 0)
4411 : //{
4412 : // csspp::node::pointer_t integer(l.next_token());
4413 : // CATCH_REQUIRE(integer->is(csspp::node_type_t::SUBTRACT));
4414 : // csspp::position const & npos(integer->get_position());
4415 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4416 : // CATCH_REQUIRE(npos.get_page() == 1);
4417 : // CATCH_REQUIRE(npos.get_line() == 1);
4418 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4419 : //}
4420 :
4421 : // dimension
4422 : {
4423 : // a dimension is an integer or a decimal number
4424 : // with a string expressing the dimension
4425 6003 : csspp::node::pointer_t dimension(l.next_token());
4426 6003 : CATCH_REQUIRE(dimension->is(csspp::node_type_t::DECIMAL_NUMBER));
4427 6003 : CATCH_REQUIRE(fabs(dimension->get_decimal_number() - i / 100.0) < 0.00001);
4428 6003 : CATCH_REQUIRE(dimension->get_string() == dimensions[j]);
4429 6003 : csspp::position const & npos(dimension->get_position());
4430 6003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4431 6003 : CATCH_REQUIRE(npos.get_page() == 1);
4432 6003 : CATCH_REQUIRE(npos.get_line() == 1);
4433 6003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4434 6003 : }
4435 :
4436 : // comma
4437 : {
4438 6003 : csspp::node::pointer_t comma(l.next_token());
4439 6003 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
4440 6003 : csspp::position const & npos(comma->get_position());
4441 6003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4442 6003 : CATCH_REQUIRE(npos.get_page() == 1);
4443 6003 : CATCH_REQUIRE(npos.get_line() == 1);
4444 6003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4445 6003 : }
4446 :
4447 : // sign
4448 : //if(i < 0)
4449 : //{
4450 : // csspp::node::pointer_t integer(l.next_token());
4451 : // CATCH_REQUIRE(integer->is(csspp::node_type_t::SUBTRACT));
4452 : // csspp::position const & npos(integer->get_position());
4453 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4454 : // CATCH_REQUIRE(npos.get_page() == 1);
4455 : // CATCH_REQUIRE(npos.get_line() == 1);
4456 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4457 : //}
4458 :
4459 : // decimal number (separated!)
4460 : {
4461 6003 : csspp::node::pointer_t decimal_number(l.next_token());
4462 6003 : CATCH_REQUIRE(decimal_number->is(csspp::node_type_t::DECIMAL_NUMBER));
4463 6003 : CATCH_REQUIRE(fabs(decimal_number->get_decimal_number() - i / 100.0) < 0.00001);
4464 6003 : CATCH_REQUIRE(decimal_number->get_string() == "");
4465 6003 : csspp::position const & npos(decimal_number->get_position());
4466 6003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4467 6003 : CATCH_REQUIRE(npos.get_page() == 1);
4468 6003 : CATCH_REQUIRE(npos.get_line() == 1);
4469 6003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4470 6003 : }
4471 :
4472 : // whitespace
4473 : {
4474 6003 : csspp::node::pointer_t whitespace(l.next_token());
4475 6003 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
4476 6003 : csspp::position const & npos(whitespace->get_position());
4477 6003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4478 6003 : CATCH_REQUIRE(npos.get_page() == 1);
4479 6003 : CATCH_REQUIRE(npos.get_line() == 1);
4480 6003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4481 6003 : }
4482 :
4483 : // "dimension" (as a separate identifier)
4484 : {
4485 : // a dimension is an integer or a decimal number
4486 : // with a string expressing the dimension
4487 6003 : csspp::node::pointer_t dimension(l.next_token());
4488 6003 : CATCH_REQUIRE(dimension->is(csspp::node_type_t::IDENTIFIER));
4489 6003 : CATCH_REQUIRE(dimension->get_string() == dimensions[j]);
4490 6003 : csspp::position const & npos(dimension->get_position());
4491 6003 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4492 6003 : CATCH_REQUIRE(npos.get_page() == 1);
4493 6003 : CATCH_REQUIRE(npos.get_line() == 1);
4494 6003 : CATCH_REQUIRE(npos.get_total_line() == 1);
4495 6003 : }
4496 6003 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
4497 6003 : }
4498 : }
4499 : }
4500 :
4501 : // decimal numbers that start with "." or "-."
4502 : {
4503 1 : char const *dimensions[] = {
4504 : "em", // character em
4505 : "px", // pixel
4506 : "pt" // point
4507 : };
4508 200 : for(int i(-99); i <= 99; ++i)
4509 : {
4510 796 : for(size_t j(0); j < sizeof(dimensions) / sizeof(dimensions[0]); ++j)
4511 : {
4512 597 : std::stringstream ss;
4513 597 : ss << (i < 0 ? "-" : "") << "." << std::setw(2) << std::setfill('0') << abs(i) << dimensions[j]
4514 597 : << "," << (i < 0 ? "-" : "") << "." << std::setw(2) << abs(i) << " " << dimensions[j]; // prove it does not work when we have a space
4515 1791 : csspp::position pos("test.css");
4516 597 : csspp::lexer l(ss, pos);
4517 :
4518 : // sign
4519 : //if(i < 0)
4520 : //{
4521 : // csspp::node::pointer_t integer(l.next_token());
4522 : // CATCH_REQUIRE(integer->is(csspp::node_type_t::SUBTRACT));
4523 : // csspp::position const & npos(integer->get_position());
4524 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4525 : // CATCH_REQUIRE(npos.get_page() == 1);
4526 : // CATCH_REQUIRE(npos.get_line() == 1);
4527 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4528 : //}
4529 :
4530 : // dimension
4531 : {
4532 : // a dimension is an integer or a decimal number
4533 : // with a string expressing the dimension
4534 597 : csspp::node::pointer_t dimension(l.next_token());
4535 597 : CATCH_REQUIRE(dimension->is(csspp::node_type_t::DECIMAL_NUMBER));
4536 597 : CATCH_REQUIRE(fabs(dimension->get_decimal_number() - i / 100.0) < 0.00001);
4537 597 : CATCH_REQUIRE(dimension->get_string() == dimensions[j]);
4538 597 : csspp::position const & npos(dimension->get_position());
4539 597 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4540 597 : CATCH_REQUIRE(npos.get_page() == 1);
4541 597 : CATCH_REQUIRE(npos.get_line() == 1);
4542 597 : CATCH_REQUIRE(npos.get_total_line() == 1);
4543 597 : }
4544 :
4545 : // comma
4546 : {
4547 597 : csspp::node::pointer_t comma(l.next_token());
4548 597 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
4549 597 : csspp::position const & npos(comma->get_position());
4550 597 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4551 597 : CATCH_REQUIRE(npos.get_page() == 1);
4552 597 : CATCH_REQUIRE(npos.get_line() == 1);
4553 597 : CATCH_REQUIRE(npos.get_total_line() == 1);
4554 597 : }
4555 :
4556 : // sign
4557 : //if(i < 0)
4558 : //{
4559 : // csspp::node::pointer_t integer(l.next_token());
4560 : // CATCH_REQUIRE(integer->is(csspp::node_type_t::SUBTRACT));
4561 : // csspp::position const & npos(integer->get_position());
4562 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4563 : // CATCH_REQUIRE(npos.get_page() == 1);
4564 : // CATCH_REQUIRE(npos.get_line() == 1);
4565 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4566 : //}
4567 :
4568 : // decimal number (separated!)
4569 : {
4570 597 : csspp::node::pointer_t decimal_number(l.next_token());
4571 597 : CATCH_REQUIRE(decimal_number->is(csspp::node_type_t::DECIMAL_NUMBER));
4572 597 : CATCH_REQUIRE(fabs(decimal_number->get_decimal_number() - i / 100.0) < 0.00001);
4573 597 : CATCH_REQUIRE(decimal_number->get_string() == "");
4574 597 : csspp::position const & npos(decimal_number->get_position());
4575 597 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4576 597 : CATCH_REQUIRE(npos.get_page() == 1);
4577 597 : CATCH_REQUIRE(npos.get_line() == 1);
4578 597 : CATCH_REQUIRE(npos.get_total_line() == 1);
4579 597 : }
4580 :
4581 : // whitespace
4582 : {
4583 597 : csspp::node::pointer_t whitespace(l.next_token());
4584 597 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
4585 597 : csspp::position const & npos(whitespace->get_position());
4586 597 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4587 597 : CATCH_REQUIRE(npos.get_page() == 1);
4588 597 : CATCH_REQUIRE(npos.get_line() == 1);
4589 597 : CATCH_REQUIRE(npos.get_total_line() == 1);
4590 597 : }
4591 :
4592 : // "dimension" (as a separate identifier)
4593 : {
4594 : // a dimension is an integer or a decimal number
4595 : // with a string expressing the dimension
4596 597 : csspp::node::pointer_t dimension(l.next_token());
4597 597 : CATCH_REQUIRE(dimension->is(csspp::node_type_t::IDENTIFIER));
4598 597 : CATCH_REQUIRE(dimension->get_string() == dimensions[j]);
4599 597 : csspp::position const & npos(dimension->get_position());
4600 597 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4601 597 : CATCH_REQUIRE(npos.get_page() == 1);
4602 597 : CATCH_REQUIRE(npos.get_line() == 1);
4603 597 : CATCH_REQUIRE(npos.get_total_line() == 1);
4604 597 : }
4605 597 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
4606 597 : }
4607 : }
4608 : }
4609 :
4610 : // invalid escape character
4611 : {
4612 1 : std::stringstream ss;
4613 1 : ss << "1.25e\\\n";
4614 3 : csspp::position pos("test.css");
4615 1 : csspp::lexer l(ss, pos);
4616 :
4617 : // dimension
4618 : {
4619 : // a dimension is an integer or a decimal number
4620 : // with a string expressing the dimension
4621 1 : csspp::node::pointer_t dimension(l.next_token());
4622 1 : CATCH_REQUIRE(dimension->is(csspp::node_type_t::DECIMAL_NUMBER));
4623 1 : CATCH_REQUIRE(fabs(dimension->get_decimal_number() - 1.25) < 0.00001);
4624 1 : CATCH_REQUIRE(dimension->get_string() == "e");
4625 1 : csspp::position const & npos(dimension->get_position());
4626 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4627 1 : CATCH_REQUIRE(npos.get_page() == 1);
4628 1 : CATCH_REQUIRE(npos.get_line() == 1);
4629 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4630 1 : }
4631 :
4632 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
4633 :
4634 1 : VERIFY_ERRORS("test.css(1): error: spurious newline character after a \\ character outside of a string.\n");
4635 1 : }
4636 :
4637 : // no error left over
4638 1 : VERIFY_ERRORS("");
4639 1 : }
4640 :
4641 1 : CATCH_TEST_CASE("Percent", "[lexer] [number] [percent]")
4642 : {
4643 : // percent with integers, converts to decimal number anyway
4644 : {
4645 20002 : for(int i(-10000); i <= 10000; ++i)
4646 : {
4647 20001 : std::stringstream ss;
4648 : ss << i << "%"
4649 20001 : << "," << i << "\\%"
4650 20001 : << "," << i << "\\25"
4651 20001 : << "," << i << " " << "%"; // and when spaced, it becomes MODULO
4652 60003 : csspp::position pos("test.css");
4653 20001 : csspp::lexer l(ss, pos);
4654 :
4655 : // sign
4656 : //if(i < 0)
4657 : //{
4658 : // csspp::node::pointer_t subtract(l.next_token());
4659 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
4660 : // csspp::position const & npos(subtract->get_position());
4661 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4662 : // CATCH_REQUIRE(npos.get_page() == 1);
4663 : // CATCH_REQUIRE(npos.get_line() == 1);
4664 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4665 : //}
4666 :
4667 : // percent
4668 : {
4669 20001 : csspp::node::pointer_t percent(l.next_token());
4670 20001 : CATCH_REQUIRE(percent->is(csspp::node_type_t::PERCENT));
4671 20001 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(percent->get_decimal_number(), static_cast<csspp::decimal_number_t>(i) / 100.0, 0.0));
4672 20001 : csspp::position const & npos(percent->get_position());
4673 20001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4674 20001 : CATCH_REQUIRE(npos.get_page() == 1);
4675 20001 : CATCH_REQUIRE(npos.get_line() == 1);
4676 20001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4677 20001 : }
4678 :
4679 : // comma
4680 : {
4681 20001 : csspp::node::pointer_t comma(l.next_token());
4682 20001 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
4683 20001 : csspp::position const & npos(comma->get_position());
4684 20001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4685 20001 : CATCH_REQUIRE(npos.get_page() == 1);
4686 20001 : CATCH_REQUIRE(npos.get_line() == 1);
4687 20001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4688 20001 : }
4689 :
4690 : // sign
4691 : //if(i < 0)
4692 : //{
4693 : // csspp::node::pointer_t subtract(l.next_token());
4694 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
4695 : // csspp::position const & npos(subtract->get_position());
4696 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4697 : // CATCH_REQUIRE(npos.get_page() == 1);
4698 : // CATCH_REQUIRE(npos.get_line() == 1);
4699 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4700 : //}
4701 :
4702 : // dimension (because '%' written '\%' is not a PERCENT...)
4703 : {
4704 20001 : csspp::node::pointer_t integer(l.next_token());
4705 20001 : CATCH_REQUIRE(integer->is(csspp::node_type_t::INTEGER));
4706 20001 : CATCH_REQUIRE(integer->get_integer() == i);
4707 20001 : CATCH_REQUIRE(integer->get_string() == "%");
4708 20001 : csspp::position const & npos(integer->get_position());
4709 20001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4710 20001 : CATCH_REQUIRE(npos.get_page() == 1);
4711 20001 : CATCH_REQUIRE(npos.get_line() == 1);
4712 20001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4713 20001 : }
4714 :
4715 : // comma
4716 : {
4717 20001 : csspp::node::pointer_t comma(l.next_token());
4718 20001 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
4719 20001 : csspp::position const & npos(comma->get_position());
4720 20001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4721 20001 : CATCH_REQUIRE(npos.get_page() == 1);
4722 20001 : CATCH_REQUIRE(npos.get_line() == 1);
4723 20001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4724 20001 : }
4725 :
4726 : // sign
4727 : //if(i < 0)
4728 : //{
4729 : // csspp::node::pointer_t subtract(l.next_token());
4730 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
4731 : // csspp::position const & npos(subtract->get_position());
4732 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4733 : // CATCH_REQUIRE(npos.get_page() == 1);
4734 : // CATCH_REQUIRE(npos.get_line() == 1);
4735 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4736 : //}
4737 :
4738 : // dimension (again \25 is not a PERCENT)
4739 : {
4740 20001 : csspp::node::pointer_t dimension(l.next_token());
4741 20001 : CATCH_REQUIRE(dimension->is(csspp::node_type_t::INTEGER));
4742 20001 : CATCH_REQUIRE(dimension->get_integer() == i);
4743 20001 : CATCH_REQUIRE(dimension->get_string() == "%");
4744 20001 : csspp::position const & npos(dimension->get_position());
4745 20001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4746 20001 : CATCH_REQUIRE(npos.get_page() == 1);
4747 20001 : CATCH_REQUIRE(npos.get_line() == 1);
4748 20001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4749 20001 : }
4750 :
4751 : // comma
4752 : {
4753 20001 : csspp::node::pointer_t comma(l.next_token());
4754 20001 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
4755 20001 : csspp::position const & npos(comma->get_position());
4756 20001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4757 20001 : CATCH_REQUIRE(npos.get_page() == 1);
4758 20001 : CATCH_REQUIRE(npos.get_line() == 1);
4759 20001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4760 20001 : }
4761 :
4762 : // sign
4763 : //if(i < 0)
4764 : //{
4765 : // csspp::node::pointer_t subtract(l.next_token());
4766 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
4767 : // csspp::position const & npos(subtract->get_position());
4768 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4769 : // CATCH_REQUIRE(npos.get_page() == 1);
4770 : // CATCH_REQUIRE(npos.get_line() == 1);
4771 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4772 : //}
4773 :
4774 : // integer (separated!)
4775 : {
4776 20001 : csspp::node::pointer_t integer(l.next_token());
4777 20001 : CATCH_REQUIRE(integer->is(csspp::node_type_t::INTEGER));
4778 20001 : CATCH_REQUIRE(integer->get_integer() == i);
4779 20001 : CATCH_REQUIRE(integer->get_string() == "");
4780 20001 : CATCH_REQUIRE(integer->get_string() == "");
4781 20001 : csspp::position const & npos(integer->get_position());
4782 20001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4783 20001 : CATCH_REQUIRE(npos.get_page() == 1);
4784 20001 : CATCH_REQUIRE(npos.get_line() == 1);
4785 20001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4786 20001 : }
4787 :
4788 : // whitespace
4789 : {
4790 20001 : csspp::node::pointer_t whitespace(l.next_token());
4791 20001 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
4792 20001 : csspp::position const & npos(whitespace->get_position());
4793 20001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4794 20001 : CATCH_REQUIRE(npos.get_page() == 1);
4795 20001 : CATCH_REQUIRE(npos.get_line() == 1);
4796 20001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4797 20001 : }
4798 :
4799 : // "percent" by itself is MODULO
4800 : {
4801 20001 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::MODULO));
4802 20001 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
4803 :
4804 20001 : VERIFY_ERRORS("");
4805 : }
4806 20001 : }
4807 : }
4808 :
4809 : // percent directly with decimal numbers
4810 : {
4811 2002 : for(int i(-1000); i <= 1000; ++i)
4812 : {
4813 2001 : std::stringstream ss;
4814 2001 : ss << (i < 0 ? "-" : "") << abs(i) / 100 << "." << std::setw(2) << std::setfill('0') << abs(i % 100) << "%"
4815 2001 : << "," << (i < 0 ? "-" : "") << abs(i) / 100 << "." << std::setw(2) << abs(i % 100) << " " << "%"; // prove it does not work when we have a space
4816 6003 : csspp::position pos("test.css");
4817 2001 : csspp::lexer l(ss, pos);
4818 :
4819 : // sign
4820 : //if(i < 0)
4821 : //{
4822 : // csspp::node::pointer_t subtract(l.next_token());
4823 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
4824 : // csspp::position const & npos(subtract->get_position());
4825 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4826 : // CATCH_REQUIRE(npos.get_page() == 1);
4827 : // CATCH_REQUIRE(npos.get_line() == 1);
4828 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4829 : //}
4830 :
4831 : // percent
4832 : {
4833 2001 : csspp::node::pointer_t percent(l.next_token());
4834 2001 : CATCH_REQUIRE(percent->is(csspp::node_type_t::PERCENT));
4835 2001 : CATCH_REQUIRE(fabs(percent->get_decimal_number() - i / 10000.0) < 0.00001);
4836 2001 : csspp::position const & npos(percent->get_position());
4837 2001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4838 2001 : CATCH_REQUIRE(npos.get_page() == 1);
4839 2001 : CATCH_REQUIRE(npos.get_line() == 1);
4840 2001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4841 2001 : }
4842 :
4843 : // comma
4844 : {
4845 2001 : csspp::node::pointer_t comma(l.next_token());
4846 2001 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
4847 2001 : csspp::position const & npos(comma->get_position());
4848 2001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4849 2001 : CATCH_REQUIRE(npos.get_page() == 1);
4850 2001 : CATCH_REQUIRE(npos.get_line() == 1);
4851 2001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4852 2001 : }
4853 :
4854 : // sign
4855 : //if(i < 0)
4856 : //{
4857 : // csspp::node::pointer_t subtract(l.next_token());
4858 : // CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
4859 : // csspp::position const & npos(subtract->get_position());
4860 : // CATCH_REQUIRE(npos.get_filename() == "test.css");
4861 : // CATCH_REQUIRE(npos.get_page() == 1);
4862 : // CATCH_REQUIRE(npos.get_line() == 1);
4863 : // CATCH_REQUIRE(npos.get_total_line() == 1);
4864 : //}
4865 :
4866 : // decimal number (separated!)
4867 : {
4868 2001 : csspp::node::pointer_t decimal_number(l.next_token());
4869 2001 : CATCH_REQUIRE(decimal_number->is(csspp::node_type_t::DECIMAL_NUMBER));
4870 2001 : CATCH_REQUIRE(fabs(decimal_number->get_decimal_number() - i / 100.0) < 0.00001);
4871 2001 : CATCH_REQUIRE(decimal_number->get_string() == "");
4872 2001 : csspp::position const & npos(decimal_number->get_position());
4873 2001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4874 2001 : CATCH_REQUIRE(npos.get_page() == 1);
4875 2001 : CATCH_REQUIRE(npos.get_line() == 1);
4876 2001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4877 2001 : }
4878 :
4879 : // whitespace
4880 : {
4881 2001 : csspp::node::pointer_t whitespace(l.next_token());
4882 2001 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
4883 2001 : csspp::position const & npos(whitespace->get_position());
4884 2001 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4885 2001 : CATCH_REQUIRE(npos.get_page() == 1);
4886 2001 : CATCH_REQUIRE(npos.get_line() == 1);
4887 2001 : CATCH_REQUIRE(npos.get_total_line() == 1);
4888 2001 : }
4889 :
4890 : // "percent" by itself is MODULO
4891 : {
4892 2001 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::MODULO));
4893 2001 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
4894 :
4895 2001 : VERIFY_ERRORS("");
4896 : }
4897 2001 : }
4898 : }
4899 :
4900 : // no error left over
4901 1 : VERIFY_ERRORS("");
4902 1 : }
4903 :
4904 1 : CATCH_TEST_CASE("Unicode range", "[lexer] [unicode]")
4905 : {
4906 : // a small test to make sure we get U or u as identifiers when
4907 : // the + is not followed by the right character
4908 : {
4909 1 : std::stringstream ss;
4910 1 : ss << "U+U or u+u";
4911 3 : csspp::position pos("test.css");
4912 1 : csspp::lexer l(ss, pos);
4913 :
4914 : // identifier
4915 : {
4916 1 : csspp::node::pointer_t identifier(l.next_token());
4917 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
4918 1 : CATCH_REQUIRE(identifier->get_string() == "U");
4919 1 : csspp::position const & npos(identifier->get_position());
4920 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4921 1 : CATCH_REQUIRE(npos.get_page() == 1);
4922 1 : CATCH_REQUIRE(npos.get_line() == 1);
4923 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4924 1 : }
4925 :
4926 : // add
4927 : {
4928 1 : csspp::node::pointer_t add(l.next_token());
4929 1 : CATCH_REQUIRE(add->is(csspp::node_type_t::ADD));
4930 1 : csspp::position const & npos(add->get_position());
4931 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4932 1 : CATCH_REQUIRE(npos.get_page() == 1);
4933 1 : CATCH_REQUIRE(npos.get_line() == 1);
4934 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4935 1 : }
4936 :
4937 : // identifier
4938 : {
4939 1 : csspp::node::pointer_t identifier(l.next_token());
4940 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
4941 1 : CATCH_REQUIRE(identifier->get_string() == "U");
4942 1 : csspp::position const & npos(identifier->get_position());
4943 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4944 1 : CATCH_REQUIRE(npos.get_page() == 1);
4945 1 : CATCH_REQUIRE(npos.get_line() == 1);
4946 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4947 1 : }
4948 :
4949 : // whitespace
4950 : {
4951 1 : csspp::node::pointer_t whitespace(l.next_token());
4952 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
4953 1 : csspp::position const & npos(whitespace->get_position());
4954 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4955 1 : CATCH_REQUIRE(npos.get_page() == 1);
4956 1 : CATCH_REQUIRE(npos.get_line() == 1);
4957 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4958 1 : }
4959 :
4960 : // identifier
4961 : {
4962 1 : csspp::node::pointer_t identifier(l.next_token());
4963 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
4964 1 : CATCH_REQUIRE(identifier->get_string() == "or");
4965 1 : csspp::position const & npos(identifier->get_position());
4966 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4967 1 : CATCH_REQUIRE(npos.get_page() == 1);
4968 1 : CATCH_REQUIRE(npos.get_line() == 1);
4969 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4970 1 : }
4971 :
4972 : // whitespace
4973 : {
4974 1 : csspp::node::pointer_t whitespace(l.next_token());
4975 1 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::WHITESPACE));
4976 1 : csspp::position const & npos(whitespace->get_position());
4977 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4978 1 : CATCH_REQUIRE(npos.get_page() == 1);
4979 1 : CATCH_REQUIRE(npos.get_line() == 1);
4980 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4981 1 : }
4982 :
4983 : // identifier
4984 : {
4985 1 : csspp::node::pointer_t identifier(l.next_token());
4986 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
4987 1 : CATCH_REQUIRE(identifier->get_string() == "u");
4988 1 : csspp::position const & npos(identifier->get_position());
4989 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
4990 1 : CATCH_REQUIRE(npos.get_page() == 1);
4991 1 : CATCH_REQUIRE(npos.get_line() == 1);
4992 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
4993 1 : }
4994 :
4995 : // add
4996 : {
4997 1 : csspp::node::pointer_t add(l.next_token());
4998 1 : CATCH_REQUIRE(add->is(csspp::node_type_t::ADD));
4999 1 : csspp::position const & npos(add->get_position());
5000 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5001 1 : CATCH_REQUIRE(npos.get_page() == 1);
5002 1 : CATCH_REQUIRE(npos.get_line() == 1);
5003 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5004 1 : }
5005 :
5006 : // identifier
5007 : {
5008 1 : csspp::node::pointer_t identifier(l.next_token());
5009 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
5010 1 : CATCH_REQUIRE(identifier->get_string() == "u");
5011 1 : csspp::position const & npos(identifier->get_position());
5012 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5013 1 : CATCH_REQUIRE(npos.get_page() == 1);
5014 1 : CATCH_REQUIRE(npos.get_line() == 1);
5015 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5016 1 : }
5017 :
5018 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5019 1 : }
5020 :
5021 : // one value (U+<value>)
5022 : // two values with the same number (U+<value>-<value>)
5023 : // two values with the same number, but force 6 digits each (U+<value>-<value>)
5024 : // check the first 64Kb (plan 0) and then randomize
5025 : {
5026 65537 : for(csspp::wide_char_t unicode(0); unicode < 65536; ++unicode)
5027 : {
5028 65536 : std::stringstream ss;
5029 65536 : ss << (rand() & 1 ? "U" : "u") << "+" << std::hex << unicode
5030 65536 : << "," << (rand() & 1 ? "U" : "u") << "+" << std::hex << unicode << "-" << unicode
5031 65536 : << "," << (rand() & 1 ? "U" : "u") << "+" << std::hex << std::setw(6) << std::setfill('0') << unicode << "-" << std::setw(6) << unicode << std::setfill('\0');
5032 196608 : csspp::position pos("test.css");
5033 65536 : csspp::lexer l(ss, pos);
5034 :
5035 65536 : csspp_test::our_unicode_range_t range(unicode, unicode);
5036 :
5037 : // unicode range
5038 : {
5039 65536 : csspp::node::pointer_t unicode_range(l.next_token());
5040 65536 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5041 65536 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5042 65536 : csspp::position const & npos(unicode_range->get_position());
5043 65536 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5044 65536 : CATCH_REQUIRE(npos.get_page() == 1);
5045 65536 : CATCH_REQUIRE(npos.get_line() == 1);
5046 65536 : CATCH_REQUIRE(npos.get_total_line() == 1);
5047 65536 : }
5048 :
5049 : // comma
5050 : {
5051 65536 : csspp::node::pointer_t comma(l.next_token());
5052 65536 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
5053 65536 : csspp::position const & npos(comma->get_position());
5054 65536 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5055 65536 : CATCH_REQUIRE(npos.get_page() == 1);
5056 65536 : CATCH_REQUIRE(npos.get_line() == 1);
5057 65536 : CATCH_REQUIRE(npos.get_total_line() == 1);
5058 65536 : }
5059 :
5060 : // unicode range
5061 : {
5062 65536 : csspp::node::pointer_t unicode_range(l.next_token());
5063 65536 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5064 65536 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5065 65536 : csspp::position const & npos(unicode_range->get_position());
5066 65536 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5067 65536 : CATCH_REQUIRE(npos.get_page() == 1);
5068 65536 : CATCH_REQUIRE(npos.get_line() == 1);
5069 65536 : CATCH_REQUIRE(npos.get_total_line() == 1);
5070 65536 : }
5071 :
5072 : // comma
5073 : {
5074 65536 : csspp::node::pointer_t comma(l.next_token());
5075 65536 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
5076 65536 : csspp::position const & npos(comma->get_position());
5077 65536 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5078 65536 : CATCH_REQUIRE(npos.get_page() == 1);
5079 65536 : CATCH_REQUIRE(npos.get_line() == 1);
5080 65536 : CATCH_REQUIRE(npos.get_total_line() == 1);
5081 65536 : }
5082 :
5083 : // unicode range
5084 : {
5085 65536 : csspp::node::pointer_t unicode_range(l.next_token());
5086 65536 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5087 65536 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5088 65536 : csspp::position const & npos(unicode_range->get_position());
5089 65536 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5090 65536 : CATCH_REQUIRE(npos.get_page() == 1);
5091 65536 : CATCH_REQUIRE(npos.get_line() == 1);
5092 65536 : CATCH_REQUIRE(npos.get_total_line() == 1);
5093 65536 : }
5094 :
5095 65536 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5096 65536 : }
5097 :
5098 1001 : for(int i(0); i < 1000; ++i)
5099 : {
5100 1000 : csspp::wide_char_t unicode(rand() % 0x110000);
5101 1000 : std::stringstream ss;
5102 1000 : ss << (rand() & 1 ? "U" : "u") << "+" << std::hex << unicode
5103 1000 : << "," << (rand() & 1 ? "U" : "u") << "+" << std::hex << unicode << "-" << unicode
5104 1000 : << "," << (rand() & 1 ? "U" : "u") << "+" << std::hex << std::setw(6) << std::setfill('0') << unicode << "-" << std::setw(6) << unicode << std::setfill('\0');
5105 3000 : csspp::position pos("test.css");
5106 1000 : csspp::lexer l(ss, pos);
5107 :
5108 1000 : csspp_test::our_unicode_range_t range(unicode, unicode);
5109 :
5110 : // unicode range
5111 : {
5112 1000 : csspp::node::pointer_t unicode_range(l.next_token());
5113 1000 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5114 1000 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5115 1000 : csspp::position const & npos(unicode_range->get_position());
5116 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5117 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5118 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5119 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5120 1000 : }
5121 :
5122 : // comma
5123 : {
5124 1000 : csspp::node::pointer_t comma(l.next_token());
5125 1000 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
5126 1000 : csspp::position const & npos(comma->get_position());
5127 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5128 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5129 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5130 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5131 1000 : }
5132 :
5133 : // unicode range
5134 : {
5135 1000 : csspp::node::pointer_t unicode_range(l.next_token());
5136 1000 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5137 1000 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5138 1000 : csspp::position const & npos(unicode_range->get_position());
5139 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5140 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5141 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5142 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5143 1000 : }
5144 :
5145 : // comma
5146 : {
5147 1000 : csspp::node::pointer_t comma(l.next_token());
5148 1000 : CATCH_REQUIRE(comma->is(csspp::node_type_t::COMMA));
5149 1000 : csspp::position const & npos(comma->get_position());
5150 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5151 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5152 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5153 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5154 1000 : }
5155 :
5156 : // unicode range
5157 : {
5158 1000 : csspp::node::pointer_t unicode_range(l.next_token());
5159 1000 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5160 1000 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5161 1000 : csspp::position const & npos(unicode_range->get_position());
5162 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5163 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5164 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5165 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5166 1000 : }
5167 :
5168 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5169 1000 : }
5170 : }
5171 :
5172 : // test that we recover the identifier right after a Unicode Range
5173 : {
5174 1 : std::stringstream ss;
5175 1 : csspp::wide_char_t unicode(rand() % 0x110000);
5176 1 : ss << (rand() & 1 ? "U" : "u") << "+" << std::hex << std::setw(6) << std::setfill('0') << unicode << "Alexis";
5177 3 : csspp::position pos("test.css");
5178 1 : csspp::lexer l(ss, pos);
5179 :
5180 1 : csspp_test::our_unicode_range_t range(unicode, unicode);
5181 :
5182 : // unicode range
5183 : {
5184 1 : csspp::node::pointer_t unicode_range(l.next_token());
5185 1 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5186 1 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5187 1 : csspp::position const & npos(unicode_range->get_position());
5188 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5189 1 : CATCH_REQUIRE(npos.get_page() == 1);
5190 1 : CATCH_REQUIRE(npos.get_line() == 1);
5191 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5192 1 : }
5193 :
5194 : // identifier
5195 : {
5196 1 : csspp::node::pointer_t identifier(l.next_token());
5197 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
5198 1 : CATCH_REQUIRE(identifier->get_string() == "Alexis");
5199 1 : csspp::position const & npos(identifier->get_position());
5200 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5201 1 : CATCH_REQUIRE(npos.get_page() == 1);
5202 1 : CATCH_REQUIRE(npos.get_line() == 1);
5203 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5204 1 : }
5205 :
5206 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5207 1 : }
5208 :
5209 : // test that we recover the number right after a Unicode Range
5210 : {
5211 1 : std::stringstream ss;
5212 1 : csspp::wide_char_t unicode(rand() % 0x110000);
5213 1 : ss << (rand() & 1 ? "U" : "u") << "+" << std::hex << std::setw(6) << std::setfill('0') << unicode << "123";
5214 3 : csspp::position pos("test.css");
5215 1 : csspp::lexer l(ss, pos);
5216 :
5217 1 : csspp_test::our_unicode_range_t range(unicode, unicode);
5218 :
5219 : // unicode range
5220 : {
5221 1 : csspp::node::pointer_t unicode_range(l.next_token());
5222 1 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5223 1 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5224 1 : csspp::position const & npos(unicode_range->get_position());
5225 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5226 1 : CATCH_REQUIRE(npos.get_page() == 1);
5227 1 : CATCH_REQUIRE(npos.get_line() == 1);
5228 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5229 1 : }
5230 :
5231 : // integer
5232 : {
5233 1 : csspp::node::pointer_t integer(l.next_token());
5234 1 : CATCH_REQUIRE(integer->is(csspp::node_type_t::INTEGER));
5235 1 : CATCH_REQUIRE(integer->get_integer() == 123);
5236 1 : csspp::position const & npos(integer->get_position());
5237 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5238 1 : CATCH_REQUIRE(npos.get_page() == 1);
5239 1 : CATCH_REQUIRE(npos.get_line() == 1);
5240 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5241 1 : }
5242 :
5243 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5244 1 : }
5245 :
5246 : // try various masks
5247 : {
5248 : // mask of 6 needs to be tested once
5249 1 : std::stringstream ss;
5250 1 : ss << (rand() & 1 ? "U" : "u") << "+??????";
5251 3 : csspp::position pos("test.css");
5252 1 : csspp::lexer l(ss, pos);
5253 :
5254 1 : csspp_test::our_unicode_range_t range(0, 0x1FFFFF);
5255 :
5256 : // unicode range
5257 : {
5258 1 : csspp::node::pointer_t unicode_range(l.next_token());
5259 1 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5260 1 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5261 1 : csspp::position const & npos(unicode_range->get_position());
5262 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5263 1 : CATCH_REQUIRE(npos.get_page() == 1);
5264 1 : CATCH_REQUIRE(npos.get_line() == 1);
5265 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5266 1 : }
5267 :
5268 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5269 1 : }
5270 4 : for(int i(0); i < 3; i++)
5271 : {
5272 : // mask of 5 can be checked three times: ?????, 0?????, 1?????
5273 3 : int const mask_count(5);
5274 3 : int const mask((1 << (mask_count * 4)) - 1);
5275 3 : std::stringstream ss;
5276 3 : csspp::wide_char_t unicode(i == 2 ? 0x100000 : 0);
5277 3 : ss << std::hex << std::setw(6) << std::setfill('0') << unicode;
5278 3 : std::string unicode_str(ss.str());
5279 3 : ss.str("");
5280 18 : for(size_t p(unicode_str.length() - mask_count); p < unicode_str.length(); ++p)
5281 : {
5282 : // replace by the mask (i.e. '?')
5283 15 : unicode_str[p] = '?';
5284 : }
5285 3 : if(i == 0)
5286 : {
5287 : // remove leading zeroes
5288 2 : while(unicode_str.front() == '0')
5289 : {
5290 1 : unicode_str.erase(unicode_str.begin());
5291 : }
5292 : }
5293 3 : ss << (rand() & 1 ? "U" : "u") << "+" << unicode_str;
5294 9 : csspp::position pos("test.css");
5295 3 : csspp::lexer l(ss, pos);
5296 :
5297 3 : csspp_test::our_unicode_range_t range(unicode, unicode | mask);
5298 :
5299 : // unicode range
5300 : {
5301 3 : csspp::node::pointer_t unicode_range(l.next_token());
5302 3 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5303 3 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5304 3 : csspp::position const & npos(unicode_range->get_position());
5305 3 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5306 3 : CATCH_REQUIRE(npos.get_page() == 1);
5307 3 : CATCH_REQUIRE(npos.get_line() == 1);
5308 3 : CATCH_REQUIRE(npos.get_total_line() == 1);
5309 3 : }
5310 :
5311 3 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5312 3 : }
5313 18 : for(int i(0); i < 0x11; ++i)
5314 : {
5315 : // mask of 4 needs to be tested from 0x00 to 0x10
5316 : // (we could also check with the leading zero and without
5317 : // for each value, but that's not too important)
5318 17 : int const mask_count(4);
5319 17 : int const mask((1 << (mask_count * 4)) - 1);
5320 17 : std::stringstream ss;
5321 17 : csspp::wide_char_t unicode(i << 16); //(rand() % 0x110000) & ~mask);
5322 17 : ss << std::hex << std::setw(6) << std::setfill('0') << unicode;
5323 17 : std::string unicode_str(ss.str());
5324 17 : ss.str("");
5325 85 : for(size_t p(unicode_str.length() - mask_count); p < unicode_str.length(); ++p)
5326 : {
5327 : // replace by the mask (i.e. '?')
5328 68 : unicode_str[p] = '?';
5329 : }
5330 17 : if(rand() % 3 != 0)
5331 : {
5332 : // remove leading zeroes
5333 24 : while(unicode_str.front() == '0')
5334 : {
5335 12 : unicode_str.erase(unicode_str.begin());
5336 : }
5337 : }
5338 17 : ss << (rand() & 1 ? "U" : "u") << "+" << unicode_str;
5339 51 : csspp::position pos("test.css");
5340 17 : csspp::lexer l(ss, pos);
5341 :
5342 17 : csspp_test::our_unicode_range_t range(unicode, unicode | mask);
5343 :
5344 : // unicode range
5345 : {
5346 17 : csspp::node::pointer_t unicode_range(l.next_token());
5347 17 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5348 17 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5349 17 : csspp::position const & npos(unicode_range->get_position());
5350 17 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5351 17 : CATCH_REQUIRE(npos.get_page() == 1);
5352 17 : CATCH_REQUIRE(npos.get_line() == 1);
5353 17 : CATCH_REQUIRE(npos.get_total_line() == 1);
5354 17 : }
5355 :
5356 17 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5357 17 : }
5358 1001 : for(int i(0); i < 1000; ++i) //1433656549
5359 : {
5360 : // a few random mask of 1 to 3 '?'
5361 1000 : int const mask_count(rand() % 3 + 1);
5362 1000 : int const mask((1 << (mask_count * 4)) - 1);
5363 1000 : std::stringstream ss;
5364 1000 : csspp::wide_char_t unicode((rand() % 0x110000) & ~mask);
5365 1000 : ss << std::hex << std::setw(6) << std::setfill('0') << unicode;
5366 1000 : std::string unicode_str(ss.str());
5367 1000 : ss.str("");
5368 3002 : for(size_t p(unicode_str.length() - mask_count); p < unicode_str.length(); ++p)
5369 : {
5370 : // replace by the mask (i.e. '?')
5371 2002 : unicode_str[p] = '?';
5372 : }
5373 1000 : if(rand() % 3 != 0)
5374 : {
5375 : // remove leading zeroes
5376 1388 : while(unicode_str.front() == '0')
5377 : {
5378 700 : unicode_str.erase(unicode_str.begin());
5379 : }
5380 : }
5381 1000 : ss << (rand() & 1 ? "U" : "u") << "+" << unicode_str;
5382 3000 : csspp::position pos("test.css");
5383 1000 : csspp::lexer l(ss, pos);
5384 :
5385 1000 : csspp_test::our_unicode_range_t range(unicode, unicode | mask);
5386 :
5387 : // unicode range
5388 : {
5389 1000 : csspp::node::pointer_t unicode_range(l.next_token());
5390 1000 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5391 1000 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5392 1000 : csspp::position const & npos(unicode_range->get_position());
5393 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5394 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5395 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5396 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5397 1000 : }
5398 :
5399 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5400 1000 : }
5401 :
5402 : // test simple range (start only) with values that are too large
5403 1001 : for(int i(0); i < 1000; i++)
5404 : {
5405 : // check a start unicode value too large
5406 : {
5407 1000 : std::stringstream ss;
5408 : // an invalid value which is exactly 6 hexadecimal digits
5409 1000 : csspp::wide_char_t unicode(rand() % (0x1000000 - 0x110000) + 0x110000);
5410 1000 : ss << (rand() & 1 ? "U" : "u") << "+" << std::hex << unicode;
5411 3000 : csspp::position pos("test.css");
5412 1000 : csspp::lexer l(ss, pos);
5413 :
5414 : // unicode range
5415 : {
5416 1000 : csspp::node::pointer_t unicode_range(l.next_token());
5417 1000 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5418 : //CATCH_REQUIRE(unicode_range->get_integer() == range.f_range); -- there was an overflow
5419 1000 : csspp::position const & npos(unicode_range->get_position());
5420 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5421 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5422 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5423 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5424 :
5425 1000 : VERIFY_ERRORS("test.css(1): error: unicode character too large, range is U+000000 to U+10FFFF.\n");
5426 1000 : }
5427 :
5428 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5429 1000 : }
5430 :
5431 : // check with the second unicode too large
5432 : {
5433 1000 : std::stringstream ss;
5434 : // an invalid value which is exactly 6 hexadecimal digits
5435 1000 : csspp::wide_char_t unicode_start(rand() % 0x110000);
5436 1000 : csspp::wide_char_t unicode_end(rand() % (0x1000000 - 0x110000) + 0x110000);
5437 1000 : ss << (rand() & 1 ? "U" : "u") << "+" << std::hex << unicode_start << "-" << unicode_end;
5438 3000 : csspp::position pos("test.css");
5439 1000 : csspp::lexer l(ss, pos);
5440 :
5441 : // unicode range
5442 : {
5443 1000 : csspp::node::pointer_t unicode_range(l.next_token());
5444 1000 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5445 : //CATCH_REQUIRE(unicode_range->get_integer() == range.f_range); -- there was an overflow
5446 1000 : csspp::position const & npos(unicode_range->get_position());
5447 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5448 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5449 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5450 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5451 :
5452 1000 : VERIFY_ERRORS("test.css(1): error: unicode character too large, range is U+000000 to U+10FFFF.\n");
5453 1000 : }
5454 :
5455 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5456 1000 : }
5457 :
5458 : // check with a mask which is too large
5459 : {
5460 : // WARNING: this test works with a mask of 1 to 4 x '?'
5461 : // with 5, you would have to make sure that the first
5462 : // Unicode digit it 2 or more
5463 : // with 6, it never fails (and it is tested earlier)
5464 : //
5465 1000 : int const mask_count(rand() % 3 + 1);
5466 1000 : int const mask((1 << (mask_count * 4)) - 1);
5467 1000 : std::stringstream ss;
5468 : // an invalid value which is exactly 6 hexadecimal digits
5469 1000 : csspp::wide_char_t const unicode((rand() % (0x1000000 - 0x110000) + 0x110000) & ~mask);
5470 1000 : ss << std::hex << unicode;
5471 1000 : std::string unicode_str(ss.str());
5472 1000 : ss.str("");
5473 3018 : for(size_t p(unicode_str.length() - mask_count); p < unicode_str.length(); ++p)
5474 : {
5475 : // replace by the mask (i.e. '?')
5476 2018 : unicode_str[p] = '?';
5477 : }
5478 1000 : ss << (rand() & 1 ? "U" : "u") << "+" << unicode_str;
5479 3000 : csspp::position pos("test.css");
5480 1000 : csspp::lexer l(ss, pos);
5481 :
5482 : // unicode range
5483 : {
5484 1000 : csspp::node::pointer_t unicode_range(l.next_token());
5485 1000 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5486 : //CATCH_REQUIRE(unicode_range->get_integer() == range.f_range); -- there was an overflow, what could we check?
5487 1000 : csspp::position const & npos(unicode_range->get_position());
5488 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5489 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5490 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5491 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5492 :
5493 1000 : VERIFY_ERRORS("test.css(1): error: unicode character too large, range is U+000000 to U+10FFFF.\n");
5494 1000 : }
5495 :
5496 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5497 1000 : }
5498 : }
5499 :
5500 : // actual range: in order and not in order
5501 1001 : for(int i(0); i < 1000; i++)
5502 : {
5503 1000 : std::stringstream ss;
5504 : // an invalid value which is exactly 6 hexadecimal digits
5505 1000 : csspp::wide_char_t unicode_start(rand() % 0x110000);
5506 1000 : csspp::wide_char_t unicode_end(rand() % 0x110000);
5507 : // avoid equality (already tested!)
5508 1000 : while(unicode_end == unicode_start)
5509 : {
5510 0 : unicode_end = rand() % 0x110000;
5511 : }
5512 : // make sure start is smaller
5513 1000 : if(unicode_start > unicode_end)
5514 : {
5515 503 : std::swap(unicode_start, unicode_end);
5516 : }
5517 : // test both: valid and invalid ranges
5518 1000 : ss << (rand() & 1 ? "U" : "u") << "+" << std::hex << unicode_start << "-" << unicode_end
5519 1000 : << "," << (rand() & 1 ? "U" : "u") << "+" << unicode_end << "-" << unicode_start;
5520 3000 : csspp::position pos("test.css");
5521 1000 : csspp::lexer l(ss, pos);
5522 :
5523 1000 : csspp_test::our_unicode_range_t range(unicode_start, unicode_end);
5524 :
5525 : // unicode range
5526 : {
5527 1000 : csspp::node::pointer_t unicode_range(l.next_token());
5528 1000 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5529 1000 : CATCH_REQUIRE(unicode_range->get_integer() == static_cast<csspp::integer_t>(range.get_range()));
5530 1000 : csspp::position const & npos(unicode_range->get_position());
5531 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5532 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5533 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5534 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5535 1000 : }
5536 :
5537 : // comma
5538 : {
5539 1000 : csspp::node::pointer_t whitespace(l.next_token());
5540 1000 : CATCH_REQUIRE(whitespace->is(csspp::node_type_t::COMMA));
5541 1000 : csspp::position const & npos(whitespace->get_position());
5542 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5543 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5544 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5545 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5546 1000 : }
5547 :
5548 : // unicode range
5549 : {
5550 1000 : csspp::node::pointer_t unicode_range(l.next_token());
5551 1000 : CATCH_REQUIRE(unicode_range->is(csspp::node_type_t::UNICODE_RANGE));
5552 : //CATCH_REQUIRE(unicode_range->get_integer() == range.f_range); -- we get an error, we know what the range is, but we do not want to assume so in the test
5553 1000 : csspp::position const & npos(unicode_range->get_position());
5554 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5555 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5556 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5557 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5558 :
5559 1000 : VERIFY_ERRORS("test.css(1): error: unicode range cannot have a start character larger than the end character.\n");
5560 1000 : }
5561 :
5562 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5563 1000 : }
5564 :
5565 : // no error left over
5566 1 : VERIFY_ERRORS("");
5567 1 : }
5568 :
5569 1 : CATCH_TEST_CASE("Hash", "[lexer] [hash]")
5570 : {
5571 : // test a standard hash
5572 : {
5573 1 : std::stringstream ss;
5574 3 : csspp::position pos("test.css");
5575 1 : csspp::lexer l(ss, pos);
5576 1 : ss << "#-escape\\=33-";
5577 :
5578 : // hash
5579 : {
5580 1 : csspp::node::pointer_t identifier(l.next_token());
5581 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::HASH));
5582 1 : CATCH_REQUIRE(identifier->get_string() == "-escape=33-");
5583 1 : csspp::position const & npos(identifier->get_position());
5584 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5585 1 : CATCH_REQUIRE(npos.get_page() == 1);
5586 1 : CATCH_REQUIRE(npos.get_line() == 1);
5587 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5588 1 : }
5589 :
5590 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5591 1 : }
5592 :
5593 : // generate a set of simple and valid hashes
5594 1001 : for(int i(0); i < 1000; ++i)
5595 : {
5596 1000 : std::stringstream ss;
5597 3000 : csspp::position pos("test.css");
5598 1000 : csspp::lexer l(ss, pos);
5599 1000 : ss << '#';
5600 1000 : int count(rand() % 30 + 1);
5601 1000 : std::string word;
5602 16396 : for(int j(0); j < count; ++j)
5603 : {
5604 15396 : csspp::wide_char_t c(0);
5605 : for(;;)
5606 : {
5607 15427 : c = rand() % 0x110000;
5608 15427 : if((c >= 'A' && c <= 'Z')
5609 15427 : || (c >= 'a' && c <= 'z')
5610 15427 : || (c >= '0' && c <= '9')
5611 15427 : || c == '_'
5612 15427 : || c == '-'
5613 15427 : || (c > 0x80
5614 15427 : && c != 0xFFFD
5615 15427 : && (c < 0xD800 || c > 0xDFFF)
5616 15396 : && ((c & 0xFFFF) != 0xFFFE)
5617 15396 : && ((c & 0xFFFF) != 0xFFFF))
5618 : )
5619 : {
5620 : break;
5621 : }
5622 : }
5623 15396 : word += l.wctomb(c);
5624 : }
5625 1000 : ss << word;
5626 :
5627 : // hash
5628 : {
5629 1000 : csspp::node::pointer_t identifier(l.next_token());
5630 1000 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::HASH));
5631 1000 : CATCH_REQUIRE(identifier->get_string() == word);
5632 1000 : csspp::position const & npos(identifier->get_position());
5633 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5634 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5635 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5636 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5637 1000 : }
5638 :
5639 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5640 1000 : }
5641 :
5642 : // test a standard hash
5643 : {
5644 1 : std::stringstream ss;
5645 3 : csspp::position pos("test.css");
5646 1 : csspp::lexer l(ss, pos);
5647 1 : ss << "#-escape\\0 33-";
5648 :
5649 : // hash
5650 : {
5651 1 : csspp::node::pointer_t hash(l.next_token());
5652 1 : CATCH_REQUIRE(hash->is(csspp::node_type_t::HASH));
5653 1 : CATCH_REQUIRE(hash->get_string() == "-escape");
5654 1 : csspp::position const & npos(hash->get_position());
5655 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5656 1 : CATCH_REQUIRE(npos.get_page() == 1);
5657 1 : CATCH_REQUIRE(npos.get_line() == 1);
5658 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5659 :
5660 1 : VERIFY_ERRORS("test.css(1): error: escape character '\\0' is not acceptable in CSS.\n");
5661 1 : }
5662 :
5663 : // integer
5664 : {
5665 1 : csspp::node::pointer_t identifier(l.next_token());
5666 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::INTEGER));
5667 1 : CATCH_REQUIRE(identifier->get_integer() == 33);
5668 1 : csspp::position const & npos(identifier->get_position());
5669 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5670 1 : CATCH_REQUIRE(npos.get_page() == 1);
5671 1 : CATCH_REQUIRE(npos.get_line() == 1);
5672 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5673 1 : }
5674 :
5675 : // subtract
5676 : {
5677 1 : csspp::node::pointer_t subtract(l.next_token());
5678 1 : CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
5679 1 : csspp::position const & npos(subtract->get_position());
5680 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5681 1 : CATCH_REQUIRE(npos.get_page() == 1);
5682 1 : CATCH_REQUIRE(npos.get_line() == 1);
5683 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5684 1 : }
5685 :
5686 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5687 1 : }
5688 1 : }
5689 :
5690 1 : CATCH_TEST_CASE("Invalid hash", "[lexer] [hash]")
5691 : {
5692 : // test an empty hash
5693 : {
5694 1 : std::stringstream ss;
5695 3 : csspp::position pos("test.css");
5696 1 : csspp::lexer l(ss, pos);
5697 1 : ss << "empty # here";
5698 :
5699 : // identifier (empty)
5700 : {
5701 1 : csspp::node::pointer_t hash(l.next_token());
5702 1 : CATCH_REQUIRE(hash->is(csspp::node_type_t::IDENTIFIER));
5703 1 : CATCH_REQUIRE(hash->get_string() == "empty");
5704 1 : csspp::position const & npos(hash->get_position());
5705 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5706 1 : CATCH_REQUIRE(npos.get_page() == 1);
5707 1 : CATCH_REQUIRE(npos.get_line() == 1);
5708 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5709 :
5710 1 : VERIFY_ERRORS("");
5711 1 : }
5712 :
5713 : // whitespace
5714 : {
5715 1 : csspp::node::pointer_t hash(l.next_token());
5716 1 : CATCH_REQUIRE(hash->is(csspp::node_type_t::WHITESPACE));
5717 1 : csspp::position const & npos(hash->get_position());
5718 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5719 1 : CATCH_REQUIRE(npos.get_page() == 1);
5720 1 : CATCH_REQUIRE(npos.get_line() == 1);
5721 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5722 :
5723 1 : VERIFY_ERRORS("");
5724 1 : }
5725 :
5726 : // hash
5727 : // '#" by itself generates an error and nothing is returned
5728 :
5729 : // whitespace
5730 : {
5731 1 : csspp::node::pointer_t hash(l.next_token());
5732 1 : CATCH_REQUIRE(hash->is(csspp::node_type_t::WHITESPACE));
5733 1 : csspp::position const & npos(hash->get_position());
5734 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5735 1 : CATCH_REQUIRE(npos.get_page() == 1);
5736 1 : CATCH_REQUIRE(npos.get_line() == 1);
5737 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5738 :
5739 1 : VERIFY_ERRORS("test.css(1): error: '#' by itself is not valid.\n");
5740 1 : }
5741 :
5742 : // identifier (here)
5743 : {
5744 1 : csspp::node::pointer_t identifier(l.next_token());
5745 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::IDENTIFIER));
5746 1 : CATCH_REQUIRE(identifier->get_string() == "here");
5747 1 : csspp::position const & npos(identifier->get_position());
5748 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5749 1 : CATCH_REQUIRE(npos.get_page() == 1);
5750 1 : CATCH_REQUIRE(npos.get_line() == 1);
5751 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5752 1 : }
5753 :
5754 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5755 1 : }
5756 :
5757 : // no error left over
5758 1 : VERIFY_ERRORS("");
5759 1 : }
5760 :
5761 1 : CATCH_TEST_CASE("Placeholders", "[lexer] [hash]")
5762 : {
5763 : // test a standard placeholder
5764 : {
5765 1 : std::stringstream ss;
5766 3 : csspp::position pos("test.css");
5767 1 : csspp::lexer l(ss, pos);
5768 1 : ss << "%es-cape\\=33-";
5769 :
5770 : // hash
5771 : {
5772 1 : csspp::node::pointer_t identifier(l.next_token());
5773 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::PLACEHOLDER));
5774 1 : CATCH_REQUIRE(identifier->get_string() == "es-cape=33-");
5775 1 : csspp::position const & npos(identifier->get_position());
5776 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5777 1 : CATCH_REQUIRE(npos.get_page() == 1);
5778 1 : CATCH_REQUIRE(npos.get_line() == 1);
5779 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5780 1 : }
5781 :
5782 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5783 1 : }
5784 :
5785 : // generate a set of simple and valid placeholders
5786 1001 : for(int i(0); i < 1000; ++i)
5787 : {
5788 1000 : std::stringstream ss;
5789 3000 : csspp::position pos("test.css");
5790 1000 : csspp::lexer l(ss, pos);
5791 1000 : ss << '%';
5792 1000 : int count(rand() % 30 + 1);
5793 1000 : std::string word;
5794 1000 : std::string lword;
5795 16546 : for(int j(0); j < count; ++j)
5796 : {
5797 15546 : csspp::wide_char_t c(0);
5798 : for(;;)
5799 : {
5800 15572 : c = rand() % 0x110000;
5801 15572 : if((c >= 'A' && c <= 'Z')
5802 15571 : || (c >= 'a' && c <= 'z')
5803 15571 : || (c >= '0' && c <= '9')
5804 15570 : || c == '_'
5805 15570 : || (c == '-' && j != 0)
5806 15570 : || (c > 0x80
5807 15569 : && c != 0xFFFD
5808 15569 : && (c < 0xD800 || c > 0xDFFF)
5809 15544 : && ((c & 0xFFFF) != 0xFFFE)
5810 15544 : && ((c & 0xFFFF) != 0xFFFF))
5811 : )
5812 : {
5813 : break;
5814 : }
5815 : }
5816 15546 : word += l.wctomb(c);
5817 15546 : lword += l.wctomb(std::tolower(c));
5818 : }
5819 1000 : ss << word;
5820 :
5821 : // placeholder
5822 : {
5823 1000 : csspp::node::pointer_t identifier(l.next_token());
5824 1000 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::PLACEHOLDER));
5825 1000 : CATCH_REQUIRE(identifier->get_string() == word);
5826 1000 : CATCH_REQUIRE(identifier->get_lowercase_string() == lword);
5827 1000 : csspp::position const & npos(identifier->get_position());
5828 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5829 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5830 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5831 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5832 1000 : }
5833 :
5834 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5835 1000 : }
5836 :
5837 : // test a standard placeholder
5838 : {
5839 1 : std::stringstream ss;
5840 3 : csspp::position pos("test.css");
5841 1 : csspp::lexer l(ss, pos);
5842 1 : ss << "%es-cape\\0 33-";
5843 :
5844 : // placeholder
5845 : {
5846 1 : csspp::node::pointer_t hash(l.next_token());
5847 1 : CATCH_REQUIRE(hash->is(csspp::node_type_t::PLACEHOLDER));
5848 1 : CATCH_REQUIRE(hash->get_string() == "es-cape");
5849 1 : csspp::position const & npos(hash->get_position());
5850 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5851 1 : CATCH_REQUIRE(npos.get_page() == 1);
5852 1 : CATCH_REQUIRE(npos.get_line() == 1);
5853 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5854 :
5855 1 : VERIFY_ERRORS("test.css(1): error: escape character '\\0' is not acceptable in CSS.\n");
5856 1 : }
5857 :
5858 : // integer
5859 : {
5860 1 : csspp::node::pointer_t identifier(l.next_token());
5861 1 : CATCH_REQUIRE(identifier->is(csspp::node_type_t::INTEGER));
5862 1 : CATCH_REQUIRE(identifier->get_integer() == 33);
5863 1 : csspp::position const & npos(identifier->get_position());
5864 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5865 1 : CATCH_REQUIRE(npos.get_page() == 1);
5866 1 : CATCH_REQUIRE(npos.get_line() == 1);
5867 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5868 1 : }
5869 :
5870 : // subtract
5871 : {
5872 1 : csspp::node::pointer_t subtract(l.next_token());
5873 1 : CATCH_REQUIRE(subtract->is(csspp::node_type_t::SUBTRACT));
5874 1 : csspp::position const & npos(subtract->get_position());
5875 1 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5876 1 : CATCH_REQUIRE(npos.get_page() == 1);
5877 1 : CATCH_REQUIRE(npos.get_line() == 1);
5878 1 : CATCH_REQUIRE(npos.get_total_line() == 1);
5879 1 : }
5880 :
5881 1 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5882 1 : }
5883 :
5884 : // no error left over
5885 1 : VERIFY_ERRORS("");
5886 1 : }
5887 :
5888 1 : CATCH_TEST_CASE("Variables", "[lexer] [variable]")
5889 : {
5890 : // test variables
5891 1001 : for(int i(0); i < 1000; ++i)
5892 : {
5893 1000 : std::stringstream ss;
5894 3000 : csspp::position pos("test.css");
5895 1000 : csspp::lexer l(ss, pos);
5896 1000 : std::string word;
5897 1000 : std::string lword;
5898 1000 : int size(rand() % 20 + 1);
5899 11253 : for(int j(0); j < size; ++j)
5900 : {
5901 : // only valid characters
5902 10253 : char c(rand() % (10 + 26 + 26 + 2));
5903 10253 : if(c < 10)
5904 : {
5905 1602 : c += '0';
5906 1602 : lword += c;
5907 : }
5908 8651 : else if(c < 10 + 26)
5909 : {
5910 4124 : c += 'A' - 10;
5911 4124 : lword += c + 0x20;
5912 : }
5913 4527 : else if(c < 10 + 26 + 26)
5914 : {
5915 4206 : c += 'a' - 10 - 26;
5916 4206 : lword += c;
5917 : }
5918 321 : else if(c < 10 + 26 + 26 + 1)
5919 : {
5920 166 : c = '-';
5921 166 : lword += '_'; // '-' == '_' in variable names
5922 : }
5923 : else
5924 : {
5925 155 : c = '_';
5926 155 : lword += '_';
5927 : }
5928 10253 : word += c;
5929 : }
5930 1000 : ss << "$" << word;
5931 :
5932 : // variable
5933 : {
5934 1000 : csspp::node::pointer_t variable(l.next_token());
5935 1000 : CATCH_REQUIRE(variable->is(csspp::node_type_t::VARIABLE));
5936 1000 : CATCH_REQUIRE(variable->get_string() == lword);
5937 1000 : csspp::position const & npos(variable->get_position());
5938 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5939 1000 : CATCH_REQUIRE(npos.get_page() == 1);
5940 1000 : CATCH_REQUIRE(npos.get_line() == 1);
5941 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
5942 1000 : }
5943 :
5944 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
5945 :
5946 : // no error left over
5947 1000 : VERIFY_ERRORS("");
5948 1000 : }
5949 :
5950 : // test variable functions
5951 1001 : for(int i(0); i < 1000; ++i)
5952 : {
5953 1000 : std::stringstream ss;
5954 3000 : csspp::position pos("test.css");
5955 1000 : csspp::lexer l(ss, pos);
5956 1000 : std::string word;
5957 1000 : std::string lword;
5958 1000 : int size(rand() % 20 + 1);
5959 11545 : for(int j(0); j < size; ++j)
5960 : {
5961 : // only valid characters
5962 10545 : char c(rand() % (10 + 26 + 26 + 2));
5963 10545 : if(c < 10)
5964 : {
5965 1622 : c += '0';
5966 1622 : lword += c;
5967 : }
5968 8923 : else if(c < 10 + 26)
5969 : {
5970 4286 : c += 'A' - 10;
5971 4286 : lword += c + 0x20;
5972 : }
5973 4637 : else if(c < 10 + 26 + 26)
5974 : {
5975 4283 : c += 'a' - 10 - 26;
5976 4283 : lword += c;
5977 : }
5978 354 : else if(c < 10 + 26 + 26 + 1)
5979 : {
5980 176 : c = '-';
5981 176 : lword += '_'; // '-' == '_' in variable names
5982 : }
5983 : else
5984 : {
5985 178 : c = '_';
5986 178 : lword += '_';
5987 : }
5988 10545 : word += c;
5989 : }
5990 1000 : ss << "$" << word << "(args)";
5991 :
5992 : // variable function
5993 : {
5994 1000 : csspp::node::pointer_t variable(l.next_token());
5995 1000 : CATCH_REQUIRE(variable->is(csspp::node_type_t::VARIABLE_FUNCTION));
5996 1000 : CATCH_REQUIRE(variable->get_string() == lword);
5997 1000 : csspp::position const & npos(variable->get_position());
5998 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
5999 1000 : CATCH_REQUIRE(npos.get_page() == 1);
6000 1000 : CATCH_REQUIRE(npos.get_line() == 1);
6001 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
6002 1000 : }
6003 :
6004 : // args
6005 : {
6006 1000 : csspp::node::pointer_t variable(l.next_token());
6007 1000 : CATCH_REQUIRE(variable->is(csspp::node_type_t::IDENTIFIER));
6008 1000 : CATCH_REQUIRE(variable->get_string() == "args");
6009 1000 : csspp::position const & npos(variable->get_position());
6010 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
6011 1000 : CATCH_REQUIRE(npos.get_page() == 1);
6012 1000 : CATCH_REQUIRE(npos.get_line() == 1);
6013 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
6014 1000 : }
6015 :
6016 : // ')'
6017 : {
6018 1000 : csspp::node::pointer_t variable(l.next_token());
6019 1000 : CATCH_REQUIRE(variable->is(csspp::node_type_t::CLOSE_PARENTHESIS));
6020 1000 : csspp::position const & npos(variable->get_position());
6021 1000 : CATCH_REQUIRE(npos.get_filename() == "test.css");
6022 1000 : CATCH_REQUIRE(npos.get_page() == 1);
6023 1000 : CATCH_REQUIRE(npos.get_line() == 1);
6024 1000 : CATCH_REQUIRE(npos.get_total_line() == 1);
6025 1000 : }
6026 :
6027 1000 : CATCH_REQUIRE(l.next_token()->is(csspp::node_type_t::EOF_TOKEN));
6028 :
6029 : // no error left over
6030 1000 : VERIFY_ERRORS("");
6031 1000 : }
6032 1 : }
6033 :
6034 : // vim: ts=4 sw=4 et
|