LCOV - code coverage report
Current view: top level - tests - catch_parser.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 971 971 100.0 %
Date: 2023-11-01 21:56:19 Functions: 19 19 100.0 %
Legend: Lines: hit not hit

          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 parser.cpp file.
      22             :  *
      23             :  * This test runs a battery of tests agains the parser.cpp file to ensure
      24             :  * full coverage and many edge cases as expected by CSS 3.
      25             :  *
      26             :  * Note that the basic grammar that the parser implements is compatible
      27             :  * with CSS 1 and 2.1.
      28             :  *
      29             :  * Remember that the parser does not do any verification other than the
      30             :  * ability to parse the input data. So whether the rules are any good
      31             :  * is not known at the time the parser returns.
      32             :  */
      33             : 
      34             : // csspp
      35             : //
      36             : #include    <csspp/exception.h>
      37             : #include    <csspp/parser.h>
      38             : 
      39             : 
      40             : // self
      41             : //
      42             : #include    "catch_main.h"
      43             : 
      44             : 
      45             : // C++
      46             : //
      47             : #include    <sstream>
      48             : 
      49             : 
      50             : // C
      51             : //
      52             : #include    <string.h>
      53             : 
      54             : 
      55             : // last include
      56             : //
      57             : #include    <snapdev/poison.h>
      58             : 
      59             : 
      60             : 
      61             : namespace
      62             : {
      63             : 
      64             : } // no name namespace
      65             : 
      66             : 
      67             : 
      68             : 
      69           1 : CATCH_TEST_CASE("Simple stylesheets", "[parser] [stylesheet] [rules]")
      70             : {
      71             :     {
      72           1 :         std::stringstream ss;
      73           1 :         ss << "<!-- body { background : white url( /images/background.png ) } -->";
      74           3 :         csspp::position pos("test.css");
      75           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
      76             : 
      77           2 :         csspp::parser p(l);
      78             : 
      79           1 :         csspp::node::pointer_t n(p.stylesheet());
      80             : 
      81             : //std::cerr << "Result is: [" << *n << "]\n";
      82             : 
      83           1 :         std::stringstream out;
      84           1 :         out << *n;
      85           1 :         VERIFY_TREES(out.str(),
      86             : 
      87             : "LIST\n"
      88             : "  COMPONENT_VALUE\n"
      89             : "    IDENTIFIER \"body\"\n"
      90             : "    OPEN_CURLYBRACKET B:false\n"
      91             : "      COMPONENT_VALUE\n"
      92             : "        IDENTIFIER \"background\"\n"
      93             : "        WHITESPACE\n"
      94             : "        COLON\n"
      95             : "        WHITESPACE\n"
      96             : "        IDENTIFIER \"white\"\n"
      97             : "        WHITESPACE\n"
      98             : "        URL \"/images/background.png\"\n"
      99             : 
     100             :             );
     101             : 
     102             :         // no error left over
     103           1 :         VERIFY_ERRORS("");
     104           1 :     }
     105             : 
     106             :     {
     107           1 :         std::stringstream ss;
     108           1 :         ss << "<!-- body { background : white url( /images/background.png ) } --><!-- div { border: 1px; } -->";
     109           3 :         csspp::position pos("test.css");
     110           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     111             : 
     112           2 :         csspp::parser p(l);
     113             : 
     114           1 :         csspp::node::pointer_t n(p.stylesheet());
     115             : 
     116             : //std::cerr << "Result is: [" << *n << "]\n";
     117             : 
     118           1 :         std::stringstream out;
     119           1 :         out << *n;
     120           1 :         VERIFY_TREES(out.str(),
     121             : 
     122             : "LIST\n"
     123             : "  COMPONENT_VALUE\n"
     124             : "    IDENTIFIER \"body\"\n"
     125             : "    OPEN_CURLYBRACKET B:false\n"
     126             : "      COMPONENT_VALUE\n"
     127             : "        IDENTIFIER \"background\"\n"
     128             : "        WHITESPACE\n"
     129             : "        COLON\n"
     130             : "        WHITESPACE\n"
     131             : "        IDENTIFIER \"white\"\n"
     132             : "        WHITESPACE\n"
     133             : "        URL \"/images/background.png\"\n"
     134             : "  COMPONENT_VALUE\n"
     135             : "    IDENTIFIER \"div\"\n"
     136             : "    OPEN_CURLYBRACKET B:false\n"
     137             : "      COMPONENT_VALUE\n"
     138             : "        IDENTIFIER \"border\"\n"
     139             : "        COLON\n"
     140             : "        WHITESPACE\n"
     141             : "        INTEGER \"px\" I:1\n"
     142             : 
     143             :             );
     144             : 
     145             :         // no error left over
     146           1 :         VERIFY_ERRORS("");
     147           1 :     }
     148             : 
     149             :     // one large rule with semicolons inside
     150             :     {
     151           1 :         std::stringstream ss;
     152             :         ss << "div\n"
     153             :            << "{\n"
     154             :            << "    background-color: rgba(33, 77, 99, 0.3);\n"
     155             :            << "    color: rgba(0, 3, 5, 0.95);\n"
     156             :            << "    font-style: italic;\n"
     157           1 :            << "}";
     158           3 :         csspp::position pos("test.css");
     159           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     160             : 
     161           2 :         csspp::parser p(l);
     162             : 
     163           1 :         csspp::node::pointer_t n(p.stylesheet());
     164             : 
     165             : //std::cerr << "Result is: [" << *n << "]\n";
     166             : 
     167           1 :         std::stringstream out;
     168           1 :         out << *n;
     169           1 :         VERIFY_TREES(out.str(),
     170             : 
     171             : "LIST\n"
     172             : "  COMPONENT_VALUE\n"
     173             : "    IDENTIFIER \"div\"\n"
     174             : "    OPEN_CURLYBRACKET B:false\n"
     175             : "      LIST\n"
     176             : "        COMPONENT_VALUE\n"
     177             : "          IDENTIFIER \"background-color\"\n"
     178             : "          COLON\n"
     179             : "          WHITESPACE\n"
     180             : "          FUNCTION \"rgba\"\n"
     181             : "            INTEGER \"\" I:33\n"
     182             : "            COMMA\n"
     183             : "            WHITESPACE\n"
     184             : "            INTEGER \"\" I:77\n"
     185             : "            COMMA\n"
     186             : "            WHITESPACE\n"
     187             : "            INTEGER \"\" I:99\n"
     188             : "            COMMA\n"
     189             : "            WHITESPACE\n"
     190             : "            DECIMAL_NUMBER \"\" D:0.3\n"
     191             : "        COMPONENT_VALUE\n"
     192             : "          IDENTIFIER \"color\"\n"
     193             : "          COLON\n"
     194             : "          WHITESPACE\n"
     195             : "          FUNCTION \"rgba\"\n"
     196             : "            INTEGER \"\" I:0\n"
     197             : "            COMMA\n"
     198             : "            WHITESPACE\n"
     199             : "            INTEGER \"\" I:3\n"
     200             : "            COMMA\n"
     201             : "            WHITESPACE\n"
     202             : "            INTEGER \"\" I:5\n"
     203             : "            COMMA\n"
     204             : "            WHITESPACE\n"
     205             : "            DECIMAL_NUMBER \"\" D:0.95\n"
     206             : "        COMPONENT_VALUE\n"
     207             : "          IDENTIFIER \"font-style\"\n"
     208             : "          COLON\n"
     209             : "          WHITESPACE\n"
     210             : "          IDENTIFIER \"italic\"\n"
     211             : 
     212             :             );
     213             : 
     214             :         // no error left over
     215           1 :         VERIFY_ERRORS("");
     216           1 :     }
     217             : 
     218             :     // a comment, a simple rule, a comment
     219             :     {
     220           1 :         std::stringstream ss;
     221             :         ss << "// $Id: ...$\n"
     222             :            << "div { border: 1px; }\n"
     223           1 :            << "/* @preserve Copyright (c) 2015-2022  Made to Order Software Corp.  All Rights Reserved. */";
     224           3 :         csspp::position pos("test.css");
     225           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     226             : 
     227           2 :         csspp::parser p(l);
     228             : 
     229           1 :         csspp::node::pointer_t n(p.stylesheet());
     230             : 
     231             : //std::cerr << "Result is: [" << *n << "]\n";
     232             : 
     233           1 :         std::stringstream out;
     234           1 :         out << *n;
     235           1 :         VERIFY_TREES(out.str(),
     236             : 
     237             : "LIST\n"
     238             : "  COMPONENT_VALUE\n"
     239             : "    IDENTIFIER \"div\"\n"
     240             : "    OPEN_CURLYBRACKET B:false\n"
     241             : "      COMPONENT_VALUE\n"
     242             : "        IDENTIFIER \"border\"\n"
     243             : "        COLON\n"
     244             : "        WHITESPACE\n"
     245             : "        INTEGER \"px\" I:1\n"
     246             : "  COMMENT \"@preserve Copyright (c) 2015-2022  Made to Order Software Corp.  All Rights Reserved.\" I:1\n"
     247             : 
     248             :             );
     249             : 
     250             :         // no error left over
     251           1 :         VERIFY_ERRORS("");
     252           1 :     }
     253             : 
     254             :     // one empty C-like comment
     255             :     {
     256           1 :         std::stringstream ss;
     257           1 :         ss << "div { /**/ border: 1px; /**/ }\n";
     258           3 :         csspp::position pos("test.css");
     259           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     260             : 
     261           2 :         csspp::parser p(l);
     262             : 
     263           1 :         csspp::node::pointer_t n(p.stylesheet());
     264             : 
     265             : //std::cerr << "Result is: [" << *n << "]\n";
     266             : 
     267           1 :         std::stringstream out;
     268           1 :         out << *n;
     269           1 :         VERIFY_TREES(out.str(),
     270             : 
     271             : "LIST\n"
     272             : "  COMPONENT_VALUE\n"
     273             : "    IDENTIFIER \"div\"\n"
     274             : "    OPEN_CURLYBRACKET B:false\n"
     275             : "      COMPONENT_VALUE\n"
     276             : "        IDENTIFIER \"border\"\n"
     277             : "        COLON\n"
     278             : "        WHITESPACE\n"
     279             : "        INTEGER \"px\" I:1\n"
     280             : 
     281             :             );
     282             : 
     283             :         // no error left over
     284           1 :         VERIFY_ERRORS("");
     285           1 :     }
     286             : 
     287             :     // multiple empty C-like comments
     288             :     {
     289           1 :         std::stringstream ss;
     290           1 :         ss << "div { /**/ /**/ /**/ border: 1px; /**/ /**/ /**/ }\n";
     291           3 :         csspp::position pos("test.css");
     292           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     293             : 
     294           2 :         csspp::parser p(l);
     295             : 
     296           1 :         csspp::node::pointer_t n(p.stylesheet());
     297             : 
     298             : //std::cerr << "Result is: [" << *n << "]\n";
     299             : 
     300           1 :         std::stringstream out;
     301           1 :         out << *n;
     302           1 :         VERIFY_TREES(out.str(),
     303             : 
     304             : "LIST\n"
     305             : "  COMPONENT_VALUE\n"
     306             : "    IDENTIFIER \"div\"\n"
     307             : "    OPEN_CURLYBRACKET B:false\n"
     308             : "      COMPONENT_VALUE\n"
     309             : "        IDENTIFIER \"border\"\n"
     310             : "        COLON\n"
     311             : "        WHITESPACE\n"
     312             : "        INTEGER \"px\" I:1\n"
     313             : 
     314             :             );
     315             : 
     316             :         // no error left over
     317           1 :         VERIFY_ERRORS("");
     318           1 :     }
     319             : 
     320             :     // cascading fields
     321             :     {
     322           1 :         std::stringstream ss;
     323             :         ss << "div {\n"
     324             :            << "  font: { family: ivory; size: 16pt; style: italic };\n"
     325             :            << "  border: { color: #112389; width: 1px } /**/ ;\n"
     326             :            << "  color: /* text color */ white;\n"
     327           1 :            << "}";
     328           3 :         csspp::position pos("test.css");
     329           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     330             : 
     331           2 :         csspp::parser p(l);
     332             : 
     333           1 :         csspp::node::pointer_t n(p.stylesheet());
     334             : 
     335             : //std::cerr << "Result is: [" << *n << "]\n";
     336           1 :         VERIFY_ERRORS("");
     337             : 
     338           1 :         std::stringstream out;
     339           1 :         out << *n;
     340           1 :         VERIFY_TREES(out.str(),
     341             : 
     342             : "LIST\n"
     343             : "  COMPONENT_VALUE\n"
     344             : "    IDENTIFIER \"div\"\n"
     345             : "    OPEN_CURLYBRACKET B:false\n"
     346             : "      LIST\n"
     347             : "        COMPONENT_VALUE\n"
     348             : "          IDENTIFIER \"font\"\n"
     349             : "          COLON\n"
     350             : "          OPEN_CURLYBRACKET B:false\n"
     351             : "            LIST\n"
     352             : "              COMPONENT_VALUE\n"
     353             : "                IDENTIFIER \"family\"\n"
     354             : "                COLON\n"
     355             : "                WHITESPACE\n"
     356             : "                IDENTIFIER \"ivory\"\n"
     357             : "              COMPONENT_VALUE\n"
     358             : "                IDENTIFIER \"size\"\n"
     359             : "                COLON\n"
     360             : "                WHITESPACE\n"
     361             : "                INTEGER \"pt\" I:16\n"
     362             : "              COMPONENT_VALUE\n"
     363             : "                IDENTIFIER \"style\"\n"
     364             : "                COLON\n"
     365             : "                WHITESPACE\n"
     366             : "                IDENTIFIER \"italic\"\n"
     367             : "        COMPONENT_VALUE\n"
     368             : "          IDENTIFIER \"border\"\n"
     369             : "          COLON\n"
     370             : "          OPEN_CURLYBRACKET B:false\n"
     371             : "            LIST\n"
     372             : "              COMPONENT_VALUE\n"
     373             : "                IDENTIFIER \"color\"\n"
     374             : "                COLON\n"
     375             : "                WHITESPACE\n"
     376             : "                HASH \"112389\"\n"
     377             : "              COMPONENT_VALUE\n"
     378             : "                IDENTIFIER \"width\"\n"
     379             : "                COLON\n"
     380             : "                WHITESPACE\n"
     381             : "                INTEGER \"px\" I:1\n"
     382             : "        COMPONENT_VALUE\n"
     383             : "          IDENTIFIER \"color\"\n"
     384             : "          COLON\n"
     385             : "          WHITESPACE\n"
     386             : "          IDENTIFIER \"white\"\n"
     387             : 
     388             :             );
     389             : 
     390             :         // no error left over
     391           1 :         VERIFY_ERRORS("");
     392           1 :     }
     393             : 
     394             :     // verify support of an empty {}-block
     395             :     {
     396           1 :         std::stringstream ss;
     397             :         ss << "div section span {}\n"
     398           1 :            << "div p b {}\n";
     399           3 :         csspp::position pos("test.css");
     400           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     401             : 
     402           2 :         csspp::parser p(l);
     403             : 
     404           1 :         csspp::node::pointer_t n(p.stylesheet());
     405             : 
     406             : //std::cerr << "Result is: [" << *n << "]\n";
     407           1 :         VERIFY_ERRORS("");
     408             : 
     409           1 :         std::stringstream out;
     410           1 :         out << *n;
     411           1 :         VERIFY_TREES(out.str(),
     412             : 
     413             : "LIST\n"
     414             : "  COMPONENT_VALUE\n"
     415             : "    IDENTIFIER \"div\"\n"
     416             : "    WHITESPACE\n"
     417             : "    IDENTIFIER \"section\"\n"
     418             : "    WHITESPACE\n"
     419             : "    IDENTIFIER \"span\"\n"
     420             : "    OPEN_CURLYBRACKET B:false\n"
     421             : "      LIST\n"
     422             : "  COMPONENT_VALUE\n"
     423             : "    IDENTIFIER \"div\"\n"
     424             : "    WHITESPACE\n"
     425             : "    IDENTIFIER \"p\"\n"
     426             : "    WHITESPACE\n"
     427             : "    IDENTIFIER \"b\"\n"
     428             : "    OPEN_CURLYBRACKET B:false\n"
     429             : "      LIST\n"
     430             : 
     431             :             );
     432             : 
     433             :         // no error left over
     434           1 :         VERIFY_ERRORS("");
     435           1 :     }
     436           1 : }
     437             : 
     438           1 : CATCH_TEST_CASE("Invalid stylesheets", "[parser] [stylesheet] [invalid]")
     439             : {
     440             :     // closing '}' one too many times
     441             :     {
     442           1 :         std::stringstream ss;
     443           1 :         ss << "<!-- body { background : white url( /images/background.png ) } --> }";
     444           3 :         csspp::position pos("test.css");
     445           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     446             : 
     447           2 :         csspp::parser p(l);
     448             : 
     449           1 :         csspp::node::pointer_t n(p.stylesheet());
     450             : 
     451             : //std::cerr << "Result is: [" << *n << "]\n";
     452             : 
     453             :         // this failed with an error, no need to check the "broken" output
     454             : 
     455           1 :         VERIFY_ERRORS("test.css(1): error: Unexpected closing block of type: CLOSE_CURLYBRACKET.\n");
     456           1 :     }
     457             : 
     458             :     // closing ']' one too many times
     459             :     {
     460           1 :         std::stringstream ss;
     461           1 :         ss << "<!-- body[browser~=\"great\"]] { background : white url( /images/background.png ) } -->";
     462           3 :         csspp::position pos("test.css");
     463           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     464             : 
     465           2 :         csspp::parser p(l);
     466             : 
     467           1 :         csspp::node::pointer_t n(p.stylesheet());
     468             : 
     469             : //std::cerr << "Result is: [" << *n << "]\n";
     470             : 
     471             :         // this failed with an error, no need to check the "broken" output
     472             : 
     473           1 :         VERIFY_ERRORS(
     474             :                 "test.css(1): error: A qualified rule must end with a { ... } block.\n"
     475             :                 "test.css(1): error: Unexpected closing block of type: CLOSE_SQUAREBRACKET.\n"
     476             :             );
     477           1 :     }
     478             : 
     479             :     // closing ')' one too many times
     480             :     {
     481           1 :         std::stringstream ss;
     482           1 :         ss << "<!-- body[browser~=\"great\"] { background : white url( /images/background.png ); border-top-color: rgb(1,2,3)); } -->";
     483           3 :         csspp::position pos("test.css");
     484           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     485             : 
     486           2 :         csspp::parser p(l);
     487             : 
     488           1 :         csspp::node::pointer_t n(p.stylesheet());
     489             : 
     490             : //std::cerr << "Result is: [" << *n << "]\n";
     491             : 
     492             :         // this failed with an error, no need to check the "broken" output
     493             : 
     494           1 :         VERIFY_ERRORS(
     495             :                 "test.css(1): error: Block expected to end with CLOSE_CURLYBRACKET but got CLOSE_PARENTHESIS instead.\n"
     496             :                 //"test.css(1): error: Unexpected closing block of type: CLOSE_PARENTHESIS.\n"
     497             :             );
     498           1 :     }
     499             : 
     500             :     // extra ';'
     501             :     {
     502           1 :         std::stringstream ss;
     503           1 :         ss << "illegal { semi: colon };";
     504           3 :         csspp::position pos("test.css");
     505           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     506             : 
     507           2 :         csspp::parser p(l);
     508             : 
     509           1 :         csspp::node::pointer_t n(p.stylesheet());
     510             : 
     511             : //std::cerr << "Result is: [" << *n << "]\n";
     512             : 
     513             :         // this failed with an error, no need to check the "broken" output
     514             : 
     515           1 :         VERIFY_ERRORS(
     516             :                 "test.css(1): error: A qualified rule cannot end a { ... } block with a ';'.\n"
     517             :             );
     518           1 :     }
     519             : 
     520             :     // no error left over
     521           1 :     VERIFY_ERRORS("");
     522           1 : }
     523             : 
     524           1 : CATCH_TEST_CASE("Simple rules", "[parser] [rule-list]")
     525             : {
     526             :     // a simple valid rule
     527             :     {
     528           1 :         std::stringstream ss;
     529           1 :         ss << " body { background : gradient(to bottom, #012, #384513 75%, #452) } ";
     530           3 :         csspp::position pos("test.css");
     531           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     532             : 
     533           2 :         csspp::parser p(l);
     534             : 
     535             :         // rule list does not like <!-- and -->
     536           1 :         csspp::node::pointer_t n(p.rule_list());
     537             : 
     538             : //std::cerr << "Result is: [" << *n << "]\n";
     539             : 
     540           1 :         std::stringstream out;
     541           1 :         out << *n;
     542           1 :         VERIFY_TREES(out.str(),
     543             : 
     544             : "LIST\n"
     545             : "  COMPONENT_VALUE\n"
     546             : "    IDENTIFIER \"body\"\n"
     547             : "    OPEN_CURLYBRACKET B:false\n"
     548             : "      COMPONENT_VALUE\n"
     549             : "        IDENTIFIER \"background\"\n"
     550             : "        WHITESPACE\n"
     551             : "        COLON\n"
     552             : "        WHITESPACE\n"
     553             : "        FUNCTION \"gradient\"\n"
     554             : "          IDENTIFIER \"to\"\n"
     555             : "          WHITESPACE\n"
     556             : "          IDENTIFIER \"bottom\"\n"
     557             : "          COMMA\n"
     558             : "          WHITESPACE\n"
     559             : "          HASH \"012\"\n"
     560             : "          COMMA\n"
     561             : "          WHITESPACE\n"
     562             : "          HASH \"384513\"\n"
     563             : "          WHITESPACE\n"
     564             : "          PERCENT D:0.75\n"
     565             : "          COMMA\n"
     566             : "          WHITESPACE\n"
     567             : "          HASH \"452\"\n"
     568             : 
     569             :             );
     570             : 
     571             :         // no error left over
     572           1 :         VERIFY_ERRORS("");
     573           1 :     }
     574             : 
     575             :     // a simple valid rule
     576             :     {
     577           1 :         std::stringstream ss;
     578             :         ss << " div { color: blue; }"
     579             :            << " @media screen { viewport: 1000px 500px; } "
     580           1 :            << " div#op{color:hsl(120,1,0.5)}";
     581           3 :         csspp::position pos("test.css");
     582           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     583             : 
     584           2 :         csspp::parser p(l);
     585             : 
     586             :         // rule list does not like <!-- and -->
     587           1 :         csspp::node::pointer_t n(p.rule_list());
     588             : 
     589             : //std::cerr << "Result is: [" << *n << "]\n";
     590             : 
     591           1 :         std::stringstream out;
     592           1 :         out << *n;
     593           1 :         VERIFY_TREES(out.str(),
     594             : 
     595             : "LIST\n"
     596             : "  COMPONENT_VALUE\n"
     597             : "    IDENTIFIER \"div\"\n"
     598             : "    OPEN_CURLYBRACKET B:false\n"
     599             : "      COMPONENT_VALUE\n"
     600             : "        IDENTIFIER \"color\"\n"
     601             : "        COLON\n"
     602             : "        WHITESPACE\n"
     603             : "        IDENTIFIER \"blue\"\n"
     604             : "  AT_KEYWORD \"media\" I:0\n"
     605             : "    IDENTIFIER \"screen\"\n"
     606             : "    OPEN_CURLYBRACKET B:false\n"
     607             : "      COMPONENT_VALUE\n"
     608             : "        IDENTIFIER \"viewport\"\n"
     609             : "        COLON\n"
     610             : "        WHITESPACE\n"
     611             : "        INTEGER \"px\" I:1000\n"
     612             : "        WHITESPACE\n"
     613             : "        INTEGER \"px\" I:500\n"
     614             : "  COMPONENT_VALUE\n"
     615             : "    IDENTIFIER \"div\"\n"
     616             : "    HASH \"op\"\n"
     617             : "    OPEN_CURLYBRACKET B:false\n"
     618             : "      COMPONENT_VALUE\n"
     619             : "        IDENTIFIER \"color\"\n"
     620             : "        COLON\n"
     621             : "        FUNCTION \"hsl\"\n"
     622             : "          INTEGER \"\" I:120\n"
     623             : "          COMMA\n"
     624             : "          INTEGER \"\" I:1\n"
     625             : "          COMMA\n"
     626             : "          DECIMAL_NUMBER \"\" D:0.5\n"
     627             : 
     628             :             );
     629             : 
     630             :         // no error left over
     631           1 :         VERIFY_ERRORS("");
     632           1 :     }
     633           1 : }
     634             : 
     635           1 : CATCH_TEST_CASE("Nested rules", "[parser] [rule-list]")
     636             : {
     637             :     // at rule inside another at rule
     638             :     {
     639           1 :         std::stringstream ss;
     640           1 :         ss << "@if true { @message \"blah\"; }";
     641           3 :         csspp::position pos("test.css");
     642           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     643             : 
     644           2 :         csspp::parser p(l);
     645             : 
     646           1 :         csspp::node::pointer_t n(p.rule_list());
     647             : 
     648             :         // no error left over
     649           1 :         VERIFY_ERRORS("");
     650             : 
     651             : //std::cerr << "Result is: [" << *n << "]\n";
     652             : 
     653           1 :         std::stringstream out;
     654           1 :         out << *n;
     655           1 :         VERIFY_TREES(out.str(),
     656             : 
     657             : "LIST\n"
     658             : "  AT_KEYWORD \"if\" I:0\n"
     659             : "    IDENTIFIER \"true\"\n"
     660             : "    OPEN_CURLYBRACKET B:false\n"
     661             : "      COMPONENT_VALUE\n"
     662             : "        AT_KEYWORD \"message\" I:0\n"
     663             : "          STRING \"blah\"\n"
     664             : 
     665             :             );
     666           1 :     }
     667           1 : }
     668             : 
     669           1 : CATCH_TEST_CASE("Invalid rules", "[parser] [rule-list] [invalid]")
     670             : {
     671             :     // breaks on the <!--
     672             :     {
     673           1 :         std::stringstream ss;
     674           1 :         ss << "<!-- body { background : white url( /images/background.png ) } -->";
     675           3 :         csspp::position pos("test.css");
     676           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     677             : 
     678           2 :         csspp::parser p(l);
     679             : 
     680             :         // rule list does not like <!-- and -->
     681           1 :         csspp::node::pointer_t n(p.rule_list());
     682             : 
     683             : //std::cerr << "Result is: [" << *n << "]\n";
     684             : 
     685             :         // this failed with an error, no need to check the "broken" output
     686             : 
     687           1 :         VERIFY_ERRORS("test.css(1): error: HTML comment delimiters (<!-- and -->) are not allowed in this CSS document.\n");
     688           1 :     }
     689             : 
     690             :     // breaks on the -->
     691             :     {
     692           1 :         std::stringstream ss;
     693           1 :         ss << "body { background : white url( /images/background.png ) 44px } -->";
     694           3 :         csspp::position pos("test.css");
     695           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     696             : 
     697           2 :         csspp::parser p(l);
     698             : 
     699             :         // rule list does not like <!-- and -->
     700           1 :         csspp::node::pointer_t n(p.rule_list());
     701             : 
     702             : //std::cerr << "Result is: [" << *n << "]\n";
     703             : 
     704             :         // this failed with an error, no need to check the "broken" output
     705             : 
     706           1 :         VERIFY_ERRORS(
     707             :                 "test.css(1): error: A qualified rule cannot be empty; you are missing a { ... } block.\n"
     708             :                 "test.css(1): error: HTML comment delimiters (<!-- and -->) are not allowed in this CSS document.\n"
     709             :             );
     710           1 :     }
     711             : 
     712             :     // breaks on the }
     713             :     {
     714           1 :         std::stringstream ss;
     715           1 :         ss << "body { background : white url( /images/background.png ) } }";
     716           3 :         csspp::position pos("test.css");
     717           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     718             : 
     719           2 :         csspp::parser p(l);
     720             : 
     721             :         // rule list does not like <!-- and -->
     722           1 :         csspp::node::pointer_t n(p.rule_list());
     723             : 
     724             : //std::cerr << "Result is: [" << *n << "]\n";
     725             : 
     726             :         // this failed with an error, no need to check the "broken" output
     727             : 
     728           1 :         VERIFY_ERRORS(
     729             :                 "test.css(1): error: A qualified rule cannot be empty; you are missing a { ... } block.\n"
     730             :                 "test.css(1): error: Unexpected closing block of type: CLOSE_CURLYBRACKET.\n"
     731             :             );
     732           1 :     }
     733             : 
     734             :     // breaks on the ]
     735             :     {
     736           1 :         std::stringstream ss;
     737           1 :         ss << "body[lili=\"joe\"]] { background : white url( /images/background.png ) } }";
     738           3 :         csspp::position pos("test.css");
     739           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     740             : 
     741           2 :         csspp::parser p(l);
     742             : 
     743             :         // rule list does not like <!-- and -->
     744           1 :         csspp::node::pointer_t n(p.rule_list());
     745             : 
     746             : //std::cerr << "Result is: [" << *n << "]\n";
     747             : 
     748             :         // this failed with an error, no need to check the "broken" output
     749             : 
     750           1 :         VERIFY_ERRORS(
     751             :                 "test.css(1): error: A qualified rule must end with a { ... } block.\n"
     752             :                 "test.css(1): error: Unexpected closing block of type: CLOSE_SQUAREBRACKET.\n"
     753             :             );
     754           1 :     }
     755             : 
     756             :     // breaks on the )
     757             :     {
     758           1 :         std::stringstream ss;
     759           1 :         ss << " body[lili=\"joe\"] { background : white url( /images/background.png ); color:rgba(0,0,0,0)); } ";
     760           3 :         csspp::position pos("test.css");
     761           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     762             : 
     763           2 :         csspp::parser p(l);
     764             : 
     765             :         // rule list does not like <!-- and -->
     766           1 :         csspp::node::pointer_t n(p.rule_list());
     767             : 
     768             : //std::cerr << "Result is: [" << *n << "]\n";
     769             : 
     770             :         // this failed with an error, no need to check the "broken" output
     771             : 
     772           1 :         VERIFY_ERRORS(
     773             :                 "test.css(1): error: Block expected to end with CLOSE_CURLYBRACKET but got CLOSE_PARENTHESIS instead.\n"
     774             :                 //"test.css(1): error: Unexpected closing block of type: CLOSE_PARENTHESIS.\n"
     775             :             );
     776           1 :     }
     777             : 
     778             :     // a @-rule cannot be empty
     779             :     {
     780           1 :         std::stringstream ss;
     781             :         ss << " div { color: blue; }"
     782           1 :            << " @media";
     783           3 :         csspp::position pos("test.css");
     784           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     785             : 
     786           2 :         csspp::parser p(l);
     787             : 
     788             :         // rule list does not like <!-- and -->
     789           1 :         csspp::node::pointer_t n(p.rule_list());
     790             : 
     791             : //std::cerr << "Result is: [" << *n << "]\n";
     792             : 
     793           1 :         VERIFY_ERRORS("test.css(1): error: At '@' command cannot be empty (missing expression or block) unless ended by a semicolon (;).\n");
     794           1 :     }
     795             : 
     796             :     // a @-rule cannot be empty
     797             :     {
     798           1 :         std::stringstream ss;
     799           1 :         ss << "@media test and (this one too) or (that maybe)";
     800           3 :         csspp::position pos("test.css");
     801           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     802             : 
     803           2 :         csspp::parser p(l);
     804             : 
     805             :         // rule list does not like <!-- and -->
     806           1 :         csspp::node::pointer_t n(p.rule_list());
     807             : 
     808             : //std::cerr << "Result is: [" << *n << "]\n";
     809             : 
     810           1 :         VERIFY_ERRORS("test.css(1): error: At '@' command must end with a block or a ';'.\n");
     811           1 :     }
     812             : 
     813             :     // :INTEGER is not valid, plus it is viewed as a nested rule!
     814             :     {
     815           1 :         std::stringstream ss;
     816           1 :         ss << "div:556 {color:bisque}";
     817           3 :         csspp::position pos("test.css");
     818           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     819             : 
     820           2 :         csspp::parser p(l);
     821             : 
     822           1 :         csspp::node::pointer_t n(p.stylesheet());
     823             : 
     824           1 :         VERIFY_ERRORS("test.css(1): error: Variable set to a block and a nested property block must end with a semicolon (;) after said block.\n");
     825           1 :     }
     826             : 
     827             :     // no error left over
     828           1 :     VERIFY_ERRORS("");
     829           1 : }
     830             : 
     831           1 : CATCH_TEST_CASE("One simple rule", "[parser] [rule]")
     832             : {
     833             :     // a simple valid rule
     834             :     {
     835           1 :         std::stringstream ss;
     836           1 :         ss << " body { background : gradient(to bottom, #012, #384513 75%, #452) } ";
     837           3 :         csspp::position pos("test.css");
     838           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     839             : 
     840           2 :         csspp::parser p(l);
     841             : 
     842           1 :         csspp::node::pointer_t n(p.rule());
     843             : 
     844             : //std::cerr << "Result is: [" << *n << "]\n";
     845             : 
     846           1 :         std::stringstream out;
     847           1 :         out << *n;
     848           1 :         VERIFY_TREES(out.str(),
     849             : 
     850             : "COMPONENT_VALUE\n"
     851             : "  IDENTIFIER \"body\"\n"
     852             : "  OPEN_CURLYBRACKET B:false\n"
     853             : "    COMPONENT_VALUE\n"
     854             : "      IDENTIFIER \"background\"\n"
     855             : "      WHITESPACE\n"
     856             : "      COLON\n"
     857             : "      WHITESPACE\n"
     858             : "      FUNCTION \"gradient\"\n"
     859             : "        IDENTIFIER \"to\"\n"
     860             : "        WHITESPACE\n"
     861             : "        IDENTIFIER \"bottom\"\n"
     862             : "        COMMA\n"
     863             : "        WHITESPACE\n"
     864             : "        HASH \"012\"\n"
     865             : "        COMMA\n"
     866             : "        WHITESPACE\n"
     867             : "        HASH \"384513\"\n"
     868             : "        WHITESPACE\n"
     869             : "        PERCENT D:0.75\n"
     870             : "        COMMA\n"
     871             : "        WHITESPACE\n"
     872             : "        HASH \"452\"\n"
     873             : 
     874             :             );
     875             : 
     876           1 :     }
     877             : 
     878             :     // a simple valid rule
     879             :     {
     880           1 :         std::stringstream ss;
     881             :         ss << " div { color: blue; }"
     882             :            << " @media screen { viewport: 1000px 500px; } "
     883           1 :            << " div#op{color:hsl(120,1,0.5)}";
     884           3 :         csspp::position pos("test.css");
     885           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     886             : 
     887           2 :         csspp::parser p(l);
     888             : 
     889           1 :         csspp::node::pointer_t n(p.rule());
     890             : 
     891             : //std::cerr << "Result is: [" << *n << "]\n";
     892             : 
     893           1 :         std::stringstream out;
     894           1 :         out << *n;
     895           1 :         VERIFY_TREES(out.str(),
     896             : 
     897             : "COMPONENT_VALUE\n"
     898             : "  IDENTIFIER \"div\"\n"
     899             : "  OPEN_CURLYBRACKET B:false\n"
     900             : "    COMPONENT_VALUE\n"
     901             : "      IDENTIFIER \"color\"\n"
     902             : "      COLON\n"
     903             : "      WHITESPACE\n"
     904             : "      IDENTIFIER \"blue\"\n"
     905             : 
     906             :             );
     907             : 
     908           1 :         n = p.rule();
     909             : 
     910           1 :         out.str("");
     911           1 :         out << *n;
     912           1 :         VERIFY_TREES(out.str(),
     913             : 
     914             : "AT_KEYWORD \"media\" I:0\n"
     915             : "  IDENTIFIER \"screen\"\n"
     916             : "  OPEN_CURLYBRACKET B:false\n"
     917             : "    COMPONENT_VALUE\n"
     918             : "      IDENTIFIER \"viewport\"\n"
     919             : "      COLON\n"
     920             : "      WHITESPACE\n"
     921             : "      INTEGER \"px\" I:1000\n"
     922             : "      WHITESPACE\n"
     923             : "      INTEGER \"px\" I:500\n"
     924             : 
     925             :             );
     926             : 
     927           1 :         n = p.rule();
     928             : 
     929           1 :         out.str("");
     930           1 :         out << *n;
     931           1 :         VERIFY_TREES(out.str(),
     932             : 
     933             : "COMPONENT_VALUE\n"
     934             : "  IDENTIFIER \"div\"\n"
     935             : "  HASH \"op\"\n"
     936             : "  OPEN_CURLYBRACKET B:false\n"
     937             : "    COMPONENT_VALUE\n"
     938             : "      IDENTIFIER \"color\"\n"
     939             : "      COLON\n"
     940             : "      FUNCTION \"hsl\"\n"
     941             : "        INTEGER \"\" I:120\n"
     942             : "        COMMA\n"
     943             : "        INTEGER \"\" I:1\n"
     944             : "        COMMA\n"
     945             : "        DECIMAL_NUMBER \"\" D:0.5\n"
     946             : 
     947             :             );
     948             : 
     949           1 :     }
     950             : 
     951             :     // no error left over
     952           1 :     VERIFY_ERRORS("");
     953           1 : }
     954             : 
     955           1 : CATCH_TEST_CASE("Invalid one rule", "[parser] [rule] [invalid]")
     956             : {
     957             :     // breaks on the <!--
     958             :     {
     959           1 :         std::stringstream ss;
     960           1 :         ss << "<!-- body { background : white url( /images/background.png ) } -->";
     961           3 :         csspp::position pos("test.css");
     962           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     963             : 
     964           2 :         csspp::parser p(l);
     965             : 
     966           1 :         csspp::node::pointer_t n(p.rule());
     967             : 
     968             : //std::cerr << "Result is: [" << *n << "]\n";
     969             : 
     970             :         // this failed with an error, no need to check the "broken" output
     971             : 
     972           1 :         VERIFY_ERRORS("test.css(1): error: HTML comment delimiters (<!-- and -->) are not allowed in this CSS document.\n");
     973           1 :     }
     974             : 
     975             :     // breaks on the -->
     976             :     {
     977           1 :         std::stringstream ss;
     978           1 :         ss << "--> body { background : white url( /images/background.png ) }";
     979           3 :         csspp::position pos("test.css");
     980           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     981             : 
     982           2 :         csspp::parser p(l);
     983             : 
     984           1 :         csspp::node::pointer_t n(p.rule());
     985             : 
     986             : //std::cerr << "Result is: [" << *n << "]\n";
     987             : 
     988             :         // this failed with an error, no need to check the "broken" output
     989             : 
     990           1 :         VERIFY_ERRORS("test.css(1): error: HTML comment delimiters (<!-- and -->) are not allowed in this CSS document.\n");
     991           1 :     }
     992             : 
     993             :     // breaks on the }
     994             :     {
     995           1 :         std::stringstream ss;
     996           1 :         ss << "body { background : white url( /images/background.png ) } }";
     997           3 :         csspp::position pos("test.css");
     998           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     999             : 
    1000           2 :         csspp::parser p(l);
    1001             : 
    1002             :         // the first read works as expected
    1003           1 :         csspp::node::pointer_t n(p.rule());
    1004             : 
    1005             : //std::cerr << "Result is: [" << *n << "]\n";
    1006             : 
    1007           1 :         std::stringstream out;
    1008           1 :         out << *n;
    1009           1 :         VERIFY_TREES(out.str(),
    1010             : 
    1011             : "COMPONENT_VALUE\n"
    1012             : "  IDENTIFIER \"body\"\n"
    1013             : "  OPEN_CURLYBRACKET B:false\n"
    1014             : "    COMPONENT_VALUE\n"
    1015             : "      IDENTIFIER \"background\"\n"
    1016             : "      WHITESPACE\n"
    1017             : "      COLON\n"
    1018             : "      WHITESPACE\n"
    1019             : "      IDENTIFIER \"white\"\n"
    1020             : "      WHITESPACE\n"
    1021             : "      URL \"/images/background.png\"\n"
    1022             : 
    1023             :             );
    1024             : 
    1025             :         // this failed with an error, no need to check the "broken" output
    1026           1 :         n = p.rule();
    1027             : 
    1028           1 :         VERIFY_ERRORS(
    1029             :                 "test.css(1): error: A qualified rule cannot be empty; you are missing a { ... } block.\n"
    1030             :                 //"test.css(1): error: Unexpected closing block of type: CLOSE_CURLYBRACKET.\n"
    1031             :             );
    1032           1 :     }
    1033             : 
    1034             :     // breaks on the ]
    1035             :     {
    1036           1 :         std::stringstream ss;
    1037           1 :         ss << "body[lili=\"joe\"]] { background : white url( /images/background.png ) } }";
    1038           3 :         csspp::position pos("test.css");
    1039           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1040             : 
    1041           2 :         csspp::parser p(l);
    1042             : 
    1043             :         // rule up to the spurious ']' is all proper
    1044           1 :         csspp::node::pointer_t n(p.rule());
    1045             : 
    1046             : //std::cerr << "Result is: [" << *n << "]\n";
    1047             : 
    1048           1 :         std::stringstream out;
    1049           1 :         out << *n;
    1050           1 :         VERIFY_TREES(out.str(),
    1051             : 
    1052             : "COMPONENT_VALUE\n"
    1053             : "  IDENTIFIER \"body\"\n"
    1054             : "  OPEN_SQUAREBRACKET\n"
    1055             : "    IDENTIFIER \"lili\"\n"
    1056             : "    EQUAL\n"
    1057             : "    STRING \"joe\"\n"
    1058             : 
    1059             :             );
    1060             : 
    1061             :         // this failed with an error, no need to check the "broken" output
    1062           1 :         n = p.rule();
    1063             : 
    1064           1 :         VERIFY_ERRORS(
    1065             :                 "test.css(1): error: A qualified rule must end with a { ... } block.\n"
    1066             :                 "test.css(1): error: Unexpected closing block of type: CLOSE_SQUAREBRACKET.\n"
    1067             :             );
    1068           1 :     }
    1069             : 
    1070             :     // breaks on the )
    1071             :     {
    1072           1 :         std::stringstream ss;
    1073           1 :         ss << " body[lili=\"joe\"] { background : white url( /images/background.png ); color:rgba(0,0,0,0)); } ";
    1074           3 :         csspp::position pos("test.css");
    1075           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1076             : 
    1077           2 :         csspp::parser p(l);
    1078             : 
    1079           1 :         csspp::node::pointer_t n(p.rule());
    1080             : 
    1081             : //std::cerr << "Result is: [" << *n << "]\n";
    1082             : 
    1083             :         // this failed with an error, no need to check the "broken" output
    1084             : 
    1085           1 :         VERIFY_ERRORS(
    1086             :                 "test.css(1): error: Block expected to end with CLOSE_CURLYBRACKET but got CLOSE_PARENTHESIS instead.\n"
    1087             :                 //"test.css(1): error: Unexpected closing block of type: CLOSE_PARENTHESIS.\n"
    1088             :             );
    1089           1 :     }
    1090             : 
    1091             : //    // a @-rule cannot be empty
    1092             : //    {
    1093             : //        std::stringstream ss;
    1094             : //        ss << " div { color: blue; }"
    1095             : //           << " @media";
    1096             : //        csspp::position pos("test.css");
    1097             : //        csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1098             : //
    1099             : //        csspp::parser p(l);
    1100             : //
    1101             : //        csspp::node::pointer_t n(p.rule());
    1102             : //
    1103             : ////std::cerr << "Result is: [" << *n << "]\n";
    1104             : //
    1105             : //        std::stringstream out;
    1106             : //        out << *n;
    1107             : //        VERIFY_TREES(out.str(),
    1108             : //
    1109             : //"COMPONENT_VALUE\n"
    1110             : //"  IDENTIFIER \"div\"\n"
    1111             : //"  OPEN_CURLYBRACKET B:false\n"
    1112             : //"    IDENTIFIER \"color\"\n"
    1113             : //"    COLON\n"
    1114             : //"    WHITESPACE\n"
    1115             : //"    IDENTIFIER \"blue\"\n"
    1116             : //
    1117             : //            );
    1118             : //
    1119             : //        // this failed with an error, no need to check the "broken" output
    1120             : //        n = p.rule();
    1121             : //
    1122             : //        VERIFY_ERRORS("test.css(1): error: At '@' command cannot be empty (missing expression or block) unless ended by a semicolon (;).\n");
    1123             : //    }
    1124             : //
    1125             : //    // a @-rule cannot be empty
    1126             : //    {
    1127             : //        std::stringstream ss;
    1128             : //        ss << "@media test and (this one too) or (that maybe)";
    1129             : //        csspp::position pos("test.css");
    1130             : //        csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1131             : //
    1132             : //        csspp::parser p(l);
    1133             : //
    1134             : //        csspp::node::pointer_t n(p.rule());
    1135             : //
    1136             : ////std::cerr << "Result is: [" << *n << "]\n";
    1137             : //
    1138             : //        VERIFY_ERRORS("test.css(1): error: At '@' command must end with a block or a ';'.\n");
    1139             : //    }
    1140             : 
    1141             :     // no error left over
    1142           1 :     VERIFY_ERRORS("");
    1143           1 : }
    1144             : 
    1145           1 : CATCH_TEST_CASE("Simple component values", "[parser] [component-value]")
    1146             : {
    1147             :     // a simple valid rule
    1148             :     {
    1149           1 :         std::stringstream ss;
    1150           1 :         ss << " body { background : gradient(to bottom, #012, #384513 75%, #452) } ";
    1151           3 :         csspp::position pos("test.css");
    1152           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1153             : 
    1154           2 :         csspp::parser p(l);
    1155             : 
    1156           1 :         csspp::node::pointer_t n(p.component_value_list());
    1157             : 
    1158             : //std::cerr << "Result is: [" << *n << "]\n";
    1159             : 
    1160           1 :         std::stringstream out;
    1161           1 :         out << *n;
    1162           1 :         VERIFY_TREES(out.str(),
    1163             : 
    1164             : "COMPONENT_VALUE\n"
    1165             : "  IDENTIFIER \"body\"\n"
    1166             : "  OPEN_CURLYBRACKET B:false\n"
    1167             : "    COMPONENT_VALUE\n"
    1168             : "      IDENTIFIER \"background\"\n"
    1169             : "      WHITESPACE\n"
    1170             : "      COLON\n"
    1171             : "      WHITESPACE\n"
    1172             : "      FUNCTION \"gradient\"\n"
    1173             : "        IDENTIFIER \"to\"\n"
    1174             : "        WHITESPACE\n"
    1175             : "        IDENTIFIER \"bottom\"\n"
    1176             : "        COMMA\n"
    1177             : "        WHITESPACE\n"
    1178             : "        HASH \"012\"\n"
    1179             : "        COMMA\n"
    1180             : "        WHITESPACE\n"
    1181             : "        HASH \"384513\"\n"
    1182             : "        WHITESPACE\n"
    1183             : "        PERCENT D:0.75\n"
    1184             : "        COMMA\n"
    1185             : "        WHITESPACE\n"
    1186             : "        HASH \"452\"\n"
    1187             : 
    1188             :             );
    1189             : 
    1190           1 :     }
    1191             : 
    1192             :     // a simple valid rule
    1193             :     {
    1194           1 :         std::stringstream ss;
    1195             :         ss << " div { color: blue; }"
    1196             :            << " @media screen { viewport: 1000px 500px; } "
    1197           1 :            << " div#op{color:hsl(120,1,0.5)}";
    1198           3 :         csspp::position pos("test.css");
    1199           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1200             : 
    1201           2 :         csspp::parser p(l);
    1202             : 
    1203           1 :         csspp::node::pointer_t n(p.component_value_list());
    1204             : 
    1205             : //std::cerr << "Result is: [" << *n << "]\n";
    1206             : 
    1207           1 :         std::stringstream out;
    1208           1 :         out << *n;
    1209           1 :         VERIFY_TREES(out.str(),
    1210             : 
    1211             : "COMPONENT_VALUE\n"
    1212             : "  IDENTIFIER \"div\"\n"
    1213             : "  OPEN_CURLYBRACKET B:false\n"
    1214             : "    COMPONENT_VALUE\n"
    1215             : "      IDENTIFIER \"color\"\n"
    1216             : "      COLON\n"
    1217             : "      WHITESPACE\n"
    1218             : "      IDENTIFIER \"blue\"\n"
    1219             : 
    1220             :             );
    1221             : 
    1222           1 :         n = p.rule();
    1223             : 
    1224           1 :         out.str("");
    1225           1 :         out << *n;
    1226           1 :         VERIFY_TREES(out.str(),
    1227             : 
    1228             : "AT_KEYWORD \"media\" I:0\n"
    1229             : "  IDENTIFIER \"screen\"\n"
    1230             : "  OPEN_CURLYBRACKET B:false\n"
    1231             : "    COMPONENT_VALUE\n"
    1232             : "      IDENTIFIER \"viewport\"\n"
    1233             : "      COLON\n"
    1234             : "      WHITESPACE\n"
    1235             : "      INTEGER \"px\" I:1000\n"
    1236             : "      WHITESPACE\n"
    1237             : "      INTEGER \"px\" I:500\n"
    1238             : 
    1239             :             );
    1240             : 
    1241           1 :         n = p.rule();
    1242             : 
    1243           1 :         out.str("");
    1244           1 :         out << *n;
    1245           1 :         VERIFY_TREES(out.str(),
    1246             : 
    1247             : "COMPONENT_VALUE\n"
    1248             : "  IDENTIFIER \"div\"\n"
    1249             : "  HASH \"op\"\n"
    1250             : "  OPEN_CURLYBRACKET B:false\n"
    1251             : "    COMPONENT_VALUE\n"
    1252             : "      IDENTIFIER \"color\"\n"
    1253             : "      COLON\n"
    1254             : "      FUNCTION \"hsl\"\n"
    1255             : "        INTEGER \"\" I:120\n"
    1256             : "        COMMA\n"
    1257             : "        INTEGER \"\" I:1\n"
    1258             : "        COMMA\n"
    1259             : "        DECIMAL_NUMBER \"\" D:0.5\n"
    1260             : 
    1261             :             );
    1262             : 
    1263           1 :     }
    1264             : 
    1265             :     // no error left over
    1266           1 :     VERIFY_ERRORS("");
    1267           1 : }
    1268             : 
    1269           1 : CATCH_TEST_CASE("Invalid component values", "[parser] [component-value] [invalid]")
    1270             : {
    1271             :     // breaks on missing }
    1272             :     {
    1273           1 :         std::stringstream ss;
    1274           1 :         ss << "body { background : white url( /images/background.png )";
    1275           3 :         csspp::position pos("test.css");
    1276           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1277             : 
    1278           2 :         csspp::parser p(l);
    1279             : 
    1280           1 :         csspp::node::pointer_t n(p.component_value_list());
    1281             : 
    1282             : //std::cerr << "Result is: [" << *n << "]\n";
    1283             : 
    1284             :         // this failed with an error, no need to check the "broken" output
    1285             : 
    1286           1 :         VERIFY_ERRORS(
    1287             :                 "test.css(1): error: Block expected to end with CLOSE_CURLYBRACKET but got EOF_TOKEN instead.\n"
    1288             :             );
    1289           1 :     }
    1290             : 
    1291             :     // breaks on missing ]
    1292             :     {
    1293           1 :         std::stringstream ss;
    1294           1 :         ss << "body[lili=\"joe\" { background : white url( /images/background.png ) } }";
    1295           3 :         csspp::position pos("test.css");
    1296           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1297             : 
    1298           2 :         csspp::parser p(l);
    1299             : 
    1300             :         // rule list does not like <!-- and -->
    1301           1 :         csspp::node::pointer_t n(p.component_value_list());
    1302             : 
    1303             : //std::cerr << "Result is: [" << *n << "]\n";
    1304             : 
    1305             :         // this failed with an error, no need to check the "broken" output
    1306             : 
    1307           1 :         VERIFY_ERRORS(
    1308             :                 "test.css(1): error: Block expected to end with CLOSE_SQUAREBRACKET but got CLOSE_CURLYBRACKET instead.\n"
    1309             :             );
    1310           1 :     }
    1311             : 
    1312             :     // breaks on missing )
    1313             :     {
    1314           1 :         std::stringstream ss;
    1315           1 :         ss << " body[lili=\"joe\"] { background : white url( /images/background.png ); color:rgba(0,0,0,0; } ";
    1316           3 :         csspp::position pos("test.css");
    1317           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1318             : 
    1319           2 :         csspp::parser p(l);
    1320             : 
    1321           1 :         csspp::node::pointer_t n(p.component_value_list());
    1322             : 
    1323             : //std::cerr << "Result is: [" << *n << "]\n";
    1324             : 
    1325             :         // this failed with an error, no need to check the "broken" output
    1326             : 
    1327           1 :         VERIFY_ERRORS(
    1328             :                 "test.css(1): error: Block expected to end with CLOSE_PARENTHESIS but got CLOSE_CURLYBRACKET instead.\n"
    1329             :             );
    1330           1 :     }
    1331             : 
    1332             :     // no error left over
    1333           1 :     VERIFY_ERRORS("");
    1334           1 : }
    1335             : 
    1336           1 : CATCH_TEST_CASE("Simple one component value", "[parser] [component-value]")
    1337             : {
    1338             :     // a simple valid rule
    1339             :     {
    1340           1 :         std::stringstream ss;
    1341             :         ss << " body { background : gradient(to bottom, #012, #384513 75%, #452) }"
    1342           1 :            << " @media screen { viewport: 1000px 500px; }";
    1343           3 :         csspp::position pos("test.css");
    1344           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1345             : 
    1346           2 :         csspp::parser p(l);
    1347             : 
    1348           1 :         char const *results[] =
    1349             :         {
    1350             :             "WHITESPACE\n",
    1351             : 
    1352             :             "IDENTIFIER \"body\"\n",
    1353             : 
    1354             :             "WHITESPACE\n",
    1355             : 
    1356             :             "OPEN_CURLYBRACKET B:false\n"
    1357             :             "  COMPONENT_VALUE\n"
    1358             :             "    IDENTIFIER \"background\"\n"
    1359             :             "    WHITESPACE\n"
    1360             :             "    COLON\n"
    1361             :             "    WHITESPACE\n"
    1362             :             "    FUNCTION \"gradient\"\n"
    1363             :             "      IDENTIFIER \"to\"\n"
    1364             :             "      WHITESPACE\n"
    1365             :             "      IDENTIFIER \"bottom\"\n"
    1366             :             "      COMMA\n"
    1367             :             "      WHITESPACE\n"
    1368             :             "      HASH \"012\"\n"
    1369             :             "      COMMA\n"
    1370             :             "      WHITESPACE\n"
    1371             :             "      HASH \"384513\"\n"
    1372             :             "      WHITESPACE\n"
    1373             :             "      PERCENT D:0.75\n"
    1374             :             "      COMMA\n"
    1375             :             "      WHITESPACE\n"
    1376             :             "      HASH \"452\"\n",
    1377             : 
    1378             :             "WHITESPACE\n",
    1379             : 
    1380             :             "AT_KEYWORD \"media\" I:0\n",
    1381             : 
    1382             :             "WHITESPACE\n",
    1383             : 
    1384             :             "IDENTIFIER \"screen\"\n",
    1385             : 
    1386             :             "WHITESPACE\n",
    1387             : 
    1388             :             "OPEN_CURLYBRACKET B:false\n"
    1389             :             "  COMPONENT_VALUE\n"
    1390             :             "    IDENTIFIER \"viewport\"\n"
    1391             :             "    COLON\n"
    1392             :             "    WHITESPACE\n"
    1393             :             "    INTEGER \"px\" I:1000\n"
    1394             :             "    WHITESPACE\n"
    1395             :             "    INTEGER \"px\" I:500\n",
    1396             : 
    1397             :             // make sure to keep the following to make sure we got everything
    1398             :             // through the parser
    1399             :             "EOF_TOKEN\n"
    1400             :         };
    1401             : 
    1402          12 :         for(size_t i(0); i < sizeof(results) / sizeof(results[0]); ++i)
    1403             :         {
    1404          11 :             csspp::node::pointer_t n(p.component_value());
    1405          11 :             std::stringstream out;
    1406          11 :             out << *n;
    1407          11 :             VERIFY_TREES(out.str(), results[i]);
    1408          11 :             csspp_test::compare(out.str(), results[i], __FILE__, i + 1);
    1409          11 :         }
    1410             : 
    1411           1 :     }
    1412             : 
    1413             :     // no error left over
    1414           1 :     VERIFY_ERRORS("");
    1415           1 : }
    1416             : 
    1417           1 : CATCH_TEST_CASE("Invalid one component value", "[parser] [component-value] [invalid]")
    1418             : {
    1419             :     // breaks on missing }
    1420             :     {
    1421           1 :         std::stringstream ss;
    1422           1 :         ss << "body { background : 123";
    1423           3 :         csspp::position pos("test.css");
    1424           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1425             : 
    1426           2 :         csspp::parser p(l);
    1427             : 
    1428           1 :         char const *results[] =
    1429             :         {
    1430             :             "IDENTIFIER \"body\"\n",
    1431             : 
    1432             :             "WHITESPACE\n",
    1433             : 
    1434             :             "OPEN_CURLYBRACKET B:false\n"
    1435             :             "  COMPONENT_VALUE\n"
    1436             :             "    IDENTIFIER \"background\"\n"
    1437             :             "    WHITESPACE\n"
    1438             :             "    COLON\n"
    1439             :             "    WHITESPACE\n"
    1440             :             "    INTEGER \"\" I:123\n",
    1441             : 
    1442             :             // make sure to keep the following to make sure we got everything
    1443             :             // through the parser
    1444             :             "EOF_TOKEN\n"
    1445             :         };
    1446             : 
    1447           5 :         for(size_t i(0); i < sizeof(results) / sizeof(results[0]); ++i)
    1448             :         {
    1449           4 :             csspp::node::pointer_t n(p.component_value());
    1450           4 :             std::stringstream out;
    1451           4 :             out << *n;
    1452           4 :             VERIFY_TREES(out.str(), results[i]);
    1453           4 :             csspp_test::compare(out.str(), results[i], __FILE__, i + 1);
    1454           4 :         }
    1455             : 
    1456           1 :         VERIFY_ERRORS("test.css(1): error: Block expected to end with CLOSE_CURLYBRACKET but got EOF_TOKEN instead.\n");
    1457           1 :     }
    1458             : 
    1459             :     // breaks on missing ]
    1460             :     {
    1461           1 :         std::stringstream ss;
    1462           1 :         ss << "body[color='55'";
    1463           3 :         csspp::position pos("test.css");
    1464           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1465             : 
    1466           2 :         csspp::parser p(l);
    1467             : 
    1468           1 :         char const *results[] =
    1469             :         {
    1470             :             "IDENTIFIER \"body\"\n",
    1471             : 
    1472             :             "OPEN_SQUAREBRACKET\n"
    1473             :             "  IDENTIFIER \"color\"\n"
    1474             :             "  EQUAL\n"
    1475             :             "  STRING \"55\"\n",
    1476             : 
    1477             :             // make sure to keep the following to make sure we got everything
    1478             :             // through the parser
    1479             :             "EOF_TOKEN\n"
    1480             :         };
    1481             : 
    1482           4 :         for(size_t i(0); i < sizeof(results) / sizeof(results[0]); ++i)
    1483             :         {
    1484           3 :             csspp::node::pointer_t n(p.component_value());
    1485           3 :             std::stringstream out;
    1486           3 :             out << *n;
    1487           3 :             VERIFY_TREES(out.str(), results[i]);
    1488           3 :             csspp_test::compare(out.str(), results[i], __FILE__, i + 1);
    1489           3 :         }
    1490             : 
    1491           1 :         VERIFY_ERRORS("test.css(1): error: Block expected to end with CLOSE_SQUAREBRACKET but got EOF_TOKEN instead.\n");
    1492           1 :     }
    1493             : 
    1494             :     // breaks on missing )
    1495             :     {
    1496           1 :         std::stringstream ss;
    1497           1 :         ss << "body{color:rgba(1,2}";
    1498           3 :         csspp::position pos("test.css");
    1499           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1500             : 
    1501           2 :         csspp::parser p(l);
    1502             : 
    1503           1 :         char const *results[] =
    1504             :         {
    1505             :             "IDENTIFIER \"body\"\n",
    1506             : 
    1507             :             "OPEN_CURLYBRACKET B:false\n"
    1508             :             "  COMPONENT_VALUE\n"
    1509             :             "    IDENTIFIER \"color\"\n"
    1510             :             "    COLON\n"
    1511             :             "    FUNCTION \"rgba\"\n"
    1512             :             "      INTEGER \"\" I:1\n"
    1513             :             "      COMMA\n"
    1514             :             "      INTEGER \"\" I:2\n",
    1515             : 
    1516             :             // make sure to keep the following to make sure we got everything
    1517             :             // through the parser
    1518             :             "EOF_TOKEN\n"
    1519             :         };
    1520             : 
    1521           4 :         for(size_t i(0); i < sizeof(results) / sizeof(results[0]); ++i)
    1522             :         {
    1523           3 :             csspp::node::pointer_t n(p.component_value());
    1524           3 :             std::stringstream out;
    1525           3 :             out << *n;
    1526           3 :             VERIFY_TREES(out.str(), results[i]);
    1527           3 :             csspp_test::compare(out.str(), results[i], __FILE__, i + 1);
    1528           3 :         }
    1529             : 
    1530           1 :         VERIFY_ERRORS("test.css(1): error: Block expected to end with CLOSE_PARENTHESIS but got CLOSE_CURLYBRACKET instead.\n");
    1531           1 :     }
    1532             : 
    1533             :     // no error left over
    1534           1 :     VERIFY_ERRORS("");
    1535           1 : }
    1536             : 
    1537           1 : CATCH_TEST_CASE("Simple declarations", "[parser] [declaration]")
    1538             : {
    1539             :     // a simple valid declaration
    1540             :     {
    1541           1 :         std::stringstream ss;
    1542           1 :         ss << " background : gradient(to bottom, #012, #384513 75%, #452) { width: 300px } ";
    1543           3 :         csspp::position pos("test.css");
    1544           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1545             : 
    1546           2 :         csspp::parser p(l);
    1547             : 
    1548             :         // rule list does not like <!-- and -->
    1549           1 :         csspp::node::pointer_t n(p.declaration_list());
    1550             : 
    1551             : //std::cerr << "Result is: [" << *n << "]\n";
    1552             : 
    1553           1 :         std::stringstream out;
    1554           1 :         out << *n;
    1555           1 :         VERIFY_TREES(out.str(),
    1556             : 
    1557             : "LIST\n"
    1558             : "  DECLARATION \"background\"\n"
    1559             : "    COMPONENT_VALUE\n"
    1560             : "      FUNCTION \"gradient\"\n"
    1561             : "        IDENTIFIER \"to\"\n"
    1562             : "        WHITESPACE\n"
    1563             : "        IDENTIFIER \"bottom\"\n"
    1564             : "        COMMA\n"
    1565             : "        WHITESPACE\n"
    1566             : "        HASH \"012\"\n"
    1567             : "        COMMA\n"
    1568             : "        WHITESPACE\n"
    1569             : "        HASH \"384513\"\n"
    1570             : "        WHITESPACE\n"
    1571             : "        PERCENT D:0.75\n"
    1572             : "        COMMA\n"
    1573             : "        WHITESPACE\n"
    1574             : "        HASH \"452\"\n"
    1575             : "      OPEN_CURLYBRACKET B:false\n"
    1576             : "        COMPONENT_VALUE\n"
    1577             : "          IDENTIFIER \"width\"\n"
    1578             : "          COLON\n"
    1579             : "          WHITESPACE\n"
    1580             : "          INTEGER \"px\" I:300\n"
    1581             : 
    1582             :             );
    1583             : 
    1584             :         // no error left over
    1585           1 :         VERIFY_ERRORS("");
    1586           1 :     }
    1587             : 
    1588             :     // a @-rule in a declaration
    1589             :     {
    1590           1 :         std::stringstream ss;
    1591           1 :         ss << " @enhanced capabilities { background : gradient(to bottom, #012, #384513 75%, #452) } ";
    1592           3 :         csspp::position pos("test.css");
    1593           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1594             : 
    1595           2 :         csspp::parser p(l);
    1596             : 
    1597             :         // rule list does not like <!-- and -->
    1598           1 :         csspp::node::pointer_t n(p.declaration_list());
    1599             : 
    1600             : //std::cerr << "Result is: [" << *n << "]\n";
    1601             : 
    1602           1 :         std::stringstream out;
    1603           1 :         out << *n;
    1604           1 :         VERIFY_TREES(out.str(),
    1605             : 
    1606             : "LIST\n"
    1607             : "  AT_KEYWORD \"enhanced\" I:0\n"
    1608             : "    IDENTIFIER \"capabilities\"\n"
    1609             : "    OPEN_CURLYBRACKET B:false\n"
    1610             : "      COMPONENT_VALUE\n"
    1611             : "        IDENTIFIER \"background\"\n"
    1612             : "        WHITESPACE\n"
    1613             : "        COLON\n"
    1614             : "        WHITESPACE\n"
    1615             : "        FUNCTION \"gradient\"\n"
    1616             : "          IDENTIFIER \"to\"\n"
    1617             : "          WHITESPACE\n"
    1618             : "          IDENTIFIER \"bottom\"\n"
    1619             : "          COMMA\n"
    1620             : "          WHITESPACE\n"
    1621             : "          HASH \"012\"\n"
    1622             : "          COMMA\n"
    1623             : "          WHITESPACE\n"
    1624             : "          HASH \"384513\"\n"
    1625             : "          WHITESPACE\n"
    1626             : "          PERCENT D:0.75\n"
    1627             : "          COMMA\n"
    1628             : "          WHITESPACE\n"
    1629             : "          HASH \"452\"\n"
    1630             : 
    1631             :             );
    1632             : 
    1633             :         // no error left over
    1634           1 :         VERIFY_ERRORS("");
    1635           1 :     }
    1636             : 
    1637             :     // multiple declarations require a ';'
    1638             :     {
    1639           1 :         std::stringstream ss;
    1640           1 :         ss << "a: 33px; b: 66px; c: 123px";
    1641           3 :         csspp::position pos("test.css");
    1642           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1643             : 
    1644           2 :         csspp::parser p(l);
    1645             : 
    1646             :         // rule list does not like <!-- and -->
    1647           1 :         csspp::node::pointer_t n(p.declaration_list());
    1648             : 
    1649             : //std::cerr << "Result is: [" << *n << "]\n";
    1650             : 
    1651           1 :         std::stringstream out;
    1652           1 :         out << *n;
    1653           1 :         VERIFY_TREES(out.str(),
    1654             : 
    1655             : "LIST\n"
    1656             : "  DECLARATION \"a\"\n"
    1657             : "    COMPONENT_VALUE\n"
    1658             : "      INTEGER \"px\" I:33\n"
    1659             : "  DECLARATION \"b\"\n"
    1660             : "    COMPONENT_VALUE\n"
    1661             : "      INTEGER \"px\" I:66\n"
    1662             : "  DECLARATION \"c\"\n"
    1663             : "    COMPONENT_VALUE\n"
    1664             : "      INTEGER \"px\" I:123\n"
    1665             : 
    1666             :             );
    1667             : 
    1668             :         // no error left over
    1669           1 :         VERIFY_ERRORS("");
    1670           1 :     }
    1671             : 
    1672             :     // multiple declarations require a ';'
    1673             :     {
    1674           1 :         std::stringstream ss;
    1675           1 :         ss << "a: 33px ! important ; b: 66px !global ; c: 123px 55em !import";
    1676           3 :         csspp::position pos("test.css");
    1677           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1678             : 
    1679           2 :         csspp::parser p(l);
    1680             : 
    1681             :         // rule list does not like <!-- and -->
    1682           1 :         csspp::node::pointer_t n(p.declaration_list());
    1683             : 
    1684             : //std::cerr << "Result is: [" << *n << "]\n";
    1685             : 
    1686           1 :         std::stringstream out;
    1687           1 :         out << *n;
    1688           1 :         VERIFY_TREES(out.str(),
    1689             : 
    1690             : "LIST\n"
    1691             : "  DECLARATION \"a\"\n"
    1692             : "    COMPONENT_VALUE\n"
    1693             : "      INTEGER \"px\" I:33\n"
    1694             : "      EXCLAMATION \"important\"\n"
    1695             : "  DECLARATION \"b\"\n"
    1696             : "    COMPONENT_VALUE\n"
    1697             : "      INTEGER \"px\" I:66\n"
    1698             : "      EXCLAMATION \"global\"\n"
    1699             : "  DECLARATION \"c\"\n"
    1700             : "    COMPONENT_VALUE\n"
    1701             : "      INTEGER \"px\" I:123\n"
    1702             : "      WHITESPACE\n"
    1703             : "      INTEGER \"em\" I:55\n"
    1704             : "      EXCLAMATION \"import\"\n"
    1705             : 
    1706             :             );
    1707             : 
    1708             :         // no error left over
    1709           1 :         VERIFY_ERRORS("");
    1710           1 :     }
    1711           1 : }
    1712             : 
    1713           1 : CATCH_TEST_CASE("Invalid declarations", "[parser] [declaration] [invalid]")
    1714             : {
    1715             :     // declarations must end with EOF
    1716             :     {
    1717           1 :         std::stringstream ss;
    1718           1 :         ss << " background : gradient(to bottom, #012, #384513 75%, #452) { width: 300px } <!--";
    1719           3 :         csspp::position pos("test.css");
    1720           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1721             : 
    1722           2 :         csspp::parser p(l);
    1723             : 
    1724             :         // rule list does not like <!-- and -->
    1725           1 :         csspp::node::pointer_t n(p.declaration_list());
    1726             : 
    1727             : //std::cerr << "Result is: [" << *n << "]\n";
    1728             : 
    1729           1 :         VERIFY_ERRORS("test.css(1): error: the end of the stream was not reached in this declaration, we stopped on a CDO.\n");
    1730           1 :     }
    1731             : 
    1732             :     // declarations missing a ':'
    1733             :     {
    1734           1 :         std::stringstream ss;
    1735           1 :         ss << " background gradient(to bottom, #012, #384513 75%, #452) { width: 300px } ";
    1736           3 :         csspp::position pos("test.css");
    1737           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1738             : 
    1739           2 :         csspp::parser p(l);
    1740             : 
    1741             :         // rule list does not like <!-- and -->
    1742           1 :         csspp::node::pointer_t n(p.declaration_list());
    1743             : 
    1744             : //std::cerr << "Result is: [" << *n << "]\n";
    1745             : 
    1746           1 :         VERIFY_ERRORS(
    1747             :                 "test.css(1): error: ':' missing in your declaration starting with \"background\".\n"
    1748             :             );
    1749           1 :     }
    1750             : 
    1751             :     // '!' without an identifier
    1752             :     {
    1753           1 :         std::stringstream ss;
    1754           1 :         ss << "background: !gradient(to bottom, #012, #384513 75%, #452)";
    1755           3 :         csspp::position pos("test.css");
    1756           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1757             : 
    1758           2 :         csspp::parser p(l);
    1759             : 
    1760             :         // rule list does not like <!-- and -->
    1761           1 :         csspp::node::pointer_t n(p.declaration_list());
    1762             : 
    1763             : //std::cerr << "Result is: [" << *n << "]\n";
    1764             : 
    1765           1 :         VERIFY_ERRORS(
    1766             :                 "test.css(1): error: A '!' must be followed by an identifier, got a FUNCTION instead.\n"
    1767             :                 //"test.css(1): error: the end of the stream was not reached in this declaration, we stopped on a FUNCTION.\n"
    1768             :             );
    1769           1 :     }
    1770             : 
    1771             :     // no error left over
    1772           1 :     VERIFY_ERRORS("");
    1773           1 : }
    1774             : 
    1775           1 : CATCH_TEST_CASE("Multi-line, multi-level stylesheet", "[parser] [rules]")
    1776             : {
    1777             :     {
    1778           1 :         std::stringstream ss;
    1779             :         ss << "body { background : white url( /images/background.png ) }"
    1780             :               "div.power-house { !important margin: 0; color: red ; }"
    1781             :               "a { text-decoration: none; }"
    1782             :               "$green: #080;"
    1783             :               "#doll { background-color: $green; &:hover { color: teal; } }"
    1784           1 :               "@supports (background-color and border-radius) or (background-image) { body > E ~ F + G H { font-style: italic } }"
    1785             :            ;
    1786           3 :         csspp::position pos("test.css");
    1787           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1788             : 
    1789           2 :         csspp::parser p(l);
    1790             : 
    1791           1 :         csspp::node::pointer_t n(p.stylesheet());
    1792             : 
    1793             :         // no error happened
    1794           1 :         VERIFY_ERRORS("");
    1795             : 
    1796             : //std::cerr << "Result is: [" << *n << "]\n";
    1797             : 
    1798           1 :         std::stringstream out;
    1799           1 :         out << *n;
    1800           1 :         VERIFY_TREES(out.str(),
    1801             : 
    1802             : "LIST\n"
    1803             : "  COMPONENT_VALUE\n"
    1804             : "    IDENTIFIER \"body\"\n"
    1805             : "    OPEN_CURLYBRACKET B:false\n"
    1806             : "      COMPONENT_VALUE\n"
    1807             : "        IDENTIFIER \"background\"\n"
    1808             : "        WHITESPACE\n"
    1809             : "        COLON\n"
    1810             : "        WHITESPACE\n"
    1811             : "        IDENTIFIER \"white\"\n"
    1812             : "        WHITESPACE\n"
    1813             : "        URL \"/images/background.png\"\n"
    1814             : "  COMPONENT_VALUE\n"
    1815             : "    IDENTIFIER \"div\"\n"
    1816             : "    PERIOD\n"
    1817             : "    IDENTIFIER \"power-house\"\n"
    1818             : "    OPEN_CURLYBRACKET B:false\n"
    1819             : "      LIST\n"
    1820             : "        COMPONENT_VALUE\n"
    1821             : "          EXCLAMATION \"important\"\n"
    1822             : "          IDENTIFIER \"margin\"\n"
    1823             : "          COLON\n"
    1824             : "          WHITESPACE\n"
    1825             : "          INTEGER \"\" I:0\n"
    1826             : "        COMPONENT_VALUE\n"
    1827             : "          IDENTIFIER \"color\"\n"
    1828             : "          COLON\n"
    1829             : "          WHITESPACE\n"
    1830             : "          IDENTIFIER \"red\"\n"
    1831             : "  COMPONENT_VALUE\n"
    1832             : "    IDENTIFIER \"a\"\n"
    1833             : "    OPEN_CURLYBRACKET B:false\n"
    1834             : "      COMPONENT_VALUE\n"
    1835             : "        IDENTIFIER \"text-decoration\"\n"
    1836             : "        COLON\n"
    1837             : "        WHITESPACE\n"
    1838             : "        IDENTIFIER \"none\"\n"
    1839             : "  COMPONENT_VALUE\n"
    1840             : "    VARIABLE \"green\"\n"
    1841             : "    COLON\n"
    1842             : "    WHITESPACE\n"
    1843             : "    HASH \"080\"\n"
    1844             : "  COMPONENT_VALUE\n"
    1845             : "    HASH \"doll\"\n"
    1846             : "    OPEN_CURLYBRACKET B:false\n"
    1847             : "      LIST\n"
    1848             : "        COMPONENT_VALUE\n"
    1849             : "          IDENTIFIER \"background-color\"\n"
    1850             : "          COLON\n"
    1851             : "          WHITESPACE\n"
    1852             : "          VARIABLE \"green\"\n"
    1853             : "        COMPONENT_VALUE\n"
    1854             : "          REFERENCE\n"
    1855             : "          COLON\n"
    1856             : "          IDENTIFIER \"hover\"\n"
    1857             : "          OPEN_CURLYBRACKET B:false\n"
    1858             : "            COMPONENT_VALUE\n"
    1859             : "              IDENTIFIER \"color\"\n"
    1860             : "              COLON\n"
    1861             : "              WHITESPACE\n"
    1862             : "              IDENTIFIER \"teal\"\n"
    1863             : "  AT_KEYWORD \"supports\" I:0\n"
    1864             : "    OPEN_PARENTHESIS\n"
    1865             : "      IDENTIFIER \"background-color\"\n"
    1866             : "      WHITESPACE\n"
    1867             : "      IDENTIFIER \"and\"\n"
    1868             : "      WHITESPACE\n"
    1869             : "      IDENTIFIER \"border-radius\"\n"
    1870             : "    WHITESPACE\n"
    1871             : "    IDENTIFIER \"or\"\n"
    1872             : "    OPEN_PARENTHESIS\n"
    1873             : "      IDENTIFIER \"background-image\"\n"
    1874             : "    OPEN_CURLYBRACKET B:false\n"
    1875             : "      COMPONENT_VALUE\n"
    1876             : "        IDENTIFIER \"body\"\n"
    1877             : "        WHITESPACE\n"
    1878             : "        GREATER_THAN\n"
    1879             : "        WHITESPACE\n"
    1880             : "        IDENTIFIER \"E\"\n"
    1881             : "        WHITESPACE\n"
    1882             : "        PRECEDED\n"
    1883             : "        WHITESPACE\n"
    1884             : "        IDENTIFIER \"F\"\n"
    1885             : "        WHITESPACE\n"
    1886             : "        ADD\n"
    1887             : "        WHITESPACE\n"
    1888             : "        IDENTIFIER \"G\"\n"
    1889             : "        WHITESPACE\n"
    1890             : "        IDENTIFIER \"H\"\n"
    1891             : "        OPEN_CURLYBRACKET B:false\n"
    1892             : "          COMPONENT_VALUE\n"
    1893             : "            IDENTIFIER \"font-style\"\n"
    1894             : "            COLON\n"
    1895             : "            WHITESPACE\n"
    1896             : "            IDENTIFIER \"italic\"\n"
    1897             : 
    1898             :             );
    1899           1 :     }
    1900             : 
    1901             :     // no error left over
    1902           1 :     VERIFY_ERRORS("");
    1903           1 : }
    1904             : 
    1905           1 : CATCH_TEST_CASE("Is variable set", "[parser] [variable] [invalid]")
    1906             : {
    1907             :     // simple test with a value + value (SASS compatible)
    1908             :     {
    1909           1 :         std::stringstream ss;
    1910           1 :         ss << "$a: 33px;";
    1911           3 :         csspp::position pos("test.css");
    1912           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1913             : 
    1914           2 :         csspp::parser p(l);
    1915             : 
    1916           1 :         csspp::node::pointer_t n(p.stylesheet());
    1917             : 
    1918             :         // no error happened
    1919           1 :         VERIFY_ERRORS("");
    1920             : 
    1921             : //std::cerr << "Result is: [" << *n << "]\n";
    1922             : 
    1923           1 :         std::stringstream out;
    1924           1 :         out << *n;
    1925           1 :         VERIFY_TREES(out.str(),
    1926             : 
    1927             : "LIST\n"
    1928             : "  COMPONENT_VALUE\n"
    1929             : "    VARIABLE \"a\"\n"
    1930             : "    COLON\n"
    1931             : "    WHITESPACE\n"
    1932             : "    INTEGER \"px\" I:33\n"
    1933             : 
    1934             :             );
    1935             : 
    1936           1 :         csspp::node::pointer_t var(n->get_child(0));
    1937           1 :         CATCH_REQUIRE(csspp::parser::is_variable_set(var, false));
    1938           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_variable_set(var, true));
    1939           1 :     }
    1940             : 
    1941             :     // case were we actually use a variable to define a selector
    1942             :     // this is not a variable set
    1943             :     {
    1944           1 :         std::stringstream ss;
    1945           1 :         ss << "$a .cute { color: red; }";
    1946           3 :         csspp::position pos("test.css");
    1947           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1948             : 
    1949           2 :         csspp::parser p(l);
    1950             : 
    1951           1 :         csspp::node::pointer_t n(p.stylesheet());
    1952             : 
    1953             :         // no error happened
    1954           1 :         VERIFY_ERRORS("");
    1955             : 
    1956             : //std::cerr << "Result is: [" << *n << "]\n";
    1957             : 
    1958           1 :         std::stringstream out;
    1959           1 :         out << *n;
    1960           1 :         VERIFY_TREES(out.str(),
    1961             : 
    1962             : "LIST\n"
    1963             : "  COMPONENT_VALUE\n"
    1964             : "    VARIABLE \"a\"\n"
    1965             : "    WHITESPACE\n"
    1966             : "    PERIOD\n"
    1967             : "    IDENTIFIER \"cute\"\n"
    1968             : "    OPEN_CURLYBRACKET B:false\n"
    1969             : "      COMPONENT_VALUE\n"
    1970             : "        IDENTIFIER \"color\"\n"
    1971             : "        COLON\n"
    1972             : "        WHITESPACE\n"
    1973             : "        IDENTIFIER \"red\"\n"
    1974             : 
    1975             :             );
    1976             : 
    1977           1 :         csspp::node::pointer_t var(n->get_child(0));
    1978           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_variable_set(var, false));
    1979           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_variable_set(var, true));
    1980           1 :     }
    1981             : 
    1982             :     // test with a variable block
    1983             :     {
    1984           1 :         std::stringstream ss;
    1985           1 :         ss << "$a: { color: red; };";
    1986           3 :         csspp::position pos("test.css");
    1987           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1988             : 
    1989           2 :         csspp::parser p(l);
    1990             : 
    1991           1 :         csspp::node::pointer_t n(p.stylesheet());
    1992             : 
    1993             :         // no error happened
    1994           1 :         VERIFY_ERRORS("");
    1995             : 
    1996             : //std::cerr << "Result is: [" << *n << "]\n";
    1997             : 
    1998           1 :         std::stringstream out;
    1999           1 :         out << *n;
    2000           1 :         VERIFY_TREES(out.str(),
    2001             : 
    2002             : "LIST\n"
    2003             : "  COMPONENT_VALUE\n"
    2004             : "    VARIABLE \"a\"\n"
    2005             : "    COLON\n"
    2006             : "    OPEN_CURLYBRACKET B:false\n"
    2007             : "      COMPONENT_VALUE\n"
    2008             : "        IDENTIFIER \"color\"\n"
    2009             : "        COLON\n"
    2010             : "        WHITESPACE\n"
    2011             : "        IDENTIFIER \"red\"\n"
    2012             : 
    2013             :             );
    2014             : 
    2015           1 :         csspp::node::pointer_t var(n->get_child(0));
    2016           1 :         CATCH_REQUIRE(csspp::parser::is_variable_set(var, false));
    2017           1 :         CATCH_REQUIRE(csspp::parser::is_variable_set(var, true));
    2018           1 :     }
    2019             : 
    2020             :     // test with the missing ';'
    2021             :     {
    2022           1 :         std::stringstream ss;
    2023           1 :         ss << "$a: { color: red; }";
    2024           3 :         csspp::position pos("test.css");
    2025           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2026             : 
    2027           2 :         csspp::parser p(l);
    2028             : 
    2029           1 :         csspp::node::pointer_t n(p.stylesheet());
    2030             : 
    2031             :         // the ';' at the end is missing
    2032           1 :         VERIFY_ERRORS("test.css(1): error: Variable set to a block and a nested property block must end with a semicolon (;) after said block.\n");
    2033           1 :     }
    2034             : 
    2035             :     // simple test with a value + value (SASS compatible)
    2036             :     {
    2037           1 :         std::stringstream ss;
    2038           1 :         ss << "$a($arg1): 33px;";
    2039           3 :         csspp::position pos("test.css");
    2040           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2041             : 
    2042           2 :         csspp::parser p(l);
    2043             : 
    2044           1 :         csspp::node::pointer_t n(p.stylesheet());
    2045             : 
    2046             :         // no error happened
    2047           1 :         VERIFY_ERRORS("");
    2048             : 
    2049             : //std::cerr << "Result is: [" << *n << "]\n";
    2050             : 
    2051           1 :         std::stringstream out;
    2052           1 :         out << *n;
    2053           1 :         VERIFY_TREES(out.str(),
    2054             : 
    2055             : "LIST\n"
    2056             : "  COMPONENT_VALUE\n"
    2057             : "    VARIABLE_FUNCTION \"a\"\n"
    2058             : "      VARIABLE \"arg1\"\n"
    2059             : "    COLON\n"
    2060             : "    WHITESPACE\n"
    2061             : "    INTEGER \"px\" I:33\n"
    2062             : 
    2063             :             );
    2064             : 
    2065           1 :         csspp::node::pointer_t var(n->get_child(0));
    2066           1 :         CATCH_REQUIRE(csspp::parser::is_variable_set(var, false));
    2067           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_variable_set(var, true));
    2068           1 :     }
    2069             : 
    2070             :     // case were we actually use a variable to define a selector
    2071             :     // this is not a variable set
    2072             :     {
    2073           1 :         std::stringstream ss;
    2074           1 :         ss << "$a(33) .cute { color: red; }";
    2075           3 :         csspp::position pos("test.css");
    2076           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2077             : 
    2078           2 :         csspp::parser p(l);
    2079             : 
    2080           1 :         csspp::node::pointer_t n(p.stylesheet());
    2081             : 
    2082             :         // no error happened
    2083           1 :         VERIFY_ERRORS("");
    2084             : 
    2085             : //std::cerr << "Result is: [" << *n << "]\n";
    2086             : 
    2087           1 :         std::stringstream out;
    2088           1 :         out << *n;
    2089           1 :         VERIFY_TREES(out.str(),
    2090             : 
    2091             : "LIST\n"
    2092             : "  COMPONENT_VALUE\n"
    2093             : "    VARIABLE_FUNCTION \"a\"\n"
    2094             : "      INTEGER \"\" I:33\n"
    2095             : "    WHITESPACE\n"
    2096             : "    PERIOD\n"
    2097             : "    IDENTIFIER \"cute\"\n"
    2098             : "    OPEN_CURLYBRACKET B:false\n"
    2099             : "      COMPONENT_VALUE\n"
    2100             : "        IDENTIFIER \"color\"\n"
    2101             : "        COLON\n"
    2102             : "        WHITESPACE\n"
    2103             : "        IDENTIFIER \"red\"\n"
    2104             : 
    2105             :             );
    2106             : 
    2107           1 :         csspp::node::pointer_t var(n->get_child(0));
    2108           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_variable_set(var, false));
    2109           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_variable_set(var, true));
    2110           1 :     }
    2111             : 
    2112             :     // test with a variable block
    2113             :     {
    2114           1 :         std::stringstream ss;
    2115           1 :         ss << "$a($arg1): { color: red; };";
    2116           3 :         csspp::position pos("test.css");
    2117           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2118             : 
    2119           2 :         csspp::parser p(l);
    2120             : 
    2121           1 :         csspp::node::pointer_t n(p.stylesheet());
    2122             : 
    2123             :         // no error happened
    2124           1 :         VERIFY_ERRORS("");
    2125             : 
    2126             : //std::cerr << "Result is: [" << *n << "]\n";
    2127             : 
    2128           1 :         std::stringstream out;
    2129           1 :         out << *n;
    2130           1 :         VERIFY_TREES(out.str(),
    2131             : 
    2132             : "LIST\n"
    2133             : "  COMPONENT_VALUE\n"
    2134             : "    VARIABLE_FUNCTION \"a\"\n"
    2135             : "      VARIABLE \"arg1\"\n"
    2136             : "    COLON\n"
    2137             : "    OPEN_CURLYBRACKET B:false\n"
    2138             : "      COMPONENT_VALUE\n"
    2139             : "        IDENTIFIER \"color\"\n"
    2140             : "        COLON\n"
    2141             : "        WHITESPACE\n"
    2142             : "        IDENTIFIER \"red\"\n"
    2143             : 
    2144             :             );
    2145             : 
    2146           1 :         csspp::node::pointer_t var(n->get_child(0));
    2147           1 :         CATCH_REQUIRE(csspp::parser::is_variable_set(var, false));
    2148           1 :         CATCH_REQUIRE(csspp::parser::is_variable_set(var, true));
    2149           1 :     }
    2150             : 
    2151             :     // test with the missing ';'
    2152             :     {
    2153           1 :         std::stringstream ss;
    2154           1 :         ss << "$a($arg1): { color: red; }";
    2155           3 :         csspp::position pos("test.css");
    2156           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2157             : 
    2158           2 :         csspp::parser p(l);
    2159             : 
    2160           1 :         csspp::node::pointer_t n(p.stylesheet());
    2161             : 
    2162             :         // the ';' at the end is missing
    2163           1 :         VERIFY_ERRORS("test.css(1): error: Variable set to a block and a nested property block must end with a semicolon (;) after said block.\n");
    2164           1 :     }
    2165             : 
    2166             :     // no error left over
    2167           1 :     VERIFY_ERRORS("");
    2168           1 : }
    2169             : 
    2170           1 : CATCH_TEST_CASE("Is nested declaration", "[parser] [variable] [invalid]")
    2171             : {
    2172             :     // which a field name with a simple nested declaration
    2173             :     {
    2174           1 :         std::stringstream ss;
    2175           1 :         ss << "width : { color : red } ;";
    2176           3 :         csspp::position pos("test.css");
    2177           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2178             : 
    2179           2 :         csspp::parser p(l);
    2180             : 
    2181           1 :         csspp::node::pointer_t n(p.stylesheet());
    2182             : 
    2183             :         // no error happened
    2184           1 :         VERIFY_ERRORS("");
    2185             : 
    2186             : //std::cerr << "Result is: [" << *n << "]\n";
    2187             : 
    2188           1 :         std::stringstream out;
    2189           1 :         out << *n;
    2190           1 :         VERIFY_TREES(out.str(),
    2191             : 
    2192             : "LIST\n"
    2193             : "  COMPONENT_VALUE\n"
    2194             : "    IDENTIFIER \"width\"\n"
    2195             : "    WHITESPACE\n"
    2196             : "    COLON\n"
    2197             : "    OPEN_CURLYBRACKET B:false\n"
    2198             : "      COMPONENT_VALUE\n"
    2199             : "        IDENTIFIER \"color\"\n"
    2200             : "        WHITESPACE\n"
    2201             : "        COLON\n"
    2202             : "        WHITESPACE\n"
    2203             : "        IDENTIFIER \"red\"\n"
    2204             : 
    2205             :             );
    2206             : 
    2207           1 :         csspp::node::pointer_t var(n->get_child(0));
    2208           1 :         CATCH_REQUIRE(csspp::parser::is_nested_declaration(var));
    2209           1 :     }
    2210             : 
    2211             :     // which a field name with a simple nested declaration
    2212             :     {
    2213           1 :         std::stringstream ss;
    2214           1 :         ss << "width :nth-child(3n+2) span{ color : red } ";
    2215           3 :         csspp::position pos("test.css");
    2216           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2217             : 
    2218           2 :         csspp::parser p(l);
    2219             : 
    2220           1 :         csspp::node::pointer_t n(p.stylesheet());
    2221             : 
    2222             :         // no error happened
    2223           1 :         VERIFY_ERRORS("");
    2224             : 
    2225             : //std::cerr << "Result is: [" << *n << "]\n";
    2226             : 
    2227           1 :         std::stringstream out;
    2228           1 :         out << *n;
    2229           1 :         VERIFY_TREES(out.str(),
    2230             : 
    2231             : "LIST\n"
    2232             : "  COMPONENT_VALUE\n"
    2233             : "    IDENTIFIER \"width\"\n"
    2234             : "    WHITESPACE\n"
    2235             : "    COLON\n"
    2236             : "    FUNCTION \"nth-child\"\n"
    2237             : "      INTEGER \"n\" I:3\n"
    2238             : "      INTEGER \"\" I:2\n"
    2239             : "    WHITESPACE\n"
    2240             : "    IDENTIFIER \"span\"\n"
    2241             : "    OPEN_CURLYBRACKET B:false\n"
    2242             : "      COMPONENT_VALUE\n"
    2243             : "        IDENTIFIER \"color\"\n"
    2244             : "        WHITESPACE\n"
    2245             : "        COLON\n"
    2246             : "        WHITESPACE\n"
    2247             : "        IDENTIFIER \"red\"\n"
    2248             : 
    2249             :             );
    2250             : 
    2251           1 :         csspp::node::pointer_t var(n->get_child(0));
    2252           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(var));
    2253           1 :     }
    2254             : 
    2255             :     // which a field name with a simple nested declaration
    2256             :     {
    2257           1 :         std::stringstream ss;
    2258           1 :         ss << "width :not(.color) { color : red } ";
    2259           3 :         csspp::position pos("test.css");
    2260           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2261             : 
    2262           2 :         csspp::parser p(l);
    2263             : 
    2264           1 :         csspp::node::pointer_t n(p.stylesheet());
    2265             : 
    2266             :         // no error happened
    2267           1 :         VERIFY_ERRORS("");
    2268             : 
    2269             : //std::cerr << "Result is: [" << *n << "]\n";
    2270             : 
    2271           1 :         std::stringstream out;
    2272           1 :         out << *n;
    2273           1 :         VERIFY_TREES(out.str(),
    2274             : 
    2275             : "LIST\n"
    2276             : "  COMPONENT_VALUE\n"
    2277             : "    IDENTIFIER \"width\"\n"
    2278             : "    WHITESPACE\n"
    2279             : "    COLON\n"
    2280             : "    FUNCTION \"not\"\n"
    2281             : "      PERIOD\n"
    2282             : "      IDENTIFIER \"color\"\n"
    2283             : "    OPEN_CURLYBRACKET B:false\n"
    2284             : "      COMPONENT_VALUE\n"
    2285             : "        IDENTIFIER \"color\"\n"
    2286             : "        WHITESPACE\n"
    2287             : "        COLON\n"
    2288             : "        WHITESPACE\n"
    2289             : "        IDENTIFIER \"red\"\n"
    2290             : 
    2291             :             );
    2292             : 
    2293           1 :         csspp::node::pointer_t var(n->get_child(0));
    2294           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(var));
    2295           1 :     }
    2296             : 
    2297             :     // in this case it is clear that none are declarations
    2298             :     // (although the span:not() is not valid since it is
    2299             :     // missing the {}-block at the end)
    2300             :     {
    2301           1 :         std::stringstream ss;
    2302           1 :         ss << "div { span :not(.wrap); p { color : red } } ";
    2303           3 :         csspp::position pos("test.css");
    2304           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2305             : 
    2306           2 :         csspp::parser p(l);
    2307             : 
    2308           1 :         csspp::node::pointer_t n(p.stylesheet());
    2309             : 
    2310             :         // no error happened
    2311           1 :         VERIFY_ERRORS("");
    2312             : 
    2313             : //std::cerr << "Result is: [" << *n << "]\n";
    2314             : 
    2315           1 :         std::stringstream out;
    2316           1 :         out << *n;
    2317           1 :         VERIFY_TREES(out.str(),
    2318             : 
    2319             : "LIST\n"
    2320             : "  COMPONENT_VALUE\n"
    2321             : "    IDENTIFIER \"div\"\n"
    2322             : "    OPEN_CURLYBRACKET B:false\n"
    2323             : "      LIST\n"
    2324             : "        COMPONENT_VALUE\n"
    2325             : "          IDENTIFIER \"span\"\n"
    2326             : "          WHITESPACE\n"
    2327             : "          COLON\n"
    2328             : "          FUNCTION \"not\"\n"
    2329             : "            PERIOD\n"
    2330             : "            IDENTIFIER \"wrap\"\n"
    2331             : "        COMPONENT_VALUE\n"
    2332             : "          IDENTIFIER \"p\"\n"
    2333             : "          OPEN_CURLYBRACKET B:false\n"
    2334             : "            COMPONENT_VALUE\n"
    2335             : "              IDENTIFIER \"color\"\n"
    2336             : "              WHITESPACE\n"
    2337             : "              COLON\n"
    2338             : "              WHITESPACE\n"
    2339             : "              IDENTIFIER \"red\"\n"
    2340             : 
    2341             :             );
    2342             : 
    2343             :         // check the first COMPONENT_VALUE
    2344           1 :         csspp::node::pointer_t div(n->get_child(0));
    2345           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(div));
    2346             : 
    2347             :         // check the second COMPONENT_VALUE
    2348           4 :         csspp::node::pointer_t span(n->get_child(0)->get_child(1)->get_child(0)->get_child(0));
    2349           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(span));
    2350             : 
    2351             :         // check the third COMPONENT_VALUE
    2352           4 :         csspp::node::pointer_t p_tag(n->get_child(0)->get_child(1)->get_child(0)->get_child(1));
    2353           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(p_tag));
    2354           1 :     }
    2355             : 
    2356             :     // in this case it is clear that none are declarations
    2357             :     // (although the span:not() is not valid since it is
    2358             :     // missing the {}-block at the end)
    2359             :     {
    2360           1 :         std::stringstream ss;
    2361           1 :         ss << "div { span : { color : red }; } ";
    2362           3 :         csspp::position pos("test.css");
    2363           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2364             : 
    2365           2 :         csspp::parser p(l);
    2366             : 
    2367           1 :         csspp::node::pointer_t n(p.stylesheet());
    2368             : 
    2369             :         // no error happened
    2370           1 :         VERIFY_ERRORS("");
    2371             : 
    2372             : //std::cerr << "Result is: [" << *n << "]\n";
    2373             : 
    2374           1 :         std::stringstream out;
    2375           1 :         out << *n;
    2376           1 :         VERIFY_TREES(out.str(),
    2377             : 
    2378             : "LIST\n"
    2379             : "  COMPONENT_VALUE\n"
    2380             : "    IDENTIFIER \"div\"\n"
    2381             : "    OPEN_CURLYBRACKET B:false\n"
    2382             : "      COMPONENT_VALUE\n"
    2383             : "        IDENTIFIER \"span\"\n"
    2384             : "        WHITESPACE\n"
    2385             : "        COLON\n"
    2386             : "        OPEN_CURLYBRACKET B:false\n"
    2387             : "          COMPONENT_VALUE\n"
    2388             : "            IDENTIFIER \"color\"\n"
    2389             : "            WHITESPACE\n"
    2390             : "            COLON\n"
    2391             : "            WHITESPACE\n"
    2392             : "            IDENTIFIER \"red\"\n"
    2393             : 
    2394             :             );
    2395             : 
    2396             :         // check the first COMPONENT_VALUE
    2397           1 :         csspp::node::pointer_t div(n->get_child(0));
    2398           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(div));
    2399             : 
    2400             :         // check the second COMPONENT_VALUE
    2401           3 :         csspp::node::pointer_t span(n->get_child(0)->get_child(1)->get_child(0));
    2402           1 :         CATCH_REQUIRE(csspp::parser::is_nested_declaration(span));
    2403             : 
    2404             :         // check the third COMPONENT_VALUE
    2405           5 :         csspp::node::pointer_t p_tag(n->get_child(0)->get_child(1)->get_child(0)->get_child(3)->get_child(0));
    2406           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(p_tag));
    2407           1 :     }
    2408             : 
    2409             :     // ':' always marks a selector
    2410             :     {
    2411           1 :         std::stringstream ss;
    2412           1 :         ss << "div { span :section : { color : red }; } ";
    2413           3 :         csspp::position pos("test.css");
    2414           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2415             : 
    2416           2 :         csspp::parser p(l);
    2417             : 
    2418           1 :         csspp::node::pointer_t n(p.stylesheet());
    2419             : 
    2420             :         // no error happened
    2421           1 :         VERIFY_ERRORS("");
    2422             : 
    2423             : //std::cerr << "Result is: [" << *n << "]\n";
    2424             : 
    2425           1 :         std::stringstream out;
    2426           1 :         out << *n;
    2427           1 :         VERIFY_TREES(out.str(),
    2428             : 
    2429             : "LIST\n"
    2430             : "  COMPONENT_VALUE\n"
    2431             : "    IDENTIFIER \"div\"\n"
    2432             : "    OPEN_CURLYBRACKET B:false\n"
    2433             : "      COMPONENT_VALUE\n"
    2434             : "        IDENTIFIER \"span\"\n"
    2435             : "        WHITESPACE\n"
    2436             : "        COLON\n"
    2437             : "        IDENTIFIER \"section\"\n"
    2438             : "        WHITESPACE\n"
    2439             : "        COLON\n"
    2440             : "        OPEN_CURLYBRACKET B:false\n"
    2441             : "          COMPONENT_VALUE\n"
    2442             : "            IDENTIFIER \"color\"\n"
    2443             : "            WHITESPACE\n"
    2444             : "            COLON\n"
    2445             : "            WHITESPACE\n"
    2446             : "            IDENTIFIER \"red\"\n"
    2447             : "      LIST\n"
    2448             : 
    2449             :             );
    2450             : 
    2451             :         // check the first COMPONENT_VALUE
    2452           1 :         csspp::node::pointer_t div(n->get_child(0));
    2453           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(div));
    2454             : 
    2455             :         // check the second COMPONENT_VALUE
    2456           3 :         csspp::node::pointer_t span(n->get_child(0)->get_child(1)->get_child(0));
    2457           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(span));
    2458             : 
    2459             :         // check the third COMPONENT_VALUE
    2460           5 :         csspp::node::pointer_t p_tag(n->get_child(0)->get_child(1)->get_child(0)->get_child(6)->get_child(0));
    2461           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(p_tag));
    2462           1 :     }
    2463             : 
    2464             :     // '%<id>' always marks a selector
    2465             :     {
    2466           1 :         std::stringstream ss;
    2467           1 :         ss << "div { span :section%july { color : red }; } ";
    2468           3 :         csspp::position pos("test.css");
    2469           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2470             : 
    2471           2 :         csspp::parser p(l);
    2472             : 
    2473           1 :         csspp::node::pointer_t n(p.stylesheet());
    2474             : 
    2475             :         // no error happened
    2476           1 :         VERIFY_ERRORS("");
    2477             : 
    2478             : //std::cerr << "Result is: [" << *n << "]\n";
    2479             : 
    2480           1 :         std::stringstream out;
    2481           1 :         out << *n;
    2482           1 :         VERIFY_TREES(out.str(),
    2483             : 
    2484             : "LIST\n"
    2485             : "  COMPONENT_VALUE\n"
    2486             : "    IDENTIFIER \"div\"\n"
    2487             : "    OPEN_CURLYBRACKET B:false\n"
    2488             : "      COMPONENT_VALUE\n"
    2489             : "        IDENTIFIER \"span\"\n"
    2490             : "        WHITESPACE\n"
    2491             : "        COLON\n"
    2492             : "        IDENTIFIER \"section\"\n"
    2493             : "        PLACEHOLDER \"july\"\n"
    2494             : "        OPEN_CURLYBRACKET B:false\n"
    2495             : "          COMPONENT_VALUE\n"
    2496             : "            IDENTIFIER \"color\"\n"
    2497             : "            WHITESPACE\n"
    2498             : "            COLON\n"
    2499             : "            WHITESPACE\n"
    2500             : "            IDENTIFIER \"red\"\n"
    2501             : "      LIST\n"
    2502             : 
    2503             :             );
    2504             : 
    2505             :         // check the first COMPONENT_VALUE
    2506           1 :         csspp::node::pointer_t div(n->get_child(0));
    2507           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(div));
    2508             : 
    2509             :         // check the second COMPONENT_VALUE
    2510           3 :         csspp::node::pointer_t span(n->get_child(0)->get_child(1)->get_child(0));
    2511           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(span));
    2512             : 
    2513             :         // check the third COMPONENT_VALUE
    2514           5 :         csspp::node::pointer_t p_tag(n->get_child(0)->get_child(1)->get_child(0)->get_child(5)->get_child(0));
    2515           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(p_tag));
    2516           1 :     }
    2517             : 
    2518             :     // 'E ~ E' always marks a selector
    2519             :     {
    2520           1 :         std::stringstream ss;
    2521           1 :         ss << "div { span :section ~ july { color : red }; } ";
    2522           3 :         csspp::position pos("test.css");
    2523           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2524             : 
    2525           2 :         csspp::parser p(l);
    2526             : 
    2527           1 :         csspp::node::pointer_t n(p.stylesheet());
    2528             : 
    2529             :         // no error happened
    2530           1 :         VERIFY_ERRORS("");
    2531             : 
    2532             : //std::cerr << "Result is: [" << *n << "]\n";
    2533             : 
    2534           1 :         std::stringstream out;
    2535           1 :         out << *n;
    2536           1 :         VERIFY_TREES(out.str(),
    2537             : 
    2538             : "LIST\n"
    2539             : "  COMPONENT_VALUE\n"
    2540             : "    IDENTIFIER \"div\"\n"
    2541             : "    OPEN_CURLYBRACKET B:false\n"
    2542             : "      COMPONENT_VALUE\n"
    2543             : "        IDENTIFIER \"span\"\n"
    2544             : "        WHITESPACE\n"
    2545             : "        COLON\n"
    2546             : "        IDENTIFIER \"section\"\n"
    2547             : "        WHITESPACE\n"
    2548             : "        PRECEDED\n"
    2549             : "        WHITESPACE\n"
    2550             : "        IDENTIFIER \"july\"\n"
    2551             : "        OPEN_CURLYBRACKET B:false\n"
    2552             : "          COMPONENT_VALUE\n"
    2553             : "            IDENTIFIER \"color\"\n"
    2554             : "            WHITESPACE\n"
    2555             : "            COLON\n"
    2556             : "            WHITESPACE\n"
    2557             : "            IDENTIFIER \"red\"\n"
    2558             : "      LIST\n"
    2559             : 
    2560             :             );
    2561             : 
    2562             :         // check the first COMPONENT_VALUE
    2563           1 :         csspp::node::pointer_t div(n->get_child(0));
    2564           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(div));
    2565             : 
    2566             :         // check the second COMPONENT_VALUE
    2567           3 :         csspp::node::pointer_t span(n->get_child(0)->get_child(1)->get_child(0));
    2568           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(span));
    2569             : 
    2570             :         // check the third COMPONENT_VALUE
    2571           5 :         csspp::node::pointer_t p_tag(n->get_child(0)->get_child(1)->get_child(0)->get_child(8)->get_child(0));
    2572           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(p_tag));
    2573           1 :     }
    2574             : 
    2575             :     // 'E & E' always marks a selector
    2576             :     {
    2577           1 :         std::stringstream ss;
    2578           1 :         ss << "div { span :section & july { color : red }; } ";
    2579           3 :         csspp::position pos("test.css");
    2580           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2581             : 
    2582           2 :         csspp::parser p(l);
    2583             : 
    2584           1 :         csspp::node::pointer_t n(p.stylesheet());
    2585             : 
    2586             :         // no error happened
    2587           1 :         VERIFY_ERRORS("");
    2588             : 
    2589             : //std::cerr << "Result is: [" << *n << "]\n";
    2590             : 
    2591           1 :         std::stringstream out;
    2592           1 :         out << *n;
    2593           1 :         VERIFY_TREES(out.str(),
    2594             : 
    2595             : "LIST\n"
    2596             : "  COMPONENT_VALUE\n"
    2597             : "    IDENTIFIER \"div\"\n"
    2598             : "    OPEN_CURLYBRACKET B:false\n"
    2599             : "      COMPONENT_VALUE\n"
    2600             : "        IDENTIFIER \"span\"\n"
    2601             : "        WHITESPACE\n"
    2602             : "        COLON\n"
    2603             : "        IDENTIFIER \"section\"\n"
    2604             : "        WHITESPACE\n"
    2605             : "        REFERENCE\n"
    2606             : "        WHITESPACE\n"
    2607             : "        IDENTIFIER \"july\"\n"
    2608             : "        OPEN_CURLYBRACKET B:false\n"
    2609             : "          COMPONENT_VALUE\n"
    2610             : "            IDENTIFIER \"color\"\n"
    2611             : "            WHITESPACE\n"
    2612             : "            COLON\n"
    2613             : "            WHITESPACE\n"
    2614             : "            IDENTIFIER \"red\"\n"
    2615             : "      LIST\n"
    2616             : 
    2617             :             );
    2618             : 
    2619             :         // check the first COMPONENT_VALUE
    2620           1 :         csspp::node::pointer_t div(n->get_child(0));
    2621           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(div));
    2622             : 
    2623             :         // check the second COMPONENT_VALUE
    2624           3 :         csspp::node::pointer_t span(n->get_child(0)->get_child(1)->get_child(0));
    2625           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(span));
    2626             : 
    2627             :         // check the third COMPONENT_VALUE
    2628           5 :         csspp::node::pointer_t p_tag(n->get_child(0)->get_child(1)->get_child(0)->get_child(8)->get_child(0));
    2629           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(p_tag));
    2630           1 :     }
    2631             : 
    2632             :     // 'E|E' always marks a selector
    2633             :     {
    2634           1 :         std::stringstream ss;
    2635           1 :         ss << "div { span :section *|july { color : red }; } ";
    2636           3 :         csspp::position pos("test.css");
    2637           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2638             : 
    2639           2 :         csspp::parser p(l);
    2640             : 
    2641           1 :         csspp::node::pointer_t n(p.stylesheet());
    2642             : 
    2643             :         // no error happened
    2644           1 :         VERIFY_ERRORS("");
    2645             : 
    2646             : //std::cerr << "Result is: [" << *n << "]\n";
    2647             : 
    2648           1 :         std::stringstream out;
    2649           1 :         out << *n;
    2650           1 :         VERIFY_TREES(out.str(),
    2651             : 
    2652             : "LIST\n"
    2653             : "  COMPONENT_VALUE\n"
    2654             : "    IDENTIFIER \"div\"\n"
    2655             : "    OPEN_CURLYBRACKET B:false\n"
    2656             : "      COMPONENT_VALUE\n"
    2657             : "        IDENTIFIER \"span\"\n"
    2658             : "        WHITESPACE\n"
    2659             : "        COLON\n"
    2660             : "        IDENTIFIER \"section\"\n"
    2661             : "        WHITESPACE\n"
    2662             : "        MULTIPLY\n"
    2663             : "        SCOPE\n"
    2664             : "        IDENTIFIER \"july\"\n"
    2665             : "        OPEN_CURLYBRACKET B:false\n"
    2666             : "          COMPONENT_VALUE\n"
    2667             : "            IDENTIFIER \"color\"\n"
    2668             : "            WHITESPACE\n"
    2669             : "            COLON\n"
    2670             : "            WHITESPACE\n"
    2671             : "            IDENTIFIER \"red\"\n"
    2672             : "      LIST\n"
    2673             : 
    2674             :             );
    2675             : 
    2676             :         // check the first COMPONENT_VALUE
    2677           1 :         csspp::node::pointer_t div(n->get_child(0));
    2678           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(div));
    2679             : 
    2680             :         // check the second COMPONENT_VALUE
    2681           3 :         csspp::node::pointer_t span(n->get_child(0)->get_child(1)->get_child(0));
    2682           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(span));
    2683             : 
    2684             :         // check the third COMPONENT_VALUE
    2685           5 :         csspp::node::pointer_t p_tag(n->get_child(0)->get_child(1)->get_child(0)->get_child(8)->get_child(0));
    2686           1 :         CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(p_tag));
    2687           1 :     }
    2688             : 
    2689             :     // a nested block must end with a ';'
    2690             :     {
    2691           1 :         std::stringstream ss;
    2692           1 :         ss << "width : { color : red }";
    2693           3 :         csspp::position pos("test.css");
    2694           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2695             : 
    2696           2 :         csspp::parser p(l);
    2697             : 
    2698           1 :         csspp::node::pointer_t n(p.stylesheet());
    2699             : 
    2700             :         // no error happened
    2701           1 :         VERIFY_ERRORS("test.css(1): error: Variable set to a block and a nested property block must end with a semicolon (;) after said block.\n");
    2702           1 :     }
    2703             : 
    2704             :     // test special cases which woudl be really hard to get from the
    2705             :     // normal parser/lexer combo
    2706          33 :     for(int i(0); i < (1 << 5); ++i)
    2707             :     {
    2708          96 :         csspp::position pos("test.css");
    2709          32 :         csspp::node::pointer_t root(new csspp::node(csspp::node_type_t::LIST, pos));
    2710             : 
    2711             :         // name WS ':' WS '{'
    2712          32 :         if((i & (1 << 0)) != 0)
    2713             :         {
    2714          16 :             csspp::node::pointer_t name(new csspp::node(csspp::node_type_t::IDENTIFIER, pos));
    2715          16 :             name->set_string("field-name");
    2716          16 :             root->add_child(name);
    2717          16 :         }
    2718             : 
    2719          32 :         if((i & (1 << 1)) != 0)
    2720             :         {
    2721          16 :             csspp::node::pointer_t whitespace1(new csspp::node(csspp::node_type_t::WHITESPACE, pos));
    2722          16 :             root->add_child(whitespace1);
    2723          16 :         }
    2724             : 
    2725          32 :         if((i & (1 << 2)) != 0)
    2726             :         {
    2727          16 :             csspp::node::pointer_t colon(new csspp::node(csspp::node_type_t::COLON, pos));
    2728          16 :             root->add_child(colon);
    2729          16 :         }
    2730             : 
    2731          32 :         if((i & (1 << 3)) != 0)
    2732             :         {
    2733          16 :             csspp::node::pointer_t whitespace2(new csspp::node(csspp::node_type_t::WHITESPACE, pos));
    2734          16 :             root->add_child(whitespace2);
    2735          16 :         }
    2736             : 
    2737          32 :         if((i & (1 << 4)) != 0)
    2738             :         {
    2739          16 :             csspp::node::pointer_t curlybracket(new csspp::node(csspp::node_type_t::OPEN_CURLYBRACKET, pos));
    2740          16 :             root->add_child(curlybracket);
    2741          16 :         }
    2742             : 
    2743             :         // this one is "valid"
    2744          32 :         switch(i)
    2745             :         {
    2746           4 :         case 0x1F: // all with and without spaces are valid
    2747             :         case 0x1D:
    2748             :         case 0x17:
    2749             :         case 0x15:
    2750           4 :             CATCH_REQUIRE(csspp::parser::is_nested_declaration(root));
    2751           4 :             break;
    2752             : 
    2753          28 :         default:
    2754          28 :             CATCH_REQUIRE_FALSE(csspp::parser::is_nested_declaration(root));
    2755          28 :             break;
    2756             : 
    2757             :         }
    2758          32 :     }
    2759             : 
    2760             :     // no error left over
    2761           1 :     VERIFY_ERRORS("");
    2762           1 : }
    2763             : 
    2764           1 : CATCH_TEST_CASE("Rules defined inside an @-Keyword", "[parser] [variable] [invalid]")
    2765             : {
    2766             :     // which a field name with a simple nested declaration
    2767             :     {
    2768           1 :         std::stringstream ss;
    2769             :         ss << "@document url(http://www.example.com/), regexp(\"https://.*\")\n"
    2770             :            << "{\n"
    2771             :            << "  body { width: 8.5in; height: 9in; }\n"
    2772             :            << "  div { border: 0.25in solid lightgray }\n"
    2773             :            << "}\n"
    2774           1 :            << "#edge { border: 1px solid black }\n";
    2775           3 :         csspp::position pos("test.css");
    2776           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2777             : 
    2778           2 :         csspp::parser p(l);
    2779             : 
    2780           1 :         csspp::node::pointer_t n(p.stylesheet());
    2781             : 
    2782             :         // no error happened
    2783           1 :         VERIFY_ERRORS("");
    2784             : 
    2785             : //std::cerr << "Result is: [" << *n << "]\n";
    2786             : 
    2787           1 :         std::stringstream out;
    2788           1 :         out << *n;
    2789           1 :         VERIFY_TREES(out.str(),
    2790             : 
    2791             : "LIST\n"
    2792             : "  AT_KEYWORD \"document\" I:0\n"
    2793             : "    URL \"http://www.example.com/\"\n"
    2794             : "    COMMA\n"
    2795             : "    WHITESPACE\n"
    2796             : "    FUNCTION \"regexp\"\n"
    2797             : "      STRING \"https://.*\"\n"
    2798             : "    OPEN_CURLYBRACKET B:false\n"
    2799             : "      COMPONENT_VALUE\n"
    2800             : "        IDENTIFIER \"body\"\n"
    2801             : "        OPEN_CURLYBRACKET B:false\n"
    2802             : "          LIST\n"
    2803             : "            COMPONENT_VALUE\n"
    2804             : "              IDENTIFIER \"width\"\n"
    2805             : "              COLON\n"
    2806             : "              WHITESPACE\n"
    2807             : "              DECIMAL_NUMBER \"in\" D:8.5\n"
    2808             : "            COMPONENT_VALUE\n"
    2809             : "              IDENTIFIER \"height\"\n"
    2810             : "              COLON\n"
    2811             : "              WHITESPACE\n"
    2812             : "              INTEGER \"in\" I:9\n"
    2813             : "      COMPONENT_VALUE\n"
    2814             : "        IDENTIFIER \"div\"\n"
    2815             : "        OPEN_CURLYBRACKET B:false\n"
    2816             : "          COMPONENT_VALUE\n"
    2817             : "            IDENTIFIER \"border\"\n"
    2818             : "            COLON\n"
    2819             : "            WHITESPACE\n"
    2820             : "            DECIMAL_NUMBER \"in\" D:0.25\n"
    2821             : "            WHITESPACE\n"
    2822             : "            IDENTIFIER \"solid\"\n"
    2823             : "            WHITESPACE\n"
    2824             : "            IDENTIFIER \"lightgray\"\n"
    2825             : "  COMPONENT_VALUE\n"
    2826             : "    HASH \"edge\"\n"
    2827             : "    OPEN_CURLYBRACKET B:false\n"
    2828             : "      COMPONENT_VALUE\n"
    2829             : "        IDENTIFIER \"border\"\n"
    2830             : "        COLON\n"
    2831             : "        WHITESPACE\n"
    2832             : "        INTEGER \"px\" I:1\n"
    2833             : "        WHITESPACE\n"
    2834             : "        IDENTIFIER \"solid\"\n"
    2835             : "        WHITESPACE\n"
    2836             : "        IDENTIFIER \"black\"\n"
    2837             : 
    2838             :             );
    2839             : 
    2840           1 :     }
    2841             : 
    2842             :     // no error left over
    2843           1 :     VERIFY_ERRORS("");
    2844           1 : }
    2845             : 
    2846           1 : CATCH_TEST_CASE("Parse argify", "[parser] [stylesheet]")
    2847             : {
    2848             :     {
    2849           1 :         std::stringstream ss;
    2850             :         ss << "a,b{color:red}\n"
    2851             :            << "a, b{color:red}\n"
    2852             :            << "a,b ,c{color:red}\n"
    2853             :            << "a , b,c{color:red}\n"
    2854             :            << "a{color:red}\n"
    2855             :            << "a {color:red}\n"
    2856           1 :            << "a,b {color:red}\n"
    2857             :            ;
    2858           3 :         csspp::position pos("test.css");
    2859           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2860             : 
    2861           2 :         csspp::parser p(l);
    2862             : 
    2863           1 :         csspp::node::pointer_t n(p.stylesheet());
    2864             : 
    2865             : //std::cerr << "Result is: [" << *n << "]\n";
    2866             : 
    2867           1 :         std::stringstream out;
    2868           1 :         out << *n;
    2869           1 :         VERIFY_TREES(out.str(),
    2870             : 
    2871             : "LIST\n"
    2872             : "  COMPONENT_VALUE\n"
    2873             : "    IDENTIFIER \"a\"\n"
    2874             : "    COMMA\n"
    2875             : "    IDENTIFIER \"b\"\n"
    2876             : "    OPEN_CURLYBRACKET B:false\n"
    2877             : "      COMPONENT_VALUE\n"
    2878             : "        IDENTIFIER \"color\"\n"
    2879             : "        COLON\n"
    2880             : "        IDENTIFIER \"red\"\n"
    2881             : "  COMPONENT_VALUE\n"
    2882             : "    IDENTIFIER \"a\"\n"
    2883             : "    COMMA\n"
    2884             : "    WHITESPACE\n"
    2885             : "    IDENTIFIER \"b\"\n"
    2886             : "    OPEN_CURLYBRACKET B:false\n"
    2887             : "      COMPONENT_VALUE\n"
    2888             : "        IDENTIFIER \"color\"\n"
    2889             : "        COLON\n"
    2890             : "        IDENTIFIER \"red\"\n"
    2891             : "  COMPONENT_VALUE\n"
    2892             : "    IDENTIFIER \"a\"\n"
    2893             : "    COMMA\n"
    2894             : "    IDENTIFIER \"b\"\n"
    2895             : "    WHITESPACE\n"
    2896             : "    COMMA\n"
    2897             : "    IDENTIFIER \"c\"\n"
    2898             : "    OPEN_CURLYBRACKET B:false\n"
    2899             : "      COMPONENT_VALUE\n"
    2900             : "        IDENTIFIER \"color\"\n"
    2901             : "        COLON\n"
    2902             : "        IDENTIFIER \"red\"\n"
    2903             : "  COMPONENT_VALUE\n"
    2904             : "    IDENTIFIER \"a\"\n"
    2905             : "    WHITESPACE\n"
    2906             : "    COMMA\n"
    2907             : "    WHITESPACE\n"
    2908             : "    IDENTIFIER \"b\"\n"
    2909             : "    COMMA\n"
    2910             : "    IDENTIFIER \"c\"\n"
    2911             : "    OPEN_CURLYBRACKET B:false\n"
    2912             : "      COMPONENT_VALUE\n"
    2913             : "        IDENTIFIER \"color\"\n"
    2914             : "        COLON\n"
    2915             : "        IDENTIFIER \"red\"\n"
    2916             : "  COMPONENT_VALUE\n"
    2917             : "    IDENTIFIER \"a\"\n"
    2918             : "    OPEN_CURLYBRACKET B:false\n"
    2919             : "      COMPONENT_VALUE\n"
    2920             : "        IDENTIFIER \"color\"\n"
    2921             : "        COLON\n"
    2922             : "        IDENTIFIER \"red\"\n"
    2923             : "  COMPONENT_VALUE\n"
    2924             : "    IDENTIFIER \"a\"\n"
    2925             : "    OPEN_CURLYBRACKET B:false\n"
    2926             : "      COMPONENT_VALUE\n"
    2927             : "        IDENTIFIER \"color\"\n"
    2928             : "        COLON\n"
    2929             : "        IDENTIFIER \"red\"\n"
    2930             : "  COMPONENT_VALUE\n"
    2931             : "    IDENTIFIER \"a\"\n"
    2932             : "    COMMA\n"
    2933             : "    IDENTIFIER \"b\"\n"
    2934             : "    OPEN_CURLYBRACKET B:false\n"
    2935             : "      COMPONENT_VALUE\n"
    2936             : "        IDENTIFIER \"color\"\n"
    2937             : "        COLON\n"
    2938             : "        IDENTIFIER \"red\"\n"
    2939             : 
    2940             :             );
    2941             : 
    2942             :         // Argify the list under each COMPONENT_VALUE
    2943           1 :         CATCH_REQUIRE(n->is(csspp::node_type_t::LIST));
    2944             : 
    2945           1 :         size_t const max_children(n->size());
    2946           8 :         for(size_t idx(0); idx < max_children; ++idx)
    2947             :         {
    2948           7 :             csspp::node::pointer_t component_value(n->get_child(idx));
    2949           7 :             CATCH_REQUIRE(component_value->is(csspp::node_type_t::COMPONENT_VALUE));
    2950           7 :             CATCH_REQUIRE(csspp::parser::argify(component_value));
    2951           7 :         }
    2952             : 
    2953             : //std::cerr << "Argified result is: [" << *n << "]\n";
    2954             : 
    2955             :         // no errors so far
    2956           1 :         VERIFY_ERRORS("");
    2957             : 
    2958           1 :         std::stringstream out2;
    2959           1 :         out2 << *n;
    2960           1 :         VERIFY_TREES(out2.str(),
    2961             : 
    2962             : "LIST\n"
    2963             : "  COMPONENT_VALUE\n"
    2964             : "    ARG\n"
    2965             : "      IDENTIFIER \"a\"\n"
    2966             : "    ARG\n"
    2967             : "      IDENTIFIER \"b\"\n"
    2968             : "    OPEN_CURLYBRACKET B:false\n"
    2969             : "      COMPONENT_VALUE\n"
    2970             : "        IDENTIFIER \"color\"\n"
    2971             : "        COLON\n"
    2972             : "        IDENTIFIER \"red\"\n"
    2973             : "  COMPONENT_VALUE\n"
    2974             : "    ARG\n"
    2975             : "      IDENTIFIER \"a\"\n"
    2976             : "    ARG\n"
    2977             : "      IDENTIFIER \"b\"\n"
    2978             : "    OPEN_CURLYBRACKET B:false\n"
    2979             : "      COMPONENT_VALUE\n"
    2980             : "        IDENTIFIER \"color\"\n"
    2981             : "        COLON\n"
    2982             : "        IDENTIFIER \"red\"\n"
    2983             : "  COMPONENT_VALUE\n"
    2984             : "    ARG\n"
    2985             : "      IDENTIFIER \"a\"\n"
    2986             : "    ARG\n"
    2987             : "      IDENTIFIER \"b\"\n"
    2988             : "    ARG\n"
    2989             : "      IDENTIFIER \"c\"\n"
    2990             : "    OPEN_CURLYBRACKET B:false\n"
    2991             : "      COMPONENT_VALUE\n"
    2992             : "        IDENTIFIER \"color\"\n"
    2993             : "        COLON\n"
    2994             : "        IDENTIFIER \"red\"\n"
    2995             : "  COMPONENT_VALUE\n"
    2996             : "    ARG\n"
    2997             : "      IDENTIFIER \"a\"\n"
    2998             : "    ARG\n"
    2999             : "      IDENTIFIER \"b\"\n"
    3000             : "    ARG\n"
    3001             : "      IDENTIFIER \"c\"\n"
    3002             : "    OPEN_CURLYBRACKET B:false\n"
    3003             : "      COMPONENT_VALUE\n"
    3004             : "        IDENTIFIER \"color\"\n"
    3005             : "        COLON\n"
    3006             : "        IDENTIFIER \"red\"\n"
    3007             : "  COMPONENT_VALUE\n"
    3008             : "    ARG\n"
    3009             : "      IDENTIFIER \"a\"\n"
    3010             : "    OPEN_CURLYBRACKET B:false\n"
    3011             : "      COMPONENT_VALUE\n"
    3012             : "        IDENTIFIER \"color\"\n"
    3013             : "        COLON\n"
    3014             : "        IDENTIFIER \"red\"\n"
    3015             : "  COMPONENT_VALUE\n"
    3016             : "    ARG\n"
    3017             : "      IDENTIFIER \"a\"\n"
    3018             : "    OPEN_CURLYBRACKET B:false\n"
    3019             : "      COMPONENT_VALUE\n"
    3020             : "        IDENTIFIER \"color\"\n"
    3021             : "        COLON\n"
    3022             : "        IDENTIFIER \"red\"\n"
    3023             : "  COMPONENT_VALUE\n"
    3024             : "    ARG\n"
    3025             : "      IDENTIFIER \"a\"\n"
    3026             : "    ARG\n"
    3027             : "      IDENTIFIER \"b\"\n"
    3028             : "    OPEN_CURLYBRACKET B:false\n"
    3029             : "      COMPONENT_VALUE\n"
    3030             : "        IDENTIFIER \"color\"\n"
    3031             : "        COLON\n"
    3032             : "        IDENTIFIER \"red\"\n"
    3033             : 
    3034             :             );
    3035             : 
    3036             :         // no error left over
    3037           1 :         VERIFY_ERRORS("");
    3038           1 :     }
    3039           1 : }
    3040             : 
    3041           1 : CATCH_TEST_CASE("Invalid argify", "[parser] [stylesheet]")
    3042             : {
    3043             :     // A starting comma is illegal
    3044             :     {
    3045           1 :         std::stringstream ss;
    3046           1 :         ss << ",a{color:red}\n";
    3047           3 :         csspp::position pos("test.css");
    3048           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3049             : 
    3050           2 :         csspp::parser p(l);
    3051             : 
    3052           1 :         csspp::node::pointer_t n(p.stylesheet());
    3053             : 
    3054             : //std::cerr << "Result is: [" << *n << "]\n";
    3055             : 
    3056             :         // no errors so far
    3057           1 :         VERIFY_ERRORS("");
    3058             : 
    3059           1 :         std::stringstream out;
    3060           1 :         out << *n;
    3061           1 :         VERIFY_TREES(out.str(),
    3062             : 
    3063             : "LIST\n"
    3064             : "  COMPONENT_VALUE\n"
    3065             : "    COMMA\n"
    3066             : "    IDENTIFIER \"a\"\n"
    3067             : "    OPEN_CURLYBRACKET B:false\n"
    3068             : "      COMPONENT_VALUE\n"
    3069             : "        IDENTIFIER \"color\"\n"
    3070             : "        COLON\n"
    3071             : "        IDENTIFIER \"red\"\n"
    3072             : 
    3073             :             );
    3074             : 
    3075             :         // Argify the list under each COMPONENT_VALUE
    3076           1 :         CATCH_REQUIRE(n->is(csspp::node_type_t::LIST));
    3077             : 
    3078           1 :         size_t const max_children(n->size());
    3079           2 :         for(size_t idx(0); idx < max_children; ++idx)
    3080             :         {
    3081           1 :             csspp::node::pointer_t component_value(n->get_child(idx));
    3082           1 :             CATCH_REQUIRE(component_value->is(csspp::node_type_t::COMPONENT_VALUE));
    3083           1 :             CATCH_REQUIRE_FALSE(csspp::parser::argify(component_value));
    3084           1 :         }
    3085             : 
    3086           1 :         VERIFY_ERRORS("test.css(1): error: dangling comma at the beginning of a list of arguments or selectors.\n");
    3087           1 :     }
    3088             : 
    3089             :     // An ending comma is illegal
    3090             :     {
    3091           1 :         std::stringstream ss;
    3092           1 :         ss << "a,{color:red}\n";
    3093           3 :         csspp::position pos("test.css");
    3094           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3095             : 
    3096           2 :         csspp::parser p(l);
    3097             : 
    3098           1 :         csspp::node::pointer_t n(p.stylesheet());
    3099             : 
    3100             :         // no errors so far
    3101           1 :         VERIFY_ERRORS("");
    3102             : 
    3103             : //std::cerr << "Result is: [" << *n << "]\n";
    3104             : 
    3105           1 :         std::stringstream out;
    3106           1 :         out << *n;
    3107           1 :         VERIFY_TREES(out.str(),
    3108             : 
    3109             : "LIST\n"
    3110             : "  COMPONENT_VALUE\n"
    3111             : "    IDENTIFIER \"a\"\n"
    3112             : "    COMMA\n"
    3113             : "    OPEN_CURLYBRACKET B:false\n"
    3114             : "      COMPONENT_VALUE\n"
    3115             : "        IDENTIFIER \"color\"\n"
    3116             : "        COLON\n"
    3117             : "        IDENTIFIER \"red\"\n"
    3118             : 
    3119             :             );
    3120             : 
    3121             :         // Argify the list under each COMPONENT_VALUE
    3122           1 :         CATCH_REQUIRE(n->is(csspp::node_type_t::LIST));
    3123             : 
    3124           1 :         size_t const max_children(n->size());
    3125           2 :         for(size_t idx(0); idx < max_children; ++idx)
    3126             :         {
    3127           1 :             csspp::node::pointer_t component_value(n->get_child(idx));
    3128           1 :             CATCH_REQUIRE(component_value->is(csspp::node_type_t::COMPONENT_VALUE));
    3129           1 :             CATCH_REQUIRE_FALSE(csspp::parser::argify(component_value));
    3130           1 :         }
    3131             : 
    3132           1 :         VERIFY_ERRORS("test.css(1): error: dangling comma at the end of a list of arguments or selectors.\n");
    3133           1 :     }
    3134             : 
    3135             :     // Two commas in a row is illegal
    3136             :     {
    3137           1 :         std::stringstream ss;
    3138           1 :         ss << "a,,b{color:red}\n";
    3139           3 :         csspp::position pos("test.css");
    3140           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3141             : 
    3142           2 :         csspp::parser p(l);
    3143             : 
    3144           1 :         csspp::node::pointer_t n(p.stylesheet());
    3145             : 
    3146             :         // no errors so far
    3147           1 :         VERIFY_ERRORS("");
    3148             : 
    3149             : //std::cerr << "Result is: [" << *n << "]\n";
    3150             : 
    3151           1 :         std::stringstream out;
    3152           1 :         out << *n;
    3153           1 :         VERIFY_TREES(out.str(),
    3154             : 
    3155             : "LIST\n"
    3156             : "  COMPONENT_VALUE\n"
    3157             : "    IDENTIFIER \"a\"\n"
    3158             : "    COMMA\n"
    3159             : "    COMMA\n"
    3160             : "    IDENTIFIER \"b\"\n"
    3161             : "    OPEN_CURLYBRACKET B:false\n"
    3162             : "      COMPONENT_VALUE\n"
    3163             : "        IDENTIFIER \"color\"\n"
    3164             : "        COLON\n"
    3165             : "        IDENTIFIER \"red\"\n"
    3166             : 
    3167             :             );
    3168             : 
    3169             :         // Argify the list under each COMPONENT_VALUE
    3170           1 :         CATCH_REQUIRE(n->is(csspp::node_type_t::LIST));
    3171             : 
    3172           1 :         size_t const max_children(n->size());
    3173           2 :         for(size_t idx(0); idx < max_children; ++idx)
    3174             :         {
    3175           1 :             csspp::node::pointer_t component_value(n->get_child(idx));
    3176           1 :             CATCH_REQUIRE(component_value->is(csspp::node_type_t::COMPONENT_VALUE));
    3177           1 :             CATCH_REQUIRE_FALSE(csspp::parser::argify(component_value));
    3178           1 :         }
    3179             : 
    3180           1 :         VERIFY_ERRORS("test.css(1): error: two commas in a row are invalid in a list of arguments or selectors.\n");
    3181           1 :     }
    3182             : 
    3183             :     // Just a comma is illegal
    3184             :     {
    3185           1 :         std::stringstream ss;
    3186           1 :         ss << ",{color:red}\n";
    3187           3 :         csspp::position pos("test.css");
    3188           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3189             : 
    3190           2 :         csspp::parser p(l);
    3191             : 
    3192           1 :         csspp::node::pointer_t n(p.stylesheet());
    3193             : 
    3194             :         // no errors so far
    3195           1 :         VERIFY_ERRORS("");
    3196             : 
    3197             : //std::cerr << "Result is: [" << *n << "]\n";
    3198             : 
    3199           1 :         std::stringstream out;
    3200           1 :         out << *n;
    3201           1 :         VERIFY_TREES(out.str(),
    3202             : 
    3203             : "LIST\n"
    3204             : "  COMPONENT_VALUE\n"
    3205             : "    COMMA\n"
    3206             : "    OPEN_CURLYBRACKET B:false\n"
    3207             : "      COMPONENT_VALUE\n"
    3208             : "        IDENTIFIER \"color\"\n"
    3209             : "        COLON\n"
    3210             : "        IDENTIFIER \"red\"\n"
    3211             : 
    3212             :             );
    3213             : 
    3214             :         // Argify the list under each COMPONENT_VALUE
    3215           1 :         CATCH_REQUIRE(n->is(csspp::node_type_t::LIST));
    3216             : 
    3217           1 :         size_t const max_children(n->size());
    3218           2 :         for(size_t idx(0); idx < max_children; ++idx)
    3219             :         {
    3220           1 :             csspp::node::pointer_t component_value(n->get_child(idx));
    3221           1 :             CATCH_REQUIRE(component_value->is(csspp::node_type_t::COMPONENT_VALUE));
    3222           1 :             CATCH_REQUIRE_FALSE(csspp::parser::argify(component_value));
    3223           1 :         }
    3224             : 
    3225           1 :         VERIFY_ERRORS("test.css(1): error: dangling comma at the beginning of a list of arguments or selectors.\n");
    3226           1 :     }
    3227             : 
    3228             :     // calling argify with the wrong separators
    3229             :     {
    3230           1 :         std::stringstream ss;
    3231           1 :         ss << "a,b{color:red}\n";
    3232           3 :         csspp::position pos("test.css");
    3233           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3234             : 
    3235           2 :         csspp::parser p(l);
    3236             : 
    3237           1 :         csspp::node::pointer_t n(p.stylesheet());
    3238             : 
    3239             :         // no errors so far
    3240           1 :         VERIFY_ERRORS("");
    3241             : 
    3242             : //std::cerr << "Result is: [" << *n << "]\n";
    3243             : 
    3244           1 :         std::stringstream out;
    3245           1 :         out << *n;
    3246           1 :         VERIFY_TREES(out.str(),
    3247             : 
    3248             : "LIST\n"
    3249             : "  COMPONENT_VALUE\n"
    3250             : "    IDENTIFIER \"a\"\n"
    3251             : "    COMMA\n"
    3252             : "    IDENTIFIER \"b\"\n"
    3253             : "    OPEN_CURLYBRACKET B:false\n"
    3254             : "      COMPONENT_VALUE\n"
    3255             : "        IDENTIFIER \"color\"\n"
    3256             : "        COLON\n"
    3257             : "        IDENTIFIER \"red\"\n"
    3258             : 
    3259             :             );
    3260             : 
    3261             :         // Attempt to argify the list under each COMPONENT_VALUE using
    3262             :         // the wrong type
    3263           1 :         CATCH_REQUIRE(n->is(csspp::node_type_t::LIST));
    3264             : 
    3265           1 :         size_t const max_children(n->size());
    3266           2 :         for(size_t idx(0); idx < max_children; ++idx)
    3267             :         {
    3268           1 :             csspp::node::pointer_t component_value(n->get_child(idx));
    3269           1 :             CATCH_REQUIRE(component_value->is(csspp::node_type_t::COMPONENT_VALUE));
    3270             : 
    3271           1 :             for(csspp::node_type_t w(csspp::node_type_t::UNKNOWN);
    3272          69 :                 w <= csspp::node_type_t::max_type;
    3273          68 :                 w = static_cast<csspp::node_type_t>(static_cast<int>(w) + 1))
    3274             :             {
    3275          68 :                 switch(w)
    3276             :                 {
    3277           2 :                 case csspp::node_type_t::COMMA:
    3278             :                 case csspp::node_type_t::DIVIDE:
    3279           2 :                     continue;
    3280             : 
    3281          66 :                 default:
    3282          66 :                     break;
    3283             : 
    3284             :                 }
    3285         198 :                 CATCH_REQUIRE_THROWS_AS(csspp::parser::argify(component_value, w), csspp::csspp_exception_logic);
    3286             :             }
    3287           1 :         }
    3288             : 
    3289           1 :         VERIFY_ERRORS("");
    3290           1 :     }
    3291             : 
    3292             :     // no error left over
    3293           1 :     VERIFY_ERRORS("");
    3294           1 : }
    3295             : 
    3296             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14