LCOV - code coverage report
Current view: top level - tests - catch_compiler.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 4001 4005 99.9 %
Date: 2023-11-01 21:56:19 Functions: 33 33 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 compiler.cpp file.
      22             :  *
      23             :  * This test runs a battery of tests agains the compiler.cpp file to ensure
      24             :  * full coverage and many edge cases as expected by CSS 3 and many of the
      25             :  * CSS Preprocessor extensions.
      26             :  */
      27             : 
      28             : // csspp
      29             : //
      30             : #include    <csspp/compiler.h>
      31             : 
      32             : #include    <csspp/exception.h>
      33             : #include    <csspp/parser.h>
      34             : 
      35             : 
      36             : // self
      37             : //
      38             : #include    "catch_main.h"
      39             : 
      40             : 
      41             : // C++
      42             : //
      43             : #include    <fstream>
      44             : #include    <iostream>
      45             : #include    <sstream>
      46             : 
      47             : 
      48             : // C
      49             : //
      50             : #include    <string.h>
      51             : #include    <unistd.h>
      52             : #include    <sys/stat.h>
      53             : 
      54             : 
      55             : // last include
      56             : //
      57             : #include    <snapdev/poison.h>
      58             : 
      59             : 
      60             : 
      61           1 : void free_char(char * ptr)
      62             : {
      63           1 :     free(ptr);
      64           1 : }
      65             : 
      66           1 : CATCH_TEST_CASE("Compile set_date_time_variables() called too soon", "[compiler] [invalid]")
      67             : {
      68           1 :         csspp::compiler c;
      69           1 :         CATCH_REQUIRE_THROWS_AS(c.set_date_time_variables(csspp_test::get_now()), csspp::csspp_exception_logic);
      70           2 : }
      71             : 
      72           1 : CATCH_TEST_CASE("Compile simple stylesheets", "[compiler] [stylesheet] [attribute]")
      73             : {
      74             :     // with many spaces
      75             :     {
      76           1 :         std::stringstream ss;
      77             :         ss << "/* testing compile */"
      78             :            << "body, a[q] > b[p=\"344.5\"] + c[z=33] ~ d[e], html *[ ff = fire ] *.blue { background : white url( /images/background.png ) }"
      79           1 :            << "/* @preserver test \"Compile Simple Stylesheet\" */";
      80           3 :         csspp::position pos("test.css");
      81           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
      82             : 
      83           2 :         csspp::parser p(l);
      84             : 
      85           1 :         csspp::node::pointer_t n(p.stylesheet());
      86             : 
      87             :         // no errors so far
      88           1 :         VERIFY_ERRORS("");
      89             : 
      90           1 :         csspp::compiler c;
      91           1 :         c.set_root(n);
      92           1 :         c.set_date_time_variables(csspp_test::get_now());
      93           1 :         c.clear_paths();
      94           1 :         c.add_path(csspp_test::get_script_path());
      95           1 :         c.add_path(csspp_test::get_version_script_path());
      96             : 
      97           1 :         c.compile(false);
      98             : 
      99             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     100             : 
     101           1 :         std::stringstream out;
     102           1 :         out << *n;
     103           1 :         VERIFY_TREES(out.str(),
     104             : 
     105             : "LIST\n"
     106             : + csspp_test::get_default_variables() +
     107             : "  COMPONENT_VALUE\n"
     108             : "    ARG\n"
     109             : "      IDENTIFIER \"body\"\n"
     110             : "    ARG\n"
     111             : "      IDENTIFIER \"a\"\n"
     112             : "      OPEN_SQUAREBRACKET\n"
     113             : "        IDENTIFIER \"q\"\n"
     114             : "      GREATER_THAN\n"
     115             : "      IDENTIFIER \"b\"\n"
     116             : "      OPEN_SQUAREBRACKET\n"
     117             : "        IDENTIFIER \"p\"\n"
     118             : "        EQUAL\n"
     119             : "        STRING \"344.5\"\n"
     120             : "      ADD\n"
     121             : "      IDENTIFIER \"c\"\n"
     122             : "      OPEN_SQUAREBRACKET\n"
     123             : "        IDENTIFIER \"z\"\n"
     124             : "        EQUAL\n"
     125             : "        INTEGER \"\" I:33\n"
     126             : "      PRECEDED\n"
     127             : "      IDENTIFIER \"d\"\n"
     128             : "      OPEN_SQUAREBRACKET\n"
     129             : "        IDENTIFIER \"e\"\n"
     130             : "    ARG\n"
     131             : "      IDENTIFIER \"html\"\n"
     132             : "      WHITESPACE\n"
     133             : "      OPEN_SQUAREBRACKET\n"
     134             : "        IDENTIFIER \"ff\"\n"
     135             : "        EQUAL\n"
     136             : "        IDENTIFIER \"fire\"\n"
     137             : "      WHITESPACE\n"
     138             : "      PERIOD\n"
     139             : "      IDENTIFIER \"blue\"\n"
     140             : "    OPEN_CURLYBRACKET B:true\n"
     141             : "      DECLARATION \"background\"\n"
     142             : "        ARG\n"
     143             : "          COLOR H:ffffffff\n"
     144             : "          WHITESPACE\n"
     145             : "          URL \"/images/background.png\"\n"
     146             : "  COMMENT \"@preserver test \"Compile Simple Stylesheet\"\" I:1\n"
     147             : + csspp_test::get_close_comment(true)
     148             : 
     149             :             );
     150             : 
     151             :         // no error left over
     152           1 :         VERIFY_ERRORS("");
     153             : 
     154           1 :         CATCH_REQUIRE(c.get_root() == n);
     155           1 :     }
     156             : 
     157             :     // without spaces
     158             :     {
     159           1 :         std::stringstream ss;
     160             :         ss << "/* testing compile */"
     161             :            << "body,a[q]>b[p=\"344.5\"]+c[z=33]~d[e],html *[ff=fire] *.blue { background:white url(/images/background.png) }"
     162           1 :            << "/* @preserver test \"Compile Simple Stylesheet\" with version #{$_csspp_major}.#{$_csspp_minor} */";
     163           3 :         csspp::position pos("test.css");
     164           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     165             : 
     166           2 :         csspp::parser p(l);
     167             : 
     168           1 :         csspp::node::pointer_t n(p.stylesheet());
     169             : 
     170             :         // no errors so far
     171           1 :         VERIFY_ERRORS("");
     172             : 
     173           1 :         csspp::compiler c;
     174           1 :         c.set_root(n);
     175           1 :         c.set_date_time_variables(csspp_test::get_now());
     176           1 :         c.clear_paths();
     177           1 :         c.add_path(csspp_test::get_script_path());
     178           1 :         c.add_path(csspp_test::get_version_script_path());
     179             : 
     180           1 :         c.compile(false);
     181             : 
     182             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     183             : 
     184           1 :         std::stringstream out;
     185           1 :         out << *n;
     186           1 :         VERIFY_TREES(out.str(),
     187             : 
     188             : "LIST\n"
     189             : + csspp_test::get_default_variables() +
     190             : "  COMPONENT_VALUE\n"
     191             : "    ARG\n"
     192             : "      IDENTIFIER \"body\"\n"
     193             : "    ARG\n"
     194             : "      IDENTIFIER \"a\"\n"
     195             : "      OPEN_SQUAREBRACKET\n"
     196             : "        IDENTIFIER \"q\"\n"
     197             : "      GREATER_THAN\n"
     198             : "      IDENTIFIER \"b\"\n"
     199             : "      OPEN_SQUAREBRACKET\n"
     200             : "        IDENTIFIER \"p\"\n"
     201             : "        EQUAL\n"
     202             : "        STRING \"344.5\"\n"
     203             : "      ADD\n"
     204             : "      IDENTIFIER \"c\"\n"
     205             : "      OPEN_SQUAREBRACKET\n"
     206             : "        IDENTIFIER \"z\"\n"
     207             : "        EQUAL\n"
     208             : "        INTEGER \"\" I:33\n"
     209             : "      PRECEDED\n"
     210             : "      IDENTIFIER \"d\"\n"
     211             : "      OPEN_SQUAREBRACKET\n"
     212             : "        IDENTIFIER \"e\"\n"
     213             : "    ARG\n"
     214             : "      IDENTIFIER \"html\"\n"
     215             : "      WHITESPACE\n"
     216             : "      OPEN_SQUAREBRACKET\n"
     217             : "        IDENTIFIER \"ff\"\n"
     218             : "        EQUAL\n"
     219             : "        IDENTIFIER \"fire\"\n"
     220             : "      WHITESPACE\n"
     221             : "      PERIOD\n"
     222             : "      IDENTIFIER \"blue\"\n"
     223             : "    OPEN_CURLYBRACKET B:true\n"
     224             : "      DECLARATION \"background\"\n"
     225             : "        ARG\n"
     226             : "          COLOR H:ffffffff\n"
     227             : "          WHITESPACE\n"
     228             : "          URL \"/images/background.png\"\n"
     229             : "  COMMENT \"@preserver test \"Compile Simple Stylesheet\" with version 1.0\" I:1\n"
     230             : + csspp_test::get_close_comment(true)
     231             : 
     232             :             );
     233             : 
     234             :         // no error left over
     235           1 :         VERIFY_ERRORS("");
     236             : 
     237           1 :         CATCH_REQUIRE(c.get_root() == n);
     238           1 :     }
     239             : 
     240             :     // rules with !important
     241             :     {
     242           1 :         std::stringstream ss;
     243           1 :         ss << "div.blackness { color: red !important }";
     244           3 :         csspp::position pos("test.css");
     245           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     246             : 
     247           2 :         csspp::parser p(l);
     248             : 
     249           1 :         csspp::node::pointer_t n(p.stylesheet());
     250             : 
     251             :         // no errors so far
     252           1 :         VERIFY_ERRORS("");
     253             : 
     254           1 :         csspp::compiler c;
     255           1 :         c.set_root(n);
     256           1 :         c.set_date_time_variables(csspp_test::get_now());
     257           1 :         c.clear_paths();
     258           1 :         c.add_path(csspp_test::get_script_path());
     259           1 :         c.add_path(csspp_test::get_version_script_path());
     260             : 
     261           1 :         c.compile(false);
     262             : 
     263             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     264             : 
     265           1 :         std::stringstream out;
     266           1 :         out << *n;
     267           1 :         VERIFY_TREES(out.str(),
     268             : 
     269             : "LIST\n"
     270             : + csspp_test::get_default_variables() +
     271             : "  COMPONENT_VALUE\n"
     272             : "    ARG\n"
     273             : "      IDENTIFIER \"div\"\n"
     274             : "      PERIOD\n"
     275             : "      IDENTIFIER \"blackness\"\n"
     276             : "    OPEN_CURLYBRACKET B:true\n"
     277             : "      DECLARATION \"color\" F:important\n"
     278             : "        ARG\n"
     279             : "          COLOR H:ff0000ff\n"
     280             : + csspp_test::get_close_comment(true)
     281             : 
     282             :             );
     283             : 
     284             :         // no error left over
     285           1 :         VERIFY_ERRORS("");
     286             : 
     287           1 :         CATCH_REQUIRE(c.get_root() == n);
     288           1 :     }
     289             : 
     290             :     // rules with ! important
     291             :     {
     292           1 :         std::stringstream ss;
     293           1 :         ss << "div.blackness { color: red ! important }";
     294           3 :         csspp::position pos("test.css");
     295           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     296             : 
     297           2 :         csspp::parser p(l);
     298             : 
     299           1 :         csspp::node::pointer_t n(p.stylesheet());
     300             : 
     301             :         // no errors so far
     302           1 :         VERIFY_ERRORS("");
     303             : 
     304           1 :         csspp::compiler c;
     305           1 :         c.set_root(n);
     306           1 :         c.set_date_time_variables(csspp_test::get_now());
     307           1 :         c.clear_paths();
     308           1 :         c.add_path(csspp_test::get_script_path());
     309           1 :         c.add_path(csspp_test::get_version_script_path());
     310             : 
     311           1 :         c.compile(false);
     312             : 
     313             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     314             : 
     315           1 :         std::stringstream out;
     316           1 :         out << *n;
     317           1 :         VERIFY_TREES(out.str(),
     318             : 
     319             : "LIST\n"
     320             : + csspp_test::get_default_variables() +
     321             : "  COMPONENT_VALUE\n"
     322             : "    ARG\n"
     323             : "      IDENTIFIER \"div\"\n"
     324             : "      PERIOD\n"
     325             : "      IDENTIFIER \"blackness\"\n"
     326             : "    OPEN_CURLYBRACKET B:true\n"
     327             : "      DECLARATION \"color\" F:important\n"
     328             : "        ARG\n"
     329             : "          COLOR H:ff0000ff\n"
     330             : + csspp_test::get_close_comment(true)
     331             : 
     332             :             );
     333             : 
     334             :         // no error left over
     335           1 :         VERIFY_ERRORS("");
     336             : 
     337           1 :         CATCH_REQUIRE(c.get_root() == n);
     338           1 :     }
     339             : 
     340             :     // rules with !important and no spaces
     341             :     {
     342           1 :         std::stringstream ss;
     343           1 :         ss << "div.blackness { color: red!important }";
     344           3 :         csspp::position pos("test.css");
     345           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     346             : 
     347           2 :         csspp::parser p(l);
     348             : 
     349           1 :         csspp::node::pointer_t n(p.stylesheet());
     350             : 
     351             :         // no errors so far
     352           1 :         VERIFY_ERRORS("");
     353             : 
     354           1 :         csspp::compiler c;
     355           1 :         c.set_root(n);
     356           1 :         c.set_date_time_variables(csspp_test::get_now());
     357           1 :         c.clear_paths();
     358           1 :         c.add_path(csspp_test::get_script_path());
     359           1 :         c.add_path(csspp_test::get_version_script_path());
     360             : 
     361           1 :         c.compile(false);
     362             : 
     363             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     364             : 
     365           1 :         std::stringstream out;
     366           1 :         out << *n;
     367           1 :         VERIFY_TREES(out.str(),
     368             : 
     369             : "LIST\n"
     370             : + csspp_test::get_default_variables() +
     371             : "  COMPONENT_VALUE\n"
     372             : "    ARG\n"
     373             : "      IDENTIFIER \"div\"\n"
     374             : "      PERIOD\n"
     375             : "      IDENTIFIER \"blackness\"\n"
     376             : "    OPEN_CURLYBRACKET B:true\n"
     377             : "      DECLARATION \"color\" F:important\n"
     378             : "        ARG\n"
     379             : "          COLOR H:ff0000ff\n"
     380             : + csspp_test::get_close_comment(true)
     381             : 
     382             :             );
     383             : 
     384             :         // no error left over
     385           1 :         VERIFY_ERRORS("");
     386             : 
     387           1 :         CATCH_REQUIRE(c.get_root() == n);
     388           1 :     }
     389             : 
     390             :     // empty rules have to compile too
     391             :     {
     392           1 :         std::stringstream ss;
     393             :         ss << "div.blackness section.light span.clear\n"
     394             :            << "{\n"
     395           1 :            << "}\n";
     396           3 :         csspp::position pos("test.css");
     397           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     398             : 
     399           2 :         csspp::parser p(l);
     400             : 
     401           1 :         csspp::node::pointer_t n(p.stylesheet());
     402             : 
     403             :         // no errors so far
     404           1 :         VERIFY_ERRORS("");
     405             : 
     406           1 :         csspp::compiler c;
     407           1 :         c.set_root(n);
     408           1 :         c.set_date_time_variables(csspp_test::get_now());
     409           1 :         c.clear_paths();
     410           1 :         c.add_path(csspp_test::get_script_path());
     411           1 :         c.add_path(csspp_test::get_version_script_path());
     412             : 
     413           1 :         c.compile(false);
     414             : 
     415             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     416             : 
     417           1 :         std::stringstream out;
     418           1 :         out << *n;
     419           1 :         VERIFY_TREES(out.str(),
     420             : 
     421             : "LIST\n"
     422             : + csspp_test::get_default_variables()
     423             : + csspp_test::get_close_comment(true)
     424             : 
     425             :             );
     426             : 
     427             :         // no error left over
     428           1 :         VERIFY_ERRORS("");
     429             : 
     430           1 :         CATCH_REQUIRE(c.get_root() == n);
     431           1 :     }
     432             : 
     433             :     // special IE8 value which has to be skipped
     434             :     {
     435           1 :         std::stringstream ss;
     436             :         ss << ".transparent img\n"
     437             :            << "{\n"
     438             :            << "  $alpha: 5% * 4;\n"
     439             :            << "  filter: opacity($alpha);\n"
     440             :            << "  filter: alpha( opacity=20 );\n"
     441           1 :            << "}\n";
     442           3 :         csspp::position pos("test.css");
     443           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     444             : 
     445           2 :         csspp::parser p(l);
     446             : 
     447           1 :         csspp::node::pointer_t n(p.stylesheet());
     448             : 
     449             :         // no errors so far
     450           1 :         VERIFY_ERRORS("");
     451             : 
     452           1 :         csspp::compiler c;
     453           1 :         c.set_root(n);
     454           1 :         c.set_date_time_variables(csspp_test::get_now());
     455           1 :         c.clear_paths();
     456           1 :         c.add_path(csspp_test::get_script_path());
     457           1 :         c.add_path(csspp_test::get_version_script_path());
     458             : 
     459           1 :         c.compile(false);
     460             : 
     461             :         // no error left over
     462           1 :         VERIFY_ERRORS(
     463             :                 "test.css(4): warning: the alpha(), chroma() and similar functions of the filter field are Internet Explorer specific extensions which are not supported across browsers.\n"
     464             :                 "test.css(5): warning: the alpha(), chroma() and similar functions of the filter field are Internet Explorer specific extensions which are not supported across browsers.\n"
     465             :             );
     466             : 
     467             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     468             : 
     469           1 :         std::stringstream out;
     470           1 :         out << *n;
     471           1 :         VERIFY_TREES(out.str(),
     472             : 
     473             : "LIST\n"
     474             : + csspp_test::get_default_variables() +
     475             : "  COMPONENT_VALUE\n"
     476             : "    ARG\n"
     477             : "      PERIOD\n"
     478             : "      IDENTIFIER \"transparent\"\n"
     479             : "      WHITESPACE\n"
     480             : "      IDENTIFIER \"img\"\n"
     481             : "    OPEN_CURLYBRACKET B:true\n"
     482             : "        V:alpha\n"
     483             : "          LIST\n"
     484             : "            VARIABLE \"alpha\"\n"
     485             : "            LIST\n"
     486             : "              PERCENT D:0.05\n"
     487             : "              WHITESPACE\n"
     488             : "              MULTIPLY\n"
     489             : "              WHITESPACE\n"
     490             : "              INTEGER \"\" I:4\n"
     491             : "      LIST\n"
     492             : "        DECLARATION \"filter\"\n"
     493             : "          FUNCTION \"opacity\"\n"
     494             : "            PERCENT D:0.05\n"
     495             : "            WHITESPACE\n"
     496             : "            MULTIPLY\n"
     497             : "            WHITESPACE\n"
     498             : "            INTEGER \"\" I:4\n"
     499             : "        DECLARATION \"filter\"\n"
     500             : "          FUNCTION \"alpha\"\n"
     501             : "            IDENTIFIER \"opacity\"\n"
     502             : "            EQUAL\n"
     503             : "            INTEGER \"\" I:20\n"
     504             : + csspp_test::get_close_comment(true)
     505             : 
     506             :             );
     507             : 
     508             :         // no error left over
     509           1 :         VERIFY_ERRORS("");
     510             : 
     511           1 :         CATCH_REQUIRE(c.get_root() == n);
     512           1 :     }
     513             : 
     514             :     // a simple test with '--no-logo' specified
     515             :     {
     516           1 :         std::stringstream ss;
     517             :         ss << ".box\n"
     518             :            << "{\n"
     519             :            << "  color: $_csspp_no_logo ? red : blue;\n"
     520           1 :            << "}\n";
     521           3 :         csspp::position pos("test.css");
     522           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     523             : 
     524           2 :         csspp::parser p(l);
     525             : 
     526           1 :         csspp::node::pointer_t n(p.stylesheet());
     527             : 
     528             :         // no errors so far
     529           1 :         VERIFY_ERRORS("");
     530             : 
     531           1 :         csspp::compiler c;
     532           1 :         c.set_root(n);
     533           1 :         c.set_date_time_variables(csspp_test::get_now());
     534           1 :         c.set_no_logo();
     535           1 :         c.clear_paths();
     536           1 :         c.add_path(csspp_test::get_script_path());
     537           1 :         c.add_path(csspp_test::get_version_script_path());
     538             : 
     539           1 :         c.compile(false);
     540             : 
     541             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     542             : 
     543             :         // no error left over
     544           1 :         VERIFY_ERRORS("");
     545             : 
     546           1 :         std::stringstream out;
     547           1 :         out << *n;
     548           1 :         VERIFY_TREES(out.str(),
     549             : 
     550             : "LIST\n"
     551             : + csspp_test::get_default_variables(csspp_test::flag_no_logo_true) +
     552             : "  COMPONENT_VALUE\n"
     553             : "    ARG\n"
     554             : "      PERIOD\n"
     555             : "      IDENTIFIER \"box\"\n"
     556             : "    OPEN_CURLYBRACKET B:true\n"
     557             : "      DECLARATION \"color\"\n"
     558             : "        ARG\n"
     559             : "          COLOR H:ff0000ff\n"
     560             : //+ csspp_test::get_close_comment(true) -- with --no-logo this is gone
     561             : 
     562             :             );
     563             : 
     564             :         // no error left over
     565           1 :         VERIFY_ERRORS("");
     566             : 
     567           1 :         CATCH_REQUIRE(c.get_root() == n);
     568           1 :     }
     569           1 : }
     570             : 
     571           5 : CATCH_TEST_CASE("Compile user defined functions", "[compiler] [function]")
     572             : {
     573           5 :     CATCH_START_SECTION("deg2rad() function and translate() CSS function")
     574             :     {
     575           1 :         std::stringstream ss;
     576             :         ss << "/* testing user defined functions */\n"
     577             :            << "body { angle : deg2rad( 32deg ) }\n"
     578             :            << "a b { transform: translate(12%, 0); }\n"
     579           1 :            << "/* @preserver test \"Compile User Functions\" */\n";
     580           3 :         csspp::position pos("test.css");
     581           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     582             : 
     583           2 :         csspp::parser p(l);
     584             : 
     585           1 :         csspp::node::pointer_t n(p.stylesheet());
     586             : 
     587             :         // no errors so far
     588           1 :         VERIFY_ERRORS("");
     589             : 
     590           1 :         csspp::compiler c;
     591           1 :         c.set_root(n);
     592           1 :         c.set_date_time_variables(csspp_test::get_now());
     593           1 :         c.clear_paths();
     594           1 :         c.add_path(csspp_test::get_script_path());
     595           1 :         c.add_path(csspp_test::get_version_script_path());
     596             : 
     597           1 :         c.compile(false);
     598             : 
     599             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     600             : 
     601           1 :         std::stringstream out;
     602           1 :         out << *n;
     603           1 :         VERIFY_TREES(out.str(),
     604             : 
     605             : "LIST\n"
     606             : + csspp_test::get_default_variables() +
     607             : "  COMPONENT_VALUE\n"
     608             : "    ARG\n"
     609             : "      IDENTIFIER \"body\"\n"
     610             : "    OPEN_CURLYBRACKET B:true\n"
     611             : "      DECLARATION \"angle\"\n"
     612             : "        ARG\n"
     613             : "          DECIMAL_NUMBER \"rad\" D:0.559\n"
     614             : "  COMPONENT_VALUE\n"
     615             : "    ARG\n"
     616             : "      IDENTIFIER \"a\"\n"
     617             : "      WHITESPACE\n"
     618             : "      IDENTIFIER \"b\"\n"
     619             : "    OPEN_CURLYBRACKET B:true\n"
     620             : "      DECLARATION \"transform\"\n"
     621             : "        ARG\n"
     622             : "          FUNCTION \"translate\"\n"
     623             : "            ARG\n"
     624             : "              PERCENT D:0.12\n"
     625             : "            ARG\n"
     626             : "              INTEGER \"\" I:0\n"
     627             : "  COMMENT \"@preserver test \"Compile User Functions\"\" I:1\n"
     628             : + csspp_test::get_close_comment(true)
     629             : 
     630             :             );
     631             : 
     632             :         // no error left over
     633           1 :         VERIFY_ERRORS("");
     634             : 
     635           1 :         CATCH_REQUIRE(c.get_root() == n);
     636           1 :     }
     637           5 :     CATCH_END_SECTION()
     638             : 
     639           5 :     CATCH_START_SECTION("define an $undefined variable but no undefined() function")
     640             :     {
     641             :         // this is not invalid, until we check for all the CSS function names
     642           1 :         std::stringstream ss;
     643             :         ss << "/* testing user defined functions */\n"
     644             :            << "$zzzundefined: 12%;\n"
     645             :            << "body { angle : zzzundefined( 3rad ) }\n"
     646           1 :            << "/* @preserver test \"Compile User Functions\" */\n";
     647           3 :         csspp::position pos("test.css");
     648           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     649             : 
     650           2 :         csspp::parser p(l);
     651             : 
     652           1 :         csspp::node::pointer_t n(p.stylesheet());
     653             : 
     654             :         // no errors so far
     655           1 :         VERIFY_ERRORS("");
     656             : 
     657           1 :         csspp::compiler c;
     658           1 :         c.set_root(n);
     659           1 :         c.set_date_time_variables(csspp_test::get_now());
     660           1 :         c.clear_paths();
     661           1 :         c.add_path(csspp_test::get_script_path());
     662           1 :         c.add_path(csspp_test::get_version_script_path());
     663             : 
     664           1 :         c.compile(false);
     665             : 
     666             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     667             : 
     668           1 :         std::stringstream out;
     669           1 :         out << *n;
     670           1 :         VERIFY_TREES(out.str(),
     671             : 
     672             : "LIST\n"
     673             : + csspp_test::get_default_variables() +
     674             : "    V:zzzundefined\n"
     675             : "      LIST\n"
     676             : "        VARIABLE \"zzzundefined\"\n"
     677             : "        PERCENT D:0.12\n"
     678             : "  COMPONENT_VALUE\n"
     679             : "    ARG\n"
     680             : "      IDENTIFIER \"body\"\n"
     681             : "    OPEN_CURLYBRACKET B:true\n"
     682             : "      DECLARATION \"angle\"\n"
     683             : "        ARG\n"
     684             : "          FUNCTION \"zzzundefined\"\n"
     685             : "            ARG\n"
     686             : "              INTEGER \"rad\" I:3\n"
     687             : "  COMMENT \"@preserver test \"Compile User Functions\"\" I:1\n"
     688             : + csspp_test::get_close_comment(true)
     689             : 
     690             :             );
     691             : 
     692             :         // no error left over
     693           1 :         VERIFY_ERRORS("");
     694             : 
     695           1 :         CATCH_REQUIRE(c.get_root() == n);
     696           1 :     }
     697           5 :     CATCH_END_SECTION()
     698             : 
     699           5 :     CATCH_START_SECTION("function with default parameters")
     700             :     {
     701             :         // this is not invalid, until we check for all the CSS function names
     702           1 :         std::stringstream ss;
     703             :         ss << "/* testing user defined functions */\n"
     704             :            << "body { color : mix(lightgrey, moccasin) }\n"
     705           1 :            << "/* @preserver test \"Compile User Functions\" */\n";
     706           3 :         csspp::position pos("test.css");
     707           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     708             : 
     709           2 :         csspp::parser p(l);
     710             : 
     711           1 :         csspp::node::pointer_t n(p.stylesheet());
     712             : 
     713             :         // no errors so far
     714           1 :         VERIFY_ERRORS("");
     715             : 
     716           1 :         csspp::compiler c;
     717           1 :         c.set_root(n);
     718           1 :         c.set_date_time_variables(csspp_test::get_now());
     719           1 :         c.clear_paths();
     720           1 :         c.add_path(csspp_test::get_script_path());
     721           1 :         c.add_path(csspp_test::get_version_script_path());
     722             : 
     723           1 :         c.compile(false);
     724             : 
     725             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     726             : 
     727           1 :         std::stringstream out;
     728           1 :         out << *n;
     729           1 :         VERIFY_TREES(out.str(),
     730             : 
     731             : "LIST\n"
     732             : + csspp_test::get_default_variables() +
     733             : "  COMPONENT_VALUE\n"
     734             : "    ARG\n"
     735             : "      IDENTIFIER \"body\"\n"
     736             : "    OPEN_CURLYBRACKET B:true\n"
     737             : "      DECLARATION \"color\"\n"
     738             : "        ARG\n"
     739             : "          COLOR H:ffc4dce9\n"
     740             : "  COMMENT \"@preserver test \"Compile User Functions\"\" I:1\n"
     741             : + csspp_test::get_close_comment(true)
     742             : 
     743             :             );
     744             : 
     745             :         // no error left over
     746           1 :         VERIFY_ERRORS("");
     747             : 
     748           1 :         CATCH_REQUIRE(c.get_root() == n);
     749           1 :     }
     750           5 :     CATCH_END_SECTION()
     751             : 
     752           5 :     CATCH_START_SECTION("function with *complex* default parameter")
     753             :     {
     754             :         // this is not invalid, until we check for all the CSS function names
     755           1 :         std::stringstream ss;
     756             :         ss << "/* testing user defined functions */\n"
     757             :            << "@mixin zzz_my_func($normal, $complex: 3px 7% #ff39af) { @return 3; }\n"
     758             :            << "body { z-index : zzz_my_func('fromage') }\n"
     759           1 :            << "/* @preserver test \"Compile User Functions\" */\n";
     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           1 :         csspp::node::pointer_t n(p.stylesheet());
     766             : 
     767             :         // no errors so far
     768           1 :         VERIFY_ERRORS("");
     769             : 
     770           1 :         csspp::compiler c;
     771           1 :         c.set_root(n);
     772           1 :         c.set_date_time_variables(csspp_test::get_now());
     773           1 :         c.clear_paths();
     774           1 :         c.add_path(csspp_test::get_script_path());
     775           1 :         c.add_path(csspp_test::get_version_script_path());
     776             : 
     777           1 :         c.compile(false);
     778             : 
     779             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     780             : 
     781           1 :         std::stringstream out;
     782           1 :         out << *n;
     783           1 :         VERIFY_TREES(out.str(),
     784             : 
     785             : "LIST\n"
     786             : + csspp_test::get_default_variables() +
     787             : "    V:zzz_my_func\n"
     788             : "      LIST\n"
     789             : "        FUNCTION \"zzz_my_func\"\n"
     790             : "          ARG\n"
     791             : "            VARIABLE \"normal\"\n"
     792             : "          ARG\n"
     793             : "            VARIABLE \"complex\"\n"
     794             : "            INTEGER \"px\" I:3\n"
     795             : "            WHITESPACE\n"
     796             : "            PERCENT D:0.07\n"
     797             : "            WHITESPACE\n"
     798             : "            HASH \"ff39af\"\n"
     799             : "        OPEN_CURLYBRACKET B:true\n"
     800             : "          COMPONENT_VALUE\n"
     801             : "            AT_KEYWORD \"return\" I:0\n"
     802             : "              INTEGER \"\" I:3\n"
     803             : "  COMPONENT_VALUE\n"
     804             : "    ARG\n"
     805             : "      IDENTIFIER \"body\"\n"
     806             : "    OPEN_CURLYBRACKET B:true\n"
     807             : "      DECLARATION \"z-index\"\n"
     808             : "        ARG\n"
     809             : "          INTEGER \"\" I:3\n"
     810             : "  COMMENT \"@preserver test \"Compile User Functions\"\" I:1\n"
     811             : + csspp_test::get_close_comment(true)
     812             : 
     813             :             );
     814             : 
     815             :         // no error left over
     816           1 :         VERIFY_ERRORS("");
     817             : 
     818           1 :         CATCH_REQUIRE(c.get_root() == n);
     819           1 :     }
     820           5 :     CATCH_END_SECTION()
     821             : 
     822           5 :     CATCH_START_SECTION("function called with a *complex* parameter")
     823             :     {
     824             :         // this is not invalid, until we check for all the CSS function names
     825           1 :         std::stringstream ss;
     826             :         ss << "/* testing user defined functions */\n"
     827             :            << "@mixin zzz_my_func($complex) { @return 3; }\n"
     828             :            << "body { z-index : zzz_my_func('fromage' 3px rational) }\n"
     829           1 :            << "/* @preserver test \"Compile User Functions\" */\n";
     830           3 :         csspp::position pos("test.css");
     831           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     832             : 
     833           2 :         csspp::parser p(l);
     834             : 
     835           1 :         csspp::node::pointer_t n(p.stylesheet());
     836             : 
     837             :         // no errors so far
     838           1 :         VERIFY_ERRORS("");
     839             : 
     840           1 :         csspp::compiler c;
     841           1 :         c.set_root(n);
     842           1 :         c.set_date_time_variables(csspp_test::get_now());
     843           1 :         c.clear_paths();
     844           1 :         c.add_path(csspp_test::get_script_path());
     845           1 :         c.add_path(csspp_test::get_version_script_path());
     846             : 
     847           1 :         c.compile(false);
     848             : 
     849             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     850             : 
     851           1 :         std::stringstream out;
     852           1 :         out << *n;
     853           1 :         VERIFY_TREES(out.str(),
     854             : 
     855             : "LIST\n"
     856             : + csspp_test::get_default_variables() +
     857             : "    V:zzz_my_func\n"
     858             : "      LIST\n"
     859             : "        FUNCTION \"zzz_my_func\"\n"
     860             : "          ARG\n"
     861             : "            VARIABLE \"complex\"\n"
     862             : "        OPEN_CURLYBRACKET B:true\n"
     863             : "          COMPONENT_VALUE\n"
     864             : "            AT_KEYWORD \"return\" I:0\n"
     865             : "              INTEGER \"\" I:3\n"
     866             : "  COMPONENT_VALUE\n"
     867             : "    ARG\n"
     868             : "      IDENTIFIER \"body\"\n"
     869             : "    OPEN_CURLYBRACKET B:true\n"
     870             : "      DECLARATION \"z-index\"\n"
     871             : "        ARG\n"
     872             : "          INTEGER \"\" I:3\n"
     873             : "  COMMENT \"@preserver test \"Compile User Functions\"\" I:1\n"
     874             : + csspp_test::get_close_comment(true)
     875             : 
     876             :             );
     877             : 
     878             :         // no error left over
     879           1 :         VERIFY_ERRORS("");
     880             : 
     881           1 :         CATCH_REQUIRE(c.get_root() == n);
     882           1 :     }
     883           5 :     CATCH_END_SECTION()
     884           5 : }
     885             : 
     886           4 : CATCH_TEST_CASE("Compile invalid declaration in link with user defined functions", "[compiler] [invalid] [function]")
     887             : {
     888           4 :     CATCH_START_SECTION("attempt to call a function with an invalid definition")
     889             :     {
     890           1 :         std::stringstream ss;
     891             :         ss << "/* testing user defined functions */\n"
     892             :            << "@mixin my_func($good, bad) { @return 3; }\n"
     893             :            << "body { angle : my_func( 32deg, -3px ) }\n"
     894           1 :            << "/* @preserver test \"Compile Invalid Functions\" */\n";
     895           3 :         csspp::position pos("test.css");
     896           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     897             : 
     898           2 :         csspp::parser p(l);
     899             : 
     900           1 :         csspp::node::pointer_t n(p.stylesheet());
     901             : 
     902             :         // no errors so far
     903           1 :         VERIFY_ERRORS("");
     904             : 
     905           1 :         csspp::compiler c;
     906           1 :         c.set_root(n);
     907           1 :         c.set_date_time_variables(csspp_test::get_now());
     908           1 :         c.clear_paths();
     909           1 :         c.add_path(csspp_test::get_script_path());
     910           1 :         c.add_path(csspp_test::get_version_script_path());
     911             : 
     912           1 :         c.compile(false);
     913             : 
     914             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     915             : 
     916             :         // no error left over
     917           1 :         VERIFY_ERRORS("test.css(2): error: function declarations expect variables for each of their arguments, not a IDENTIFIER.\n");
     918             : 
     919           1 :         CATCH_REQUIRE(c.get_root() == n);
     920           1 :     }
     921           4 :     CATCH_END_SECTION()
     922             : 
     923           4 :     CATCH_START_SECTION("attempt to call a function with a missing argument")
     924             :     {
     925           1 :         std::stringstream ss;
     926             :         ss << "/* testing user defined functions */\n"
     927             :            << "body { color : desaturate( white ) }\n"
     928           1 :            << "/* @preserver test \"Compile Invalid Functions\" */\n";
     929           3 :         csspp::position pos("test.css");
     930           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     931             : 
     932           2 :         csspp::parser p(l);
     933             : 
     934           1 :         csspp::node::pointer_t n(p.stylesheet());
     935             : 
     936             :         // no errors so far
     937           1 :         VERIFY_ERRORS("");
     938             : 
     939           1 :         csspp::compiler c;
     940           1 :         c.set_root(n);
     941           1 :         c.set_date_time_variables(csspp_test::get_now());
     942           1 :         c.clear_paths();
     943           1 :         c.add_path(csspp_test::get_script_path());
     944           1 :         c.add_path(csspp_test::get_version_script_path());
     945             : 
     946           1 :         c.compile(false);
     947             : 
     948             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     949             : 
     950             :         // no error left over
     951           1 :         VERIFY_ERRORS("scripts/system/functions.scss(39): error: missing function variable named \"percent\" when calling desaturate();.\n");
     952             : 
     953           1 :         CATCH_REQUIRE(c.get_root() == n);
     954           1 :     }
     955           4 :     CATCH_END_SECTION()
     956             : 
     957           4 :     CATCH_START_SECTION("@return is empty")
     958             :     {
     959           1 :         std::stringstream ss;
     960             :         ss << "/* testing user defined functions */\n"
     961             :            << "@mixin zzz_my_func() { @return { nothing; } }\n"
     962             :            << "body { color : zzz_my_func( ) }\n"
     963           1 :            << "/* @preserver test \"Compile Invalid Functions\" */\n";
     964           3 :         csspp::position pos("test.css");
     965           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
     966             : 
     967           2 :         csspp::parser p(l);
     968             : 
     969           1 :         csspp::node::pointer_t n(p.stylesheet());
     970             : 
     971             :         // no errors so far
     972           1 :         VERIFY_ERRORS("");
     973             : 
     974           1 :         csspp::compiler c;
     975           1 :         c.set_root(n);
     976           1 :         c.set_date_time_variables(csspp_test::get_now());
     977           1 :         c.clear_paths();
     978           1 :         c.add_path(csspp_test::get_script_path());
     979           1 :         c.add_path(csspp_test::get_version_script_path());
     980             : 
     981           1 :         c.compile(false);
     982             : 
     983             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
     984             : 
     985             :         // no error left over
     986           1 :         VERIFY_ERRORS("test.css(2): error: @return must be followed by a valid expression.\n");
     987             : 
     988           1 :         CATCH_REQUIRE(c.get_root() == n);
     989           1 :     }
     990           4 :     CATCH_END_SECTION()
     991             : 
     992           4 :     CATCH_START_SECTION("@return with an invalid expression")
     993             :     {
     994           1 :         std::stringstream ss;
     995             :         ss << "/* testing user defined functions */\n"
     996             :            << "@mixin zzz_my_func() { @return -; }\n"
     997             :            << "body { color : zzz_my_func( ) }\n"
     998           1 :            << "/* @preserver test \"Compile Invalid Functions\" */\n";
     999           3 :         csspp::position pos("test.css");
    1000           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1001             : 
    1002           2 :         csspp::parser p(l);
    1003             : 
    1004           1 :         csspp::node::pointer_t n(p.stylesheet());
    1005             : 
    1006             :         // no errors so far
    1007           1 :         VERIFY_ERRORS("");
    1008             : 
    1009           1 :         csspp::compiler c;
    1010           1 :         c.set_root(n);
    1011           1 :         c.set_date_time_variables(csspp_test::get_now());
    1012           1 :         c.clear_paths();
    1013           1 :         c.add_path(csspp_test::get_script_path());
    1014           1 :         c.add_path(csspp_test::get_version_script_path());
    1015             : 
    1016           1 :         c.compile(false);
    1017             : 
    1018             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1019             : 
    1020             :         // no error left over
    1021           1 :         VERIFY_ERRORS("test.css(2): error: unsupported type EOF_TOKEN as a unary expression token.\n");
    1022             : 
    1023           1 :         CATCH_REQUIRE(c.get_root() == n);
    1024           1 :     }
    1025           4 :     CATCH_END_SECTION()
    1026             : 
    1027           4 :     VERIFY_ERRORS("");
    1028           4 : }
    1029             : 
    1030           1 : CATCH_TEST_CASE("Check all argify", "[compiler] [stylesheet]")
    1031             : {
    1032             :     // valid argify with/without spaces
    1033             :     {
    1034           1 :         std::stringstream ss;
    1035             :         ss << "a,b{color:red}\n"
    1036             :            << "a, b{color:hsl(0,100%,50%)}\n"
    1037             :            << "a,b ,c{color:rgb(255,0,0)}\n"
    1038             :            << "a , b,c{color:hsla(0,100%,50%,1)}\n"
    1039             :            << "a{color:rgba(255,0,0,1)}\n"
    1040             :            << "a {color:red}\n"
    1041           1 :            << "a,b {color:red}\n"
    1042             :            ;
    1043           3 :         csspp::position pos("test.css");
    1044           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1045             : 
    1046           2 :         csspp::parser p(l);
    1047             : 
    1048           1 :         csspp::node::pointer_t n(p.stylesheet());
    1049             : 
    1050             :         // no errors so far
    1051           1 :         VERIFY_ERRORS("");
    1052             : 
    1053           1 :         csspp::compiler c;
    1054           1 :         c.set_root(n);
    1055           1 :         c.clear_paths();
    1056           1 :         c.add_path(csspp_test::get_script_path());
    1057           1 :         c.add_path(csspp_test::get_version_script_path());
    1058             : 
    1059           1 :         c.compile(true);
    1060             : 
    1061             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1062             : 
    1063           1 :         std::stringstream out;
    1064           1 :         out << *n;
    1065           1 :         VERIFY_TREES(out.str(),
    1066             : 
    1067             : "LIST\n"
    1068             : "  COMPONENT_VALUE\n"
    1069             : "    ARG\n"
    1070             : "      IDENTIFIER \"a\"\n"
    1071             : "    ARG\n"
    1072             : "      IDENTIFIER \"b\"\n"
    1073             : "    OPEN_CURLYBRACKET B:true\n"
    1074             : "      DECLARATION \"color\"\n"
    1075             : "        ARG\n"
    1076             : "          COLOR H:ff0000ff\n"
    1077             : "  COMPONENT_VALUE\n"
    1078             : "    ARG\n"
    1079             : "      IDENTIFIER \"a\"\n"
    1080             : "    ARG\n"
    1081             : "      IDENTIFIER \"b\"\n"
    1082             : "    OPEN_CURLYBRACKET B:true\n"
    1083             : "      DECLARATION \"color\"\n"
    1084             : "        ARG\n"
    1085             : "          COLOR H:ff0000ff\n"
    1086             : "  COMPONENT_VALUE\n"
    1087             : "    ARG\n"
    1088             : "      IDENTIFIER \"a\"\n"
    1089             : "    ARG\n"
    1090             : "      IDENTIFIER \"b\"\n"
    1091             : "    ARG\n"
    1092             : "      IDENTIFIER \"c\"\n"
    1093             : "    OPEN_CURLYBRACKET B:true\n"
    1094             : "      DECLARATION \"color\"\n"
    1095             : "        ARG\n"
    1096             : "          COLOR H:ff0000ff\n"
    1097             : "  COMPONENT_VALUE\n"
    1098             : "    ARG\n"
    1099             : "      IDENTIFIER \"a\"\n"
    1100             : "    ARG\n"
    1101             : "      IDENTIFIER \"b\"\n"
    1102             : "    ARG\n"
    1103             : "      IDENTIFIER \"c\"\n"
    1104             : "    OPEN_CURLYBRACKET B:true\n"
    1105             : "      DECLARATION \"color\"\n"
    1106             : "        ARG\n"
    1107             : "          COLOR H:ff0000ff\n"
    1108             : "  COMPONENT_VALUE\n"
    1109             : "    ARG\n"
    1110             : "      IDENTIFIER \"a\"\n"
    1111             : "    OPEN_CURLYBRACKET B:true\n"
    1112             : "      DECLARATION \"color\"\n"
    1113             : "        ARG\n"
    1114             : "          COLOR H:ff0000ff\n"
    1115             : "  COMPONENT_VALUE\n"
    1116             : "    ARG\n"
    1117             : "      IDENTIFIER \"a\"\n"
    1118             : "    OPEN_CURLYBRACKET B:true\n"
    1119             : "      DECLARATION \"color\"\n"
    1120             : "        ARG\n"
    1121             : "          COLOR H:ff0000ff\n"
    1122             : "  COMPONENT_VALUE\n"
    1123             : "    ARG\n"
    1124             : "      IDENTIFIER \"a\"\n"
    1125             : "    ARG\n"
    1126             : "      IDENTIFIER \"b\"\n"
    1127             : "    OPEN_CURLYBRACKET B:true\n"
    1128             : "      DECLARATION \"color\"\n"
    1129             : "        ARG\n"
    1130             : "          COLOR H:ff0000ff\n"
    1131             : 
    1132             :             );
    1133             : 
    1134             :         // no error left over
    1135           1 :         VERIFY_ERRORS("");
    1136             : 
    1137           1 :         CATCH_REQUIRE(c.get_root() == n);
    1138           1 :     }
    1139             : 
    1140             :     // now check declarations with multiple entries like text-shadow
    1141             :     {
    1142           1 :         std::stringstream ss;
    1143             :         ss << "a, b\n"
    1144             :            << "{\n"
    1145             :            << "  text-shadow: 1px 3px 2px #f0e933, 7px 1px 5px #88ff45;\n"
    1146             :            << "  box-shadow: 2.5em 4.3em 1.25em #ffee33, 7.3px 1.25px 4.11px #88ff55, 3.32em 2.45em 4.11em #ee5599;\n"
    1147           1 :            << "}\n";
    1148           3 :         csspp::position pos("test.css");
    1149           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1150             : 
    1151           2 :         csspp::parser p(l);
    1152             : 
    1153           1 :         csspp::node::pointer_t n(p.stylesheet());
    1154             : 
    1155             :         // no errors so far
    1156           1 :         VERIFY_ERRORS("");
    1157             : 
    1158           1 :         csspp::compiler c;
    1159           1 :         c.set_root(n);
    1160           1 :         c.clear_paths();
    1161           1 :         c.add_path(csspp_test::get_script_path());
    1162           1 :         c.add_path(csspp_test::get_version_script_path());
    1163             : 
    1164           1 :         c.compile(true);
    1165             : 
    1166             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1167             : 
    1168           1 :         std::stringstream out;
    1169           1 :         out << *n;
    1170           1 :         VERIFY_TREES(out.str(),
    1171             : 
    1172             : "LIST\n"
    1173             : "  COMPONENT_VALUE\n"
    1174             : "    ARG\n"
    1175             : "      IDENTIFIER \"a\"\n"
    1176             : "    ARG\n"
    1177             : "      IDENTIFIER \"b\"\n"
    1178             : "    OPEN_CURLYBRACKET B:true\n"
    1179             : "      LIST\n"
    1180             : "        DECLARATION \"text-shadow\"\n"
    1181             : "          ARG\n"
    1182             : "            INTEGER \"px\" I:1\n"
    1183             : "            WHITESPACE\n"
    1184             : "            INTEGER \"px\" I:3\n"
    1185             : "            WHITESPACE\n"
    1186             : "            INTEGER \"px\" I:2\n"
    1187             : "            WHITESPACE\n"
    1188             : "            COLOR H:ff33e9f0\n"
    1189             : "          ARG\n"
    1190             : "            INTEGER \"px\" I:7\n"
    1191             : "            WHITESPACE\n"
    1192             : "            INTEGER \"px\" I:1\n"
    1193             : "            WHITESPACE\n"
    1194             : "            INTEGER \"px\" I:5\n"
    1195             : "            WHITESPACE\n"
    1196             : "            COLOR H:ff45ff88\n"
    1197             : "        DECLARATION \"box-shadow\"\n"
    1198             : "          ARG\n"
    1199             : "            DECIMAL_NUMBER \"em\" D:2.5\n"
    1200             : "            WHITESPACE\n"
    1201             : "            DECIMAL_NUMBER \"em\" D:4.3\n"
    1202             : "            WHITESPACE\n"
    1203             : "            DECIMAL_NUMBER \"em\" D:1.25\n"
    1204             : "            WHITESPACE\n"
    1205             : "            COLOR H:ff33eeff\n"
    1206             : "          ARG\n"
    1207             : "            DECIMAL_NUMBER \"px\" D:7.3\n"
    1208             : "            WHITESPACE\n"
    1209             : "            DECIMAL_NUMBER \"px\" D:1.25\n"
    1210             : "            WHITESPACE\n"
    1211             : "            DECIMAL_NUMBER \"px\" D:4.11\n"
    1212             : "            WHITESPACE\n"
    1213             : "            COLOR H:ff55ff88\n"
    1214             : "          ARG\n"
    1215             : "            DECIMAL_NUMBER \"em\" D:3.32\n"
    1216             : "            WHITESPACE\n"
    1217             : "            DECIMAL_NUMBER \"em\" D:2.45\n"
    1218             : "            WHITESPACE\n"
    1219             : "            DECIMAL_NUMBER \"em\" D:4.11\n"
    1220             : "            WHITESPACE\n"
    1221             : "            COLOR H:ff9955ee\n"
    1222             : 
    1223             :             );
    1224             : 
    1225             :         // no error left over
    1226           1 :         VERIFY_ERRORS("");
    1227             : 
    1228           1 :         CATCH_REQUIRE(c.get_root() == n);
    1229           1 :     }
    1230           1 : }
    1231             : 
    1232           1 : CATCH_TEST_CASE("Invalid arguments", "[compiler] [invalid]")
    1233             : {
    1234             :     // A starting comma is illegal
    1235             :     {
    1236           1 :         std::stringstream ss;
    1237           1 :         ss << ",a{color:red}\n";
    1238           3 :         csspp::position pos("test.css");
    1239           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1240             : 
    1241           2 :         csspp::parser p(l);
    1242             : 
    1243           1 :         csspp::node::pointer_t n(p.stylesheet());
    1244             : 
    1245             :         // no errors so far
    1246           1 :         VERIFY_ERRORS("");
    1247             : 
    1248           1 :         csspp::compiler c;
    1249           1 :         c.set_root(n);
    1250           1 :         c.clear_paths();
    1251           1 :         c.add_path(csspp_test::get_script_path());
    1252           1 :         c.add_path(csspp_test::get_version_script_path());
    1253             : 
    1254           1 :         c.compile(true);
    1255             : 
    1256             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1257             : 
    1258             :         // no error left over
    1259           1 :         VERIFY_ERRORS("test.css(1): error: dangling comma at the beginning of a list of arguments or selectors.\n");
    1260             : 
    1261           1 :         CATCH_REQUIRE(c.get_root() == n);
    1262           1 :     }
    1263             : 
    1264             :     // An ending comma is illegal
    1265             :     {
    1266           1 :         std::stringstream ss;
    1267           1 :         ss << "a,{color:red}\n";
    1268           3 :         csspp::position pos("test.css");
    1269           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1270             : 
    1271           2 :         csspp::parser p(l);
    1272             : 
    1273           1 :         csspp::node::pointer_t n(p.stylesheet());
    1274             : 
    1275             :         // no errors so far
    1276           1 :         VERIFY_ERRORS("");
    1277             : 
    1278           1 :         csspp::compiler c;
    1279           1 :         c.set_root(n);
    1280           1 :         c.clear_paths();
    1281           1 :         c.add_path(csspp_test::get_script_path());
    1282           1 :         c.add_path(csspp_test::get_version_script_path());
    1283             : 
    1284           1 :         c.compile(true);
    1285             : 
    1286             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1287             : 
    1288             :         // no error left over
    1289           1 :         VERIFY_ERRORS("test.css(1): error: dangling comma at the end of a list of arguments or selectors.\n");
    1290             : 
    1291           1 :         CATCH_REQUIRE(c.get_root() == n);
    1292           1 :     }
    1293             : 
    1294             :     // Two commas in a row is illegal
    1295             :     {
    1296           1 :         std::stringstream ss;
    1297           1 :         ss << "a,,b{color:red}\n";
    1298           3 :         csspp::position pos("test.css");
    1299           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1300             : 
    1301           2 :         csspp::parser p(l);
    1302             : 
    1303           1 :         csspp::node::pointer_t n(p.stylesheet());
    1304             : 
    1305             :         // no errors so far
    1306           1 :         VERIFY_ERRORS("");
    1307             : 
    1308           1 :         csspp::compiler c;
    1309           1 :         c.set_root(n);
    1310           1 :         c.clear_paths();
    1311           1 :         c.add_path(csspp_test::get_script_path());
    1312           1 :         c.add_path(csspp_test::get_version_script_path());
    1313             : 
    1314           1 :         c.compile(true);
    1315             : 
    1316             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1317             : 
    1318             :         // no error left over
    1319           1 :         VERIFY_ERRORS("test.css(1): error: two commas in a row are invalid in a list of arguments or selectors.\n");
    1320             : 
    1321           1 :         CATCH_REQUIRE(c.get_root() == n);
    1322           1 :     }
    1323             : 
    1324             :     // Just a comma is illegal
    1325             :     {
    1326           1 :         std::stringstream ss;
    1327           1 :         ss << ",{color:red}\n";
    1328           3 :         csspp::position pos("test.css");
    1329           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1330             : 
    1331           2 :         csspp::parser p(l);
    1332             : 
    1333           1 :         csspp::node::pointer_t n(p.stylesheet());
    1334             : 
    1335             :         // no errors so far
    1336           1 :         VERIFY_ERRORS("");
    1337             : 
    1338           1 :         csspp::compiler c;
    1339           1 :         c.set_root(n);
    1340           1 :         c.clear_paths();
    1341           1 :         c.add_path(csspp_test::get_script_path());
    1342           1 :         c.add_path(csspp_test::get_version_script_path());
    1343             : 
    1344           1 :         c.compile(true);
    1345             : 
    1346             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1347             : 
    1348             :         // no error left over
    1349           1 :         VERIFY_ERRORS("test.css(1): error: dangling comma at the beginning of a list of arguments or selectors.\n");
    1350             : 
    1351           1 :         CATCH_REQUIRE(c.get_root() == n);
    1352           1 :     }
    1353             : 
    1354             :     // A repeated hash
    1355             :     {
    1356           1 :         std::stringstream ss;
    1357           1 :         ss << "#color div #color { color : red }";
    1358           3 :         csspp::position pos("test.css");
    1359           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1360             : 
    1361           2 :         csspp::parser p(l);
    1362             : 
    1363           1 :         csspp::node::pointer_t n(p.stylesheet());
    1364             : 
    1365             :         // no errors so far
    1366           1 :         VERIFY_ERRORS("");
    1367             : 
    1368           1 :         csspp::compiler c;
    1369           1 :         c.set_root(n);
    1370           1 :         c.clear_paths();
    1371           1 :         c.add_path(csspp_test::get_script_path());
    1372           1 :         c.add_path(csspp_test::get_version_script_path());
    1373             : 
    1374           1 :         c.compile(true);
    1375             : 
    1376             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1377             : 
    1378           1 :         VERIFY_ERRORS("test.css(1): error: found #color twice in selector: \"#color div #color\".\n");
    1379             : 
    1380           1 :         CATCH_REQUIRE(c.get_root() == n);
    1381           1 :     }
    1382             : 
    1383             :     // rules with !important at the wrong place
    1384             :     {
    1385           1 :         std::stringstream ss;
    1386           1 :         ss << "div.blackness { color: !important red }";
    1387           3 :         csspp::position pos("test.css");
    1388           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1389             : 
    1390           2 :         csspp::parser p(l);
    1391             : 
    1392           1 :         csspp::node::pointer_t n(p.stylesheet());
    1393             : 
    1394             :         // no errors so far
    1395           1 :         VERIFY_ERRORS("");
    1396             : 
    1397           1 :         csspp::compiler c;
    1398           1 :         c.set_root(n);
    1399           1 :         c.set_date_time_variables(csspp_test::get_now());
    1400           1 :         c.clear_paths();
    1401           1 :         c.add_path(csspp_test::get_script_path());
    1402           1 :         c.add_path(csspp_test::get_version_script_path());
    1403             : 
    1404           1 :         c.compile(false);
    1405             : 
    1406             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1407             : 
    1408           1 :         VERIFY_ERRORS("test.css(1): warning: A special flag, !important in this case, must only appear at the end of a declaration.\n");
    1409             : 
    1410           1 :         std::stringstream out;
    1411           1 :         out << *n;
    1412           1 :         VERIFY_TREES(out.str(),
    1413             : 
    1414             : "LIST\n"
    1415             : + csspp_test::get_default_variables() +
    1416             : "  COMPONENT_VALUE\n"
    1417             : "    ARG\n"
    1418             : "      IDENTIFIER \"div\"\n"
    1419             : "      PERIOD\n"
    1420             : "      IDENTIFIER \"blackness\"\n"
    1421             : "    OPEN_CURLYBRACKET B:true\n"
    1422             : "      DECLARATION \"color\" F:important\n"
    1423             : "        ARG\n"
    1424             : "          COLOR H:ff0000ff\n"
    1425             : + csspp_test::get_close_comment(true)
    1426             : 
    1427             :             );
    1428             : 
    1429             :         // no error left over
    1430           1 :         VERIFY_ERRORS("");
    1431             : 
    1432           1 :         CATCH_REQUIRE(c.get_root() == n);
    1433           1 :     }
    1434             : 
    1435             :     // no error left over
    1436           1 :     VERIFY_ERRORS("");
    1437           1 : }
    1438             : 
    1439           1 : CATCH_TEST_CASE("Selector attribute tests", "[compiler] [stylesheet] [attribute]")
    1440             : {
    1441           1 :     char const * op[] =
    1442             :     {
    1443             :         "=",    "EQUAL",
    1444             :         "~=",   "INCLUDE_MATCH",
    1445             :         "^=",   "PREFIX_MATCH",
    1446             :         "$=",   "SUFFIX_MATCH",
    1447             :         "*=",   "SUBSTRING_MATCH",
    1448             :         "|=",   "DASH_MATCH"
    1449             :     };
    1450           1 :     char const * val[] =
    1451             :     {
    1452             :         "c",        "IDENTIFIER \"c\"",
    1453             :         "' c '",    "STRING \" c \"",
    1454             :         "123",      "INTEGER \"\" I:123",
    1455             :         "1.23",     "DECIMAL_NUMBER \"\" D:1.23"
    1456             :     };
    1457             : 
    1458             :     // TODO: rewrite that one to use a few less lines
    1459           7 :     for(size_t i(0); i < sizeof(op) / sizeof(op[0]); i += 2)
    1460             :     {
    1461          30 :         for(size_t j(0); j < sizeof(val) / sizeof(val[0]); j += 2)
    1462             :         {
    1463         408 :             for(size_t k(0); k < (1 << 4); ++k)
    1464             :             {
    1465             :                 // a[b op c | 'str' | 123 | 1.23] {color:red}
    1466         384 :                 std::stringstream ss;
    1467         384 :                 ss << "a[";
    1468         384 :                 if((k & (1 << 0)) != 0)
    1469             :                 {
    1470         192 :                     ss << " ";
    1471             :                 }
    1472         384 :                 ss << "b";
    1473         384 :                 if((k & (1 << 1)) != 0)
    1474             :                 {
    1475         192 :                     ss << " ";
    1476             :                 }
    1477         384 :                 ss << op[i];
    1478         384 :                 if((k & (1 << 2)) != 0)
    1479             :                 {
    1480         192 :                     ss << " ";
    1481             :                 }
    1482         384 :                 ss << val[j];
    1483         384 :                 if((k & (1 << 3)) != 0)
    1484             :                 {
    1485         192 :                     ss << " ";
    1486             :                 }
    1487             :                 ss << "]"
    1488         768 :                    << (rand() % 2 == 0 ? " " : "")
    1489             :                    << "{"
    1490         768 :                    << (rand() % 2 == 0 ? " " : "")
    1491             :                    << "color:"
    1492         768 :                    << (rand() % 2 == 0 ? "rgb(255,0,0)" : "rgba(255,0,0,1.0)")
    1493         768 :                    << (rand() % 2 == 0 ? " " : "")
    1494         384 :                    << "}\n";
    1495        1152 :                 csspp::position pos("test.css");
    1496         384 :                 csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1497             : 
    1498         768 :                 csspp::parser p(l);
    1499             : 
    1500         384 :                 csspp::node::pointer_t n(p.stylesheet());
    1501             : 
    1502             :                 // no errors so far
    1503         384 :                 VERIFY_ERRORS("");
    1504             : 
    1505         384 :                 csspp::compiler c;
    1506         384 :                 c.set_root(n);
    1507         384 :                 c.clear_paths();
    1508         384 :                 c.add_path(csspp_test::get_script_path());
    1509         384 :                 c.add_path(csspp_test::get_version_script_path());
    1510             : 
    1511         384 :                 c.compile(true);
    1512             : 
    1513             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1514             : 
    1515         384 :                 VERIFY_ERRORS("");
    1516             : 
    1517         384 :                 std::stringstream out;
    1518         384 :                 out << *n;
    1519         384 :                 std::stringstream expected;
    1520             :                 expected <<
    1521             :                         "LIST\n"
    1522             :                         "  COMPONENT_VALUE\n"
    1523             :                         "    ARG\n"
    1524             :                         "      IDENTIFIER \"a\"\n"
    1525             :                         "      OPEN_SQUAREBRACKET\n"
    1526             :                         "        IDENTIFIER \"b\"\n"
    1527         384 :                      << "        " << op[i + 1] << "\n"
    1528         384 :                      << "        " << val[j + 1] << "\n"
    1529             :                         "    OPEN_CURLYBRACKET B:true\n"
    1530             :                         "      DECLARATION \"color\"\n"
    1531             :                         "        ARG\n"
    1532         384 :                         "          COLOR H:ff0000ff\n"
    1533             :                     ;
    1534         384 :                 VERIFY_TREES(out.str(), expected.str());
    1535             : 
    1536         384 :                 CATCH_REQUIRE(c.get_root() == n);
    1537         384 :             }
    1538             :         }
    1539             :     }
    1540             : 
    1541             :     // a[b!=c]
    1542           5 :     for(size_t j(0); j < sizeof(val) / sizeof(val[0]); j += 2)
    1543             :     {
    1544          68 :         for(size_t k(0); k < (1 << 4); ++k)
    1545             :         {
    1546          64 :             std::stringstream ss;
    1547          64 :             ss << "a[";
    1548          64 :             if((k & (1 << 0)) != 0)
    1549             :             {
    1550          32 :                 ss << " ";
    1551             :             }
    1552          64 :             ss << "b";
    1553          64 :             if((k & (1 << 1)) != 0)
    1554             :             {
    1555          32 :                 ss << " ";
    1556             :             }
    1557          64 :             ss << "!=";
    1558          64 :             if((k & (1 << 2)) != 0)
    1559             :             {
    1560          32 :                 ss << " ";
    1561             :             }
    1562          64 :             ss << val[j];
    1563          64 :             if((k & (1 << 3)) != 0)
    1564             :             {
    1565          32 :                 ss << " ";
    1566             :             }
    1567             :             ss << "]"
    1568         128 :                << (rand() % 2 == 0 ? " " : "")
    1569             :                << "{"
    1570         128 :                << (rand() % 2 == 0 ? " " : "")
    1571             :                << "color:red"
    1572         128 :                << (rand() % 2 == 0 ? " " : "")
    1573          64 :                << "}\n";
    1574         192 :             csspp::position pos("test.css");
    1575          64 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1576             : 
    1577         128 :             csspp::parser p(l);
    1578             : 
    1579          64 :             csspp::node::pointer_t n(p.stylesheet());
    1580             : 
    1581             :             // no errors so far
    1582          64 :             VERIFY_ERRORS("");
    1583             : 
    1584          64 :             csspp::compiler c;
    1585          64 :             c.set_root(n);
    1586          64 :             c.clear_paths();
    1587          64 :             c.add_path(csspp_test::get_script_path());
    1588          64 :             c.add_path(csspp_test::get_version_script_path());
    1589             : 
    1590          64 :             c.compile(true);
    1591             : 
    1592             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1593             : 
    1594          64 :             VERIFY_ERRORS("");
    1595             : 
    1596          64 :             std::stringstream out;
    1597          64 :             out << *n;
    1598          64 :             std::stringstream expected;
    1599             :             expected <<
    1600             :                     "LIST\n"
    1601             :                     "  COMPONENT_VALUE\n"
    1602             :                     "    ARG\n"
    1603             :                     "      IDENTIFIER \"a\"\n"
    1604             :                     "      COLON\n"
    1605             :                     "      FUNCTION \"not\"\n"
    1606             :                     "        OPEN_SQUAREBRACKET\n"
    1607             :                     "          IDENTIFIER \"b\"\n"
    1608             :                     "          EQUAL\n"
    1609          64 :                     "          " << val[j + 1] << "\n"
    1610             :                     "    OPEN_CURLYBRACKET B:true\n"
    1611             :                     "      DECLARATION \"color\"\n"
    1612             :                     "        ARG\n"
    1613          64 :                     "          COLOR H:ff0000ff\n"
    1614             :                 ;
    1615          64 :             VERIFY_TREES(out.str(), expected.str());
    1616             : 
    1617          64 :             CATCH_REQUIRE(c.get_root() == n);
    1618          64 :         }
    1619             :     }
    1620             : 
    1621             :     // Test with just 'b' and various spaces combinations
    1622           5 :     for(size_t k(0); k < (1 << 2); ++k)
    1623             :     {
    1624             :         // a[b] {color:red}
    1625           4 :         std::stringstream ss;
    1626           4 :         ss << "a[";
    1627           4 :         if((k & (1 << 0)) != 0)
    1628             :         {
    1629           2 :             ss << " ";
    1630             :         }
    1631           4 :         ss << "b";
    1632           4 :         if((k & (1 << 1)) != 0)
    1633             :         {
    1634           2 :             ss << " ";
    1635             :         }
    1636             :         ss << "]"
    1637           8 :            << (rand() % 2 == 0 ? " " : "")
    1638             :            << "{"
    1639           8 :            << (rand() % 2 == 0 ? " " : "")
    1640             :            << "color:red"
    1641           8 :            << (rand() % 2 == 0 ? " " : "")
    1642           4 :            << "}\n";
    1643          12 :         csspp::position pos("test.css");
    1644           4 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1645             : 
    1646           8 :         csspp::parser p(l);
    1647             : 
    1648           4 :         csspp::node::pointer_t n(p.stylesheet());
    1649             : 
    1650             :         // no errors so far
    1651           4 :         VERIFY_ERRORS("");
    1652             : 
    1653           4 :         csspp::compiler c;
    1654           4 :         c.set_root(n);
    1655           4 :         c.clear_paths();
    1656           4 :         c.add_path(csspp_test::get_script_path());
    1657           4 :         c.add_path(csspp_test::get_version_script_path());
    1658             : 
    1659           4 :         c.compile(true);
    1660             : 
    1661             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1662             : 
    1663           4 :         VERIFY_ERRORS("");
    1664             : 
    1665           4 :         std::stringstream out;
    1666           4 :         out << *n;
    1667           4 :         std::stringstream expected;
    1668             :         expected <<
    1669             :                 "LIST\n"
    1670             :                 "  COMPONENT_VALUE\n"
    1671             :                 "    ARG\n"
    1672             :                 "      IDENTIFIER \"a\"\n"
    1673             :                 "      OPEN_SQUAREBRACKET\n"
    1674             :                 "        IDENTIFIER \"b\"\n"
    1675             :                 "    OPEN_CURLYBRACKET B:true\n"
    1676             :                 "      DECLARATION \"color\"\n"
    1677             :                 "        ARG\n"
    1678           4 :                 "          COLOR H:ff0000ff\n"
    1679             :             ;
    1680           4 :         VERIFY_TREES(out.str(), expected.str());
    1681             : 
    1682           4 :         CATCH_REQUIRE(c.get_root() == n);
    1683           4 :     }
    1684           1 : }
    1685             : 
    1686           6 : CATCH_TEST_CASE("Invalid attributes", "[compiler] [invalid]")
    1687             : {
    1688             :     // attribute name cannot be an integer, decimal number, opening
    1689             :     // brackets or parenthesis, delimiter, etc. only an identifier
    1690           6 :     CATCH_START_SECTION("Missing operator or value")
    1691             :     {
    1692           1 :         char const * invalid_value[] =
    1693             :         {
    1694             :             "123",
    1695             :             "1.23",
    1696             :             "'1.23'",
    1697             :             "1.23%",
    1698             :             "(b)",
    1699             :             "[b]",
    1700             :             "{b}",
    1701             :             "+b",
    1702             :             //"@b",
    1703             :             //"<!--",
    1704             :             //"-->",
    1705             :             //")",
    1706             :             //"}",
    1707             :             ",b,",
    1708             :             "/* @preserve this comment */",
    1709             :             "|=b",
    1710             :             "/b",
    1711             :             "$ b",
    1712             :             "=b",
    1713             :             "!b",
    1714             :             "b(1)",
    1715             :             ">b",
    1716             :             "#123",
    1717             :             "~=b",
    1718             :             "*b",
    1719             :             ".top",
    1720             :             "%name",
    1721             :             "~b",
    1722             :             "&b",
    1723             :             "|b",
    1724             :             //";b",
    1725             :         };
    1726             : 
    1727          26 :         for(auto iv : invalid_value)
    1728             :         {
    1729          25 :             std::stringstream ss;
    1730          25 :             ss << "a[" << iv << "]{color:red}\n";
    1731          75 :             csspp::position pos("test.css");
    1732             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    1733          25 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1734             : 
    1735          50 :             csspp::parser p(l);
    1736             : 
    1737          25 :             csspp::node::pointer_t n(p.stylesheet());
    1738             : 
    1739             :             // no errors so far
    1740          25 :             VERIFY_ERRORS("");
    1741             : 
    1742          25 :             csspp::compiler c;
    1743          25 :             c.set_root(n);
    1744          25 :             c.clear_paths();
    1745          25 :             c.add_path(csspp_test::get_script_path());
    1746          25 :             c.add_path(csspp_test::get_version_script_path());
    1747             : 
    1748          25 :             c.compile(true);
    1749             : 
    1750             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1751             : 
    1752          25 :             VERIFY_ERRORS("test.css(1): error: an attribute selector expects to first find an identifier.\n");
    1753             : 
    1754          25 :             CATCH_REQUIRE(c.get_root() == n);
    1755          25 :         }
    1756             :     }
    1757           6 :     CATCH_END_SECTION()
    1758             : 
    1759             :     // attribute only accept a very few binary operators: =, |=, ~=, $=, ^=, *=
    1760             :     // anything else is an error (including another identifier)
    1761           6 :     CATCH_START_SECTION("Not an attribute operator")
    1762             :     {
    1763           1 :         char const * invalid_value[] =
    1764             :         {
    1765             :             "identifier-too",
    1766             :             "123",
    1767             :             "1.23",
    1768             :             "'1.23'",
    1769             :             "1.23%",
    1770             :             "(b)",
    1771             :             "[b]",
    1772             :             //"{b}", -- causes parser/lexer problems at this time... not too sure whether that's normal though
    1773             :             "+",
    1774             :             ",",
    1775             :             "/* @preserve this comment */",
    1776             :             "/",
    1777             :             "$",
    1778             :             "!",
    1779             :             ">",
    1780             :             ">=",
    1781             :             "<=",
    1782             :             "<",
    1783             :             ":=",
    1784             :             "?",
    1785             :             "&&",
    1786             :             "#123",
    1787             :             "*",
    1788             :             "**",
    1789             :             ".top",
    1790             :             "%name",
    1791             :             "~",
    1792             :             "&",
    1793             :             "|",
    1794             :             "||"
    1795             :         };
    1796             : 
    1797          30 :         for(auto iv : invalid_value)
    1798             :         {
    1799          29 :             std::stringstream ss;
    1800          29 :             ss << "a[b " << iv << " c]{color:red}\n";
    1801          87 :             csspp::position pos("test.css");
    1802             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    1803          29 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1804             : 
    1805          58 :             csspp::parser p(l);
    1806             : 
    1807          29 :             csspp::node::pointer_t n(p.stylesheet());
    1808             : 
    1809             :             // no errors so far
    1810          29 :             VERIFY_ERRORS("");
    1811             : 
    1812          29 :             csspp::compiler c;
    1813          29 :             c.set_root(n);
    1814             : 
    1815          29 :             c.compile(true);
    1816             : 
    1817             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1818             : 
    1819          29 :             VERIFY_ERRORS("test.css(1): error: expected attribute operator missing, supported operators are '=', '!=', '~=', '^=', '$=', '*=', and '|='.\n");
    1820             : 
    1821          29 :             CATCH_REQUIRE(c.get_root() == n);
    1822          29 :         }
    1823             :     }
    1824           6 :     CATCH_END_SECTION()
    1825             : 
    1826             :     // attribute and a binary operators: =, |=, ~=, $=, ^=, *=
    1827             :     // not followed by any value
    1828           6 :     CATCH_START_SECTION("Valid operators, missing right hand side value")
    1829             :     {
    1830           1 :         char const * invalid_value[] =
    1831             :         {
    1832             :             "=",
    1833             :             " =",
    1834             :             "= ",
    1835             :             " = ",
    1836             :             "!=",
    1837             :             " !=",
    1838             :             "!= ",
    1839             :             " != ",
    1840             :             "|=",
    1841             :             " |=",
    1842             :             "|= ",
    1843             :             " |= ",
    1844             :             "~=",
    1845             :             " ~=",
    1846             :             "~= ",
    1847             :             " ~= ",
    1848             :             "$=",
    1849             :             " $=",
    1850             :             "$= ",
    1851             :             " $= ",
    1852             :             "^=",
    1853             :             " ^=",
    1854             :             "^= ",
    1855             :             " ^= ",
    1856             :             "*=",
    1857             :             " *=",
    1858             :             "*= ",
    1859             :             " *= ",
    1860             :         };
    1861             : 
    1862          29 :         for(auto iv : invalid_value)
    1863             :         {
    1864          28 :             std::stringstream ss;
    1865          28 :             ss << "a[b" << iv << "]{color:red}\n";
    1866          84 :             csspp::position pos("test.css");
    1867             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    1868          28 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1869             : 
    1870          56 :             csspp::parser p(l);
    1871             : 
    1872          28 :             csspp::node::pointer_t n(p.stylesheet());
    1873             : 
    1874             :             // no errors so far
    1875          28 :             VERIFY_ERRORS("");
    1876             : 
    1877          28 :             csspp::compiler c;
    1878          28 :             c.set_root(n);
    1879             : 
    1880          28 :             c.compile(true);
    1881             : 
    1882             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1883             : 
    1884          28 :             VERIFY_ERRORS("test.css(1): error: the attribute selector is expected to be an IDENTIFIER optionally followed by an operator and a value.\n");
    1885             : 
    1886          28 :             CATCH_REQUIRE(c.get_root() == n);
    1887          28 :         }
    1888             :     }
    1889           6 :     CATCH_END_SECTION()
    1890             : 
    1891             :     // attribute value can only be identifier, string, integer,
    1892             :     // and decimal number
    1893           6 :     CATCH_START_SECTION("Valid operators, invalid right hand side value")
    1894             :     {
    1895           1 :         char const * invalid_value[] =
    1896             :         {
    1897             :             "1.23%",
    1898             :             "(b)",
    1899             :             "[b]",
    1900             :             "{b}",
    1901             :             "+",
    1902             :             //"@b",
    1903             :             //"<!--",
    1904             :             //"-->",
    1905             :             //")",
    1906             :             //"}",
    1907             :             ",",
    1908             :             "/* @preserve this comment */",
    1909             :             "|=",
    1910             :             "/",
    1911             :             "$",
    1912             :             //"=",
    1913             :             //"!",
    1914             :             ">",
    1915             :             "#123",
    1916             :             "~=",
    1917             :             "*",
    1918             :             ".top",
    1919             :             "%name",
    1920             :             "~",
    1921             :             "&",
    1922             :             "|",
    1923             :             //";b",
    1924             :         };
    1925           1 :         char const *op[] =
    1926             :         {
    1927             :             "=",
    1928             :             "|=",
    1929             :             "~=",
    1930             :             "$=",
    1931             :             "^=",
    1932             :             "*="
    1933             :         };
    1934             : 
    1935          20 :         for(auto iv : invalid_value)
    1936             :         {
    1937          19 :             std::stringstream ss;
    1938          19 :             ss << "a[b" << op[rand() % 6] << iv << "]{color:red}\n";
    1939          57 :             csspp::position pos("test.css");
    1940             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    1941          19 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1942             : 
    1943          38 :             csspp::parser p(l);
    1944             : 
    1945          19 :             csspp::node::pointer_t n(p.stylesheet());
    1946             : 
    1947             :             // no errors so far
    1948          19 :             VERIFY_ERRORS("");
    1949             : 
    1950          19 :             csspp::compiler c;
    1951          19 :             c.set_root(n);
    1952             : 
    1953          19 :             c.compile(true);
    1954             : 
    1955             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1956             : 
    1957             :             // the node that caused a problem is:
    1958             :             // LIST
    1959             :             //   COMPONENT_VALUE
    1960             :             //     ARG
    1961             :             //       ...
    1962             :             //       OPEN_SQUAREBRACKET
    1963             :             //         ...
    1964             :             //         ...
    1965             :             //         <this one>
    1966          76 :             csspp::node::pointer_t op_node(n->get_child(0)->get_child(0)->get_child(1)->get_child(2));
    1967             : 
    1968          19 :             std::stringstream errmsg;
    1969          19 :             errmsg << "test.css(1): error: attribute selector value must be an identifier, a string, an integer, or a decimal number, a "
    1970          19 :                    << op_node->get_type()
    1971          19 :                    << " is not acceptable.\n";
    1972          19 :             VERIFY_ERRORS(errmsg.str());
    1973             : 
    1974          19 :             CATCH_REQUIRE(c.get_root() == n);
    1975          19 :         }
    1976             : 
    1977          20 :         for(auto iv : invalid_value)
    1978             :         {
    1979          19 :             std::stringstream ss;
    1980          19 :             ss << "a[b" << op[rand() % 6] << " " << iv << "]{color:red}\n";
    1981          57 :             csspp::position pos("test.css");
    1982             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    1983          19 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    1984             : 
    1985          38 :             csspp::parser p(l);
    1986             : 
    1987          19 :             csspp::node::pointer_t n(p.stylesheet());
    1988             : 
    1989             :             // no errors so far
    1990          19 :             VERIFY_ERRORS("");
    1991             : 
    1992          19 :             csspp::compiler c;
    1993          19 :             c.set_root(n);
    1994             : 
    1995          19 :             c.compile(true);
    1996             : 
    1997             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    1998             : 
    1999             :             // the node that caused a problem is:
    2000             :             // LIST
    2001             :             //   COMPONENT_VALUE
    2002             :             //     ARG
    2003             :             //       ...
    2004             :             //       OPEN_SQUAREBRACKET
    2005             :             //         ...
    2006             :             //         ...
    2007             :             //         <this one>
    2008          76 :             csspp::node::pointer_t op_node(n->get_child(0)->get_child(0)->get_child(1)->get_child(2));
    2009             : 
    2010          19 :             std::stringstream errmsg;
    2011          19 :             errmsg << "test.css(1): error: attribute selector value must be an identifier, a string, an integer, or a decimal number, a "
    2012          19 :                    << op_node->get_type()
    2013          19 :                    << " is not acceptable.\n";
    2014          19 :             VERIFY_ERRORS(errmsg.str());
    2015             : 
    2016          19 :             CATCH_REQUIRE(c.get_root() == n);
    2017          19 :         }
    2018             : 
    2019          20 :         for(auto iv : invalid_value)
    2020             :         {
    2021          19 :             std::stringstream ss;
    2022          19 :             ss << "a[b" << op[rand() % 6] << iv << " ]{color:red}\n";
    2023          57 :             csspp::position pos("test.css");
    2024             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    2025          19 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2026             : 
    2027          38 :             csspp::parser p(l);
    2028             : 
    2029          19 :             csspp::node::pointer_t n(p.stylesheet());
    2030             : 
    2031             :             // no errors so far
    2032          19 :             VERIFY_ERRORS("");
    2033             : 
    2034          19 :             csspp::compiler c;
    2035          19 :             c.set_root(n);
    2036             : 
    2037          19 :             c.compile(true);
    2038             : 
    2039             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2040             : 
    2041             :             // the node that caused a problem is:
    2042             :             // LIST
    2043             :             //   COMPONENT_VALUE
    2044             :             //     ARG
    2045             :             //       ...
    2046             :             //       OPEN_SQUAREBRACKET
    2047             :             //         ...
    2048             :             //         ...
    2049             :             //         <this one>
    2050          76 :             csspp::node::pointer_t op_node(n->get_child(0)->get_child(0)->get_child(1)->get_child(2));
    2051             : 
    2052          19 :             std::stringstream errmsg;
    2053          19 :             errmsg << "test.css(1): error: attribute selector value must be an identifier, a string, an integer, or a decimal number, a "
    2054          19 :                    << op_node->get_type()
    2055          19 :                    << " is not acceptable.\n";
    2056          19 :             VERIFY_ERRORS(errmsg.str());
    2057             : 
    2058          19 :             CATCH_REQUIRE(c.get_root() == n);
    2059          19 :         }
    2060             : 
    2061          20 :         for(auto iv : invalid_value)
    2062             :         {
    2063          19 :             std::stringstream ss;
    2064          19 :             ss << "a[b" << op[rand() % 6] << " " << iv << " ]{color:red}\n";
    2065          57 :             csspp::position pos("test.css");
    2066             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    2067          19 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2068             : 
    2069          38 :             csspp::parser p(l);
    2070             : 
    2071          19 :             csspp::node::pointer_t n(p.stylesheet());
    2072             : 
    2073             :             // no errors so far
    2074          19 :             VERIFY_ERRORS("");
    2075             : 
    2076          19 :             csspp::compiler c;
    2077          19 :             c.set_root(n);
    2078             : 
    2079          19 :             c.compile(true);
    2080             : 
    2081             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2082             : 
    2083             :             // the node that caused a problem is:
    2084             :             // LIST
    2085             :             //   COMPONENT_VALUE
    2086             :             //     ARG
    2087             :             //       ...
    2088             :             //       OPEN_SQUAREBRACKET
    2089             :             //         ...
    2090             :             //         ...
    2091             :             //         <this one>
    2092          76 :             csspp::node::pointer_t op_node(n->get_child(0)->get_child(0)->get_child(1)->get_child(2));
    2093             : 
    2094          19 :             std::stringstream errmsg;
    2095          19 :             errmsg << "test.css(1): error: attribute selector value must be an identifier, a string, an integer, or a decimal number, a "
    2096          19 :                    << op_node->get_type()
    2097          19 :                    << " is not acceptable.\n";
    2098          19 :             VERIFY_ERRORS(errmsg.str());
    2099             : 
    2100          19 :             CATCH_REQUIRE(c.get_root() == n);
    2101          19 :         }
    2102             :     }
    2103           6 :     CATCH_END_SECTION()
    2104             : 
    2105             :     // attribute value can only be one token
    2106           6 :     CATCH_START_SECTION("Valid operators, right hand side value followed by something")
    2107             :     {
    2108           1 :         char const * invalid_value[] =
    2109             :         {
    2110             :             "identifier",
    2111             :             "123",
    2112             :             "1.23",
    2113             :             "'1.23'",
    2114             :             "1.23%",
    2115             :             "(b)",
    2116             :             "[b]",
    2117             :             "{b}",
    2118             :             "+",
    2119             :             //"@b",
    2120             :             //"<!--",
    2121             :             //"-->",
    2122             :             //")",
    2123             :             //"}",
    2124             :             ",",
    2125             :             "/* @preserve this comment */",
    2126             :             "|=",
    2127             :             "/",
    2128             :             "$",
    2129             :             "=",
    2130             :             //"!",
    2131             :             ">",
    2132             :             "#123",
    2133             :             "~=",
    2134             :             "*",
    2135             :             ".top",
    2136             :             "%name",
    2137             :             "~",
    2138             :             "&",
    2139             :             "|",
    2140             :             //";b",
    2141             :         };
    2142           1 :         char const *op[] =
    2143             :         {
    2144             :             "=",
    2145             :             "|=",
    2146             :             "~=",
    2147             :             "$=",
    2148             :             "^=",
    2149             :             "*="
    2150             :         };
    2151             : 
    2152          25 :         for(auto iv : invalid_value)
    2153             :         {
    2154             :             // without a space these gets glued to "c"
    2155          48 :             std::string const v(iv);
    2156          24 :             if(v == "identifier"    // "cidentifier"
    2157          23 :             || v == "123"           // "c123"
    2158          47 :             || v[0] == '(')         // "c(...)"
    2159             :             {
    2160           3 :                 continue;
    2161             :             }
    2162          21 :             std::stringstream ss;
    2163          21 :             ss << "a[b" << op[rand() % 6] << "c" << iv << "]{color:red}\n";
    2164          63 :             csspp::position pos("test.css");
    2165             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    2166          21 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2167             : 
    2168          42 :             csspp::parser p(l);
    2169             : 
    2170          21 :             csspp::node::pointer_t n(p.stylesheet());
    2171             : 
    2172             :             // no errors so far
    2173          21 :             VERIFY_ERRORS("");
    2174             : 
    2175          21 :             csspp::compiler c;
    2176          21 :             c.set_root(n);
    2177             : 
    2178          21 :             c.compile(true);
    2179             : 
    2180             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2181             : 
    2182             :             // the node that caused a problem is:
    2183             :             // LIST
    2184             :             //   COMPONENT_VALUE
    2185             :             //     ARG
    2186             :             //       ...
    2187             :             //       OPEN_SQUAREBRACKET
    2188             :             //         ...
    2189             :             //         ...
    2190             :             //         <this one>
    2191          84 :             csspp::node::pointer_t op_node(n->get_child(0)->get_child(0)->get_child(1)->get_child(3));
    2192             : 
    2193          21 :             std::stringstream errmsg;
    2194          21 :             errmsg << "test.css(1): error: attribute selector cannot be followed by more than one value, found "
    2195          21 :                    << op_node->get_type()
    2196          21 :                    << " after the value, missing quotes?\n";
    2197          21 :             VERIFY_ERRORS(errmsg.str());
    2198             : 
    2199          21 :             CATCH_REQUIRE(c.get_root() == n);
    2200          24 :         }
    2201             : 
    2202          25 :         for(auto iv : invalid_value)
    2203             :         {
    2204          24 :             std::stringstream ss;
    2205          24 :             ss << "a[b" << op[rand() % 6] << "c " << iv << "]{color:red}\n";
    2206          72 :             csspp::position pos("test.css");
    2207             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    2208          24 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2209             : 
    2210          48 :             csspp::parser p(l);
    2211             : 
    2212          24 :             csspp::node::pointer_t n(p.stylesheet());
    2213             : 
    2214             :             // no errors so far
    2215          24 :             VERIFY_ERRORS("");
    2216             : 
    2217          24 :             csspp::compiler c;
    2218          24 :             c.set_root(n);
    2219             : 
    2220          24 :             c.compile(true);
    2221             : 
    2222             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2223             : 
    2224             :             // the node that caused a problem is:
    2225             :             // LIST
    2226             :             //   COMPONENT_VALUE
    2227             :             //     ARG
    2228             :             //       ...
    2229             :             //       OPEN_SQUAREBRACKET
    2230             :             //         ...
    2231             :             //         ...
    2232             :             //         <this one>
    2233          96 :             csspp::node::pointer_t op_node(n->get_child(0)->get_child(0)->get_child(1)->get_child(3));
    2234             : 
    2235          24 :             std::stringstream errmsg;
    2236          24 :             errmsg << "test.css(1): error: attribute selector cannot be followed by more than one value, found "
    2237          24 :                    << op_node->get_type()
    2238          24 :                    << " after the value, missing quotes?\n";
    2239          24 :             VERIFY_ERRORS(errmsg.str());
    2240             : 
    2241          24 :             CATCH_REQUIRE(c.get_root() == n);
    2242          24 :         }
    2243             : 
    2244          25 :         for(auto iv : invalid_value)
    2245             :         {
    2246             :             // without a space these gets glued to "c"
    2247          48 :             std::string const v(iv);
    2248          24 :             if(v == "identifier"    // "cidentifier"
    2249          23 :             || v == "123"           // "c123"
    2250          47 :             || v[0] == '(')         // "c(...)"
    2251             :             {
    2252           3 :                 continue;
    2253             :             }
    2254          21 :             std::stringstream ss;
    2255          21 :             ss << "a[b" << op[rand() % 6] << "c" << iv << " ]{color:red}\n";
    2256          63 :             csspp::position pos("test.css");
    2257             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    2258          21 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2259             : 
    2260          42 :             csspp::parser p(l);
    2261             : 
    2262          21 :             csspp::node::pointer_t n(p.stylesheet());
    2263             : 
    2264             :             // no errors so far
    2265          21 :             VERIFY_ERRORS("");
    2266             : 
    2267          21 :             csspp::compiler c;
    2268          21 :             c.set_root(n);
    2269             : 
    2270          21 :             c.compile(true);
    2271             : 
    2272             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2273             : 
    2274             :             // the node that caused a problem is:
    2275             :             // LIST
    2276             :             //   COMPONENT_VALUE
    2277             :             //     ARG
    2278             :             //       ...
    2279             :             //       OPEN_SQUAREBRACKET
    2280             :             //         ...
    2281             :             //         ...
    2282             :             //         <this one>
    2283          84 :             csspp::node::pointer_t op_node(n->get_child(0)->get_child(0)->get_child(1)->get_child(3));
    2284             : 
    2285          21 :             std::stringstream errmsg;
    2286          21 :             errmsg << "test.css(1): error: attribute selector cannot be followed by more than one value, found "
    2287          21 :                    << op_node->get_type()
    2288          21 :                    << " after the value, missing quotes?\n";
    2289          21 :             VERIFY_ERRORS(errmsg.str());
    2290             : 
    2291          21 :             CATCH_REQUIRE(c.get_root() == n);
    2292          24 :         }
    2293             : 
    2294          25 :         for(auto iv : invalid_value)
    2295             :         {
    2296          24 :             std::stringstream ss;
    2297          24 :             ss << "a[b" << op[rand() % 6] << "c " << iv << " ]{color:red}\n";
    2298          72 :             csspp::position pos("test.css");
    2299             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    2300          24 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2301             : 
    2302          48 :             csspp::parser p(l);
    2303             : 
    2304          24 :             csspp::node::pointer_t n(p.stylesheet());
    2305             : 
    2306             :             // no errors so far
    2307          24 :             VERIFY_ERRORS("");
    2308             : 
    2309          24 :             csspp::compiler c;
    2310          24 :             c.set_root(n);
    2311             : 
    2312          24 :             c.compile(true);
    2313             : 
    2314             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2315             : 
    2316             :             // the node that caused a problem is:
    2317             :             // LIST
    2318             :             //   COMPONENT_VALUE
    2319             :             //     ARG
    2320             :             //       ...
    2321             :             //       OPEN_SQUAREBRACKET
    2322             :             //         ...
    2323             :             //         ...
    2324             :             //         <this one>
    2325          96 :             csspp::node::pointer_t op_node(n->get_child(0)->get_child(0)->get_child(1)->get_child(3));
    2326             : 
    2327          24 :             std::stringstream errmsg;
    2328          24 :             errmsg << "test.css(1): error: attribute selector cannot be followed by more than one value, found "
    2329          24 :                    << op_node->get_type()
    2330          24 :                    << " after the value, missing quotes?\n";
    2331          24 :             VERIFY_ERRORS(errmsg.str());
    2332             : 
    2333          24 :             CATCH_REQUIRE(c.get_root() == n);
    2334          24 :         }
    2335             :     }
    2336           6 :     CATCH_END_SECTION()
    2337             : 
    2338             :     // attribute value can only be one token
    2339           6 :     CATCH_START_SECTION("Valid operators, right hand side value missing, no spaces")
    2340             :     {
    2341           1 :         char const *op[] =
    2342             :         {
    2343             :             "=",
    2344             :             "!=",
    2345             :             "|=",
    2346             :             "~=",
    2347             :             "$=",
    2348             :             "^=",
    2349             :             "*="
    2350             :         };
    2351             : 
    2352           8 :         for(auto o : op)
    2353             :         {
    2354           7 :             std::stringstream ss;
    2355           7 :             ss << "a[b" << o << "]{color:red}\n";
    2356          21 :             csspp::position pos("test.css");
    2357             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    2358           7 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2359             : 
    2360          14 :             csspp::parser p(l);
    2361             : 
    2362           7 :             csspp::node::pointer_t n(p.stylesheet());
    2363             : 
    2364             :             // no errors so far
    2365           7 :             VERIFY_ERRORS("");
    2366             : 
    2367           7 :             csspp::compiler c;
    2368           7 :             c.set_root(n);
    2369             : 
    2370           7 :             c.compile(true);
    2371             : 
    2372             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2373             : 
    2374             :             // the node that caused a problem is:
    2375             :             // LIST
    2376             :             //   COMPONENT_VALUE
    2377             :             //     ARG
    2378             :             //       ...
    2379             :             //       OPEN_SQUAREBRACKET
    2380             :             //         ...
    2381             :             //         ...
    2382             :             //         <this one>
    2383             :             //csspp::node::pointer_t op_node(n->get_child(0)->get_child(0)->get_child(1)->get_child(3));
    2384             : 
    2385           7 :             std::stringstream errmsg;
    2386           7 :             errmsg << "test.css(1): error: the attribute selector is expected to be an IDENTIFIER optionally followed by an operator and a value.\n";
    2387           7 :             VERIFY_ERRORS(errmsg.str());
    2388             : 
    2389           7 :             CATCH_REQUIRE(c.get_root() == n);
    2390           7 :         }
    2391             : 
    2392           8 :         for(auto o : op)
    2393             :         {
    2394           7 :             std::stringstream ss;
    2395           7 :             ss << "a[b" << o << " ]{color:red}\n";
    2396          21 :             csspp::position pos("test.css");
    2397             : //std::cerr << "Test <<<" << ss.str() << ">>>\n";
    2398           7 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2399             : 
    2400          14 :             csspp::parser p(l);
    2401             : 
    2402           7 :             csspp::node::pointer_t n(p.stylesheet());
    2403             : 
    2404             :             // no errors so far
    2405           7 :             VERIFY_ERRORS("");
    2406             : 
    2407           7 :             csspp::compiler c;
    2408           7 :             c.set_root(n);
    2409             : 
    2410           7 :             c.compile(true);
    2411             : 
    2412             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2413             : 
    2414             :             // the node that caused a problem is:
    2415             :             // LIST
    2416             :             //   COMPONENT_VALUE
    2417             :             //     ARG
    2418             :             //       ...
    2419             :             //       OPEN_SQUAREBRACKET
    2420             :             //         ...
    2421             :             //         ...
    2422             :             //         <this one>
    2423             :             //csspp::node::pointer_t op_node(n->get_child(0)->get_child(0)->get_child(1)->get_child(3));
    2424             : 
    2425           7 :             std::stringstream errmsg;
    2426           7 :             errmsg << "test.css(1): error: the attribute selector is expected to be an IDENTIFIER optionally followed by an operator and a value.\n";
    2427           7 :             VERIFY_ERRORS(errmsg.str());
    2428             : 
    2429           7 :             CATCH_REQUIRE(c.get_root() == n);
    2430           7 :         }
    2431             :     }
    2432           6 :     CATCH_END_SECTION()
    2433             : 
    2434             :     // no error left over
    2435           6 :     VERIFY_ERRORS("");
    2436           6 : }
    2437             : 
    2438           1 : CATCH_TEST_CASE("Undefined paths", "[compiler] [invalid]")
    2439             : {
    2440             :     // compile without defining the paths
    2441             :     //
    2442             :     // (The result may be a success if you installed CSS Preprocessor
    2443             :     // before since it will look for the scripts at "the right place!"
    2444             :     // when the packages are installed properly on a system.)
    2445             :     {
    2446           1 :         std::stringstream ss;
    2447           1 :         ss << ":lang(fr) {color:red}";
    2448           3 :         csspp::position pos("test.css");
    2449           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2450             : 
    2451           2 :         csspp::parser p(l);
    2452             : 
    2453           1 :         csspp::node::pointer_t n(p.stylesheet());
    2454             : 
    2455             :         // no errors so far
    2456           1 :         VERIFY_ERRORS("");
    2457             : 
    2458           1 :         csspp::compiler c;
    2459           1 :         c.set_root(n);
    2460           1 :         c.clear_paths();
    2461             :         // c.add_path(...); -- check system default
    2462             : //c.add_path(csspp_test::get_script_path());
    2463             : //c.add_path(csspp_test::get_version_script_path());
    2464             : 
    2465           1 :         std::stringstream ignore;
    2466           1 :         csspp::safe_error_stream_t safe_output(ignore);
    2467             : 
    2468             :         try
    2469             :         {
    2470           1 :             c.compile(true);
    2471             : 
    2472             :             // in case the system scripts are there, we want to check
    2473             :             // that the result is fine
    2474           0 :             std::stringstream out;
    2475           0 :             out << *n;
    2476           0 :             VERIFY_TREES(out.str(),
    2477             : 
    2478             : "LIST\n"
    2479             : "  COMPONENT_VALUE\n"
    2480             : "    ARG\n"
    2481             : "      COLON\n"
    2482             : "      FUNCTION \"lang\"\n"
    2483             : "        IDENTIFIER \"fr\"\n"
    2484             : "    OPEN_CURLYBRACKET B:true\n"
    2485             : "      DECLARATION \"color\"\n"
    2486             : "        ARG\n"
    2487             : "          COLOR H:ff0000ff\n"
    2488             : 
    2489             :                 );
    2490             : 
    2491           0 :         }
    2492           1 :         catch(csspp::csspp_exception_exit const &)
    2493             :         {
    2494           1 :             CATCH_REQUIRE(ignore.str() == "validation/pseudo-nth-functions(1): fatal: validation script \"validation/pseudo-nth-functions\" was not found.\n");
    2495           1 :         }
    2496             : 
    2497           1 :         CATCH_REQUIRE(c.get_root() == n);
    2498           1 :     }
    2499             : 
    2500             :     // no left over?
    2501           1 :     VERIFY_ERRORS("");
    2502           1 : }
    2503             : 
    2504           1 : CATCH_TEST_CASE("Simple terms", "[compiler] [stylesheet]")
    2505             : {
    2506             :     // simple terms are:
    2507             :     //      HASH
    2508             :     //      IDENTIFIER
    2509             :     //      IDENTIFIER '|' IDENTIFIER
    2510             :     //      IDENTIFIER '|' '*'
    2511             :     //      '*'
    2512             :     //      '*' '|' IDENTIFIER
    2513             :     //      '*' '|' '*'
    2514             :     //      '|' IDENTIFIER
    2515             :     //      '|' '*'
    2516             :     //      ':' IDENTIFIER -- see below
    2517             :     //      ':' FUNCTION ... ')'
    2518             :     //      '.' IDENTIFIER
    2519             :     //      '[' ... ']'
    2520             :     {
    2521           1 :         std::stringstream ss;
    2522             :         ss << "#abd identifier ns|id namespace|* * *|abc *|*"
    2523             :                << " |abc |* a:root :nth-child(3n+4) .class [foo]"
    2524           1 :            << "{color:red;width:12px}";
    2525           3 :         csspp::position pos("test.css");
    2526           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2527             : 
    2528           2 :         csspp::parser p(l);
    2529             : 
    2530           1 :         csspp::node::pointer_t n(p.stylesheet());
    2531             : 
    2532             :         // no errors so far
    2533           1 :         VERIFY_ERRORS("");
    2534             : 
    2535           1 :         csspp::compiler c;
    2536           1 :         c.set_root(n);
    2537           1 :         c.clear_paths();
    2538           1 :         c.add_path(csspp_test::get_script_path());
    2539           1 :         c.add_path(csspp_test::get_version_script_path());
    2540             : 
    2541           1 :         c.compile(true);
    2542             : 
    2543             :         // no error left over
    2544           1 :         VERIFY_ERRORS("");
    2545             : 
    2546             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2547             : 
    2548           1 :         std::stringstream out;
    2549           1 :         out << *n;
    2550           1 :         VERIFY_TREES(out.str(),
    2551             : 
    2552             : "LIST\n"
    2553             : "  COMPONENT_VALUE\n"
    2554             : "    ARG\n"
    2555             : // #abd
    2556             : "      HASH \"abd\"\n"
    2557             : "      WHITESPACE\n"
    2558             : // identifier
    2559             : "      IDENTIFIER \"identifier\"\n"
    2560             : "      WHITESPACE\n"
    2561             : // ns|id
    2562             : "      IDENTIFIER \"ns\"\n"
    2563             : "      SCOPE\n"
    2564             : "      IDENTIFIER \"id\"\n"
    2565             : "      WHITESPACE\n"
    2566             : // namespace|*
    2567             : "      IDENTIFIER \"namespace\"\n"
    2568             : "      SCOPE\n"
    2569             : "      MULTIPLY\n"
    2570             : "      WHITESPACE\n"
    2571             : // *
    2572             : "      MULTIPLY\n"
    2573             : "      WHITESPACE\n"
    2574             : // *|abc
    2575             : "      MULTIPLY\n"
    2576             : "      SCOPE\n"
    2577             : "      IDENTIFIER \"abc\"\n"
    2578             : "      WHITESPACE\n"
    2579             : // *|*
    2580             : "      MULTIPLY\n"
    2581             : "      SCOPE\n"
    2582             : "      MULTIPLY\n"
    2583             : "      WHITESPACE\n"
    2584             : // |abc
    2585             : "      SCOPE\n"
    2586             : "      IDENTIFIER \"abc\"\n"
    2587             : "      WHITESPACE\n"
    2588             : // |*
    2589             : "      SCOPE\n"
    2590             :   "      MULTIPLY\n"
    2591             : "      WHITESPACE\n"
    2592             : // a:root
    2593             : "      IDENTIFIER \"a\"\n"
    2594             : "      COLON\n"
    2595             : "      IDENTIFIER \"root\"\n"
    2596             : "      WHITESPACE\n"
    2597             : // :nth-child
    2598             : "      COLON\n"
    2599             : "      FUNCTION \"nth-child\"\n"
    2600             : "        AN_PLUS_B S:3n+4\n"
    2601             : "      WHITESPACE\n"
    2602             : // .class
    2603             : "      PERIOD\n"
    2604             : "      IDENTIFIER \"class\"\n"
    2605             : //"      WHITESPACE\n"
    2606             : // [foo]
    2607             : "      OPEN_SQUAREBRACKET\n"
    2608             : "        IDENTIFIER \"foo\"\n"
    2609             : // {color:red}
    2610             : "    OPEN_CURLYBRACKET B:true\n"
    2611             : "      LIST\n"
    2612             : "        DECLARATION \"color\"\n"
    2613             : "          ARG\n"
    2614             : "            COLOR H:ff0000ff\n"
    2615             : "        DECLARATION \"width\"\n"
    2616             : "          ARG\n"
    2617             : "            INTEGER \"px\" I:12\n"
    2618             : 
    2619             :             );
    2620             : 
    2621             :         // no error left over
    2622           1 :         VERIFY_ERRORS("");
    2623             : 
    2624           1 :         CATCH_REQUIRE(c.get_root() == n);
    2625           1 :     }
    2626             : 
    2627             :     // check all pseudo-classes
    2628             :     {
    2629           1 :         char const * pseudo_name_table[] =
    2630             :         {
    2631             :             "root",
    2632             :             "first-child",
    2633             :             "last-child",
    2634             :             "first-of-type",
    2635             :             "last-of-type",
    2636             :             "only-child",
    2637             :             "only-of-type",
    2638             :             "empty",
    2639             :             "link",
    2640             :             "visited",
    2641             :             "active",
    2642             :             "hover",
    2643             :             "focus",
    2644             :             "target",
    2645             :             "enabled",
    2646             :             "disabled",
    2647             :             "checked"
    2648             :         };
    2649             : 
    2650          18 :         for(auto pseudo_name : pseudo_name_table)
    2651             :         {
    2652             : 
    2653          17 :             std::stringstream ss;
    2654             :             ss << ":"
    2655             :                << pseudo_name
    2656          17 :                << "{color:red}\n";
    2657          51 :             csspp::position pos("test.css");
    2658          17 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2659             : 
    2660          34 :             csspp::parser p(l);
    2661             : 
    2662          17 :             csspp::node::pointer_t n(p.stylesheet());
    2663             : 
    2664             :             // no errors so far
    2665          17 :             VERIFY_ERRORS("");
    2666             : 
    2667          17 :             csspp::compiler c;
    2668          17 :             c.set_root(n);
    2669          17 :             c.clear_paths();
    2670          17 :             c.add_path(csspp_test::get_script_path());
    2671          17 :             c.add_path(csspp_test::get_version_script_path());
    2672             : 
    2673          17 :             c.compile(true);
    2674             : 
    2675             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2676             : 
    2677          17 :             std::stringstream out;
    2678          17 :             out << *n;
    2679          17 :             VERIFY_TREES(out.str(),
    2680             : 
    2681             : "LIST\n"
    2682             : "  COMPONENT_VALUE\n"
    2683             : "    ARG\n"
    2684             : "      COLON\n"
    2685             : "      IDENTIFIER \"" + std::string(pseudo_name) + "\"\n"
    2686             : "    OPEN_CURLYBRACKET B:true\n"
    2687             : "      DECLARATION \"color\"\n"
    2688             : "        ARG\n"
    2689             : "          COLOR H:ff0000ff\n"
    2690             : 
    2691             :             );
    2692             : 
    2693          17 :             CATCH_REQUIRE(c.get_root() == n);
    2694          17 :         }
    2695             : 
    2696             :         // no error left over
    2697           1 :         VERIFY_ERRORS("");
    2698             :     }
    2699             : 
    2700             :     // check all pseudo-classes
    2701             :     {
    2702           1 :         char const * pseudo_name_table[] =
    2703             :         {
    2704             :             "root",
    2705             :             "first-child",
    2706             :             "last-child",
    2707             :             "first-of-type",
    2708             :             "last-of-type",
    2709             :             "only-child",
    2710             :             "only-of-type",
    2711             :             "empty",
    2712             :             "link",
    2713             :             "visited",
    2714             :             "active",
    2715             :             "hover",
    2716             :             "focus",
    2717             :             "target",
    2718             :             "enabled",
    2719             :             "disabled",
    2720             :             "checked"
    2721             :         };
    2722             : 
    2723          18 :         for(auto pseudo_name : pseudo_name_table)
    2724             :         {
    2725             : 
    2726          17 :             std::stringstream ss;
    2727             :             ss << ":"
    2728             :                << pseudo_name
    2729          17 :                << "{color:red}\n";
    2730          51 :             csspp::position pos("test.css");
    2731          17 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2732             : 
    2733          34 :             csspp::parser p(l);
    2734             : 
    2735          17 :             csspp::node::pointer_t n(p.stylesheet());
    2736             : 
    2737             :             // no errors so far
    2738          17 :             VERIFY_ERRORS("");
    2739             : 
    2740          17 :             csspp::compiler c;
    2741          17 :             c.set_root(n);
    2742          17 :             c.clear_paths();
    2743          17 :             c.add_path(csspp_test::get_script_path());
    2744          17 :             c.add_path(csspp_test::get_version_script_path());
    2745             : 
    2746          17 :             c.compile(true);
    2747             : 
    2748             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2749             : 
    2750          17 :             std::stringstream out;
    2751          17 :             out << *n;
    2752          17 :             VERIFY_TREES(out.str(),
    2753             : 
    2754             : "LIST\n"
    2755             : "  COMPONENT_VALUE\n"
    2756             : "    ARG\n"
    2757             : "      COLON\n"
    2758             : "      IDENTIFIER \"" + std::string(pseudo_name) + "\"\n"
    2759             : "    OPEN_CURLYBRACKET B:true\n"
    2760             : "      DECLARATION \"color\"\n"
    2761             : "        ARG\n"
    2762             : "          COLOR H:ff0000ff\n"
    2763             : 
    2764             :             );
    2765             : 
    2766          17 :             CATCH_REQUIRE(c.get_root() == n);
    2767          17 :         }
    2768             : 
    2769             :         // no error left over
    2770           1 :         VERIFY_ERRORS("");
    2771             :     }
    2772             : 
    2773             :     // test all nth pseudo-functions
    2774             :     {
    2775           1 :         char const * nth_functions[] =
    2776             :         {
    2777             :             "child",
    2778             :             "last-child",
    2779             :             "of-type",
    2780             :             "last-of-type"
    2781             :         };
    2782           5 :         for(size_t i(0); i < sizeof(nth_functions) / sizeof(nth_functions[0]); ++i)
    2783             :         {
    2784           4 :             std::stringstream ss;
    2785             :             ss << "div a:nth-" << nth_functions[i] << "(3n+1)"
    2786           4 :                << "{color:#651}";
    2787          12 :             csspp::position pos("test.css");
    2788           4 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2789             : 
    2790           8 :             csspp::parser p(l);
    2791             : 
    2792           4 :             csspp::node::pointer_t n(p.stylesheet());
    2793             : 
    2794             :             // no errors so far
    2795           4 :             VERIFY_ERRORS("");
    2796             : 
    2797           4 :             csspp::compiler c;
    2798           4 :             c.set_root(n);
    2799           4 :             c.clear_paths();
    2800           4 :             c.add_path(csspp_test::get_script_path());
    2801           4 :             c.add_path(csspp_test::get_version_script_path());
    2802             : 
    2803           4 :             c.compile(true);
    2804             : 
    2805             :             // no error left over
    2806           4 :             VERIFY_ERRORS("");
    2807             : 
    2808             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2809             : 
    2810           4 :             std::stringstream out;
    2811           4 :             out << *n;
    2812           4 :             VERIFY_TREES(out.str(),
    2813             : 
    2814             : "LIST\n"
    2815             : "  COMPONENT_VALUE\n"
    2816             : "    ARG\n"
    2817             : // #abd
    2818             : "      IDENTIFIER \"div\"\n"
    2819             : "      WHITESPACE\n"
    2820             : // identifier
    2821             : "      IDENTIFIER \"a\"\n"
    2822             : "      COLON\n"
    2823             : "      FUNCTION \"nth-" + std::string(nth_functions[i]) + "\"\n"
    2824             : "        AN_PLUS_B S:3n+1\n"
    2825             : // {color:blue}
    2826             : "    OPEN_CURLYBRACKET B:true\n"
    2827             : "      DECLARATION \"color\"\n"
    2828             : "        ARG\n"
    2829             : "          COLOR H:ff115566\n"
    2830             : 
    2831             :                 );
    2832             : 
    2833           4 :             CATCH_REQUIRE(c.get_root() == n);
    2834           4 :         }
    2835             : 
    2836             :         // no error left over
    2837           1 :         VERIFY_ERRORS("");
    2838             :     }
    2839             : 
    2840             :     // test the lang() function
    2841             :     {
    2842           1 :         std::stringstream ss;
    2843             :         ss << "div q:lang(zu-za)"
    2844           1 :            << "{color:#651}";
    2845           3 :         csspp::position pos("test.css");
    2846           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2847             : 
    2848           2 :         csspp::parser p(l);
    2849             : 
    2850           1 :         csspp::node::pointer_t n(p.stylesheet());
    2851             : 
    2852             :         // no errors so far
    2853           1 :         VERIFY_ERRORS("");
    2854             : 
    2855           1 :         csspp::compiler c;
    2856           1 :         c.set_root(n);
    2857           1 :         c.clear_paths();
    2858           1 :         c.add_path(csspp_test::get_script_path());
    2859           1 :         c.add_path(csspp_test::get_version_script_path());
    2860             : 
    2861           1 :         c.compile(true);
    2862             : 
    2863             :         // no error left over
    2864           1 :         VERIFY_ERRORS("");
    2865             : 
    2866             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2867             : 
    2868           1 :         std::stringstream out;
    2869           1 :         out << *n;
    2870           1 :         VERIFY_TREES(out.str(),
    2871             : 
    2872             : "LIST\n"
    2873             : "  COMPONENT_VALUE\n"
    2874             : "    ARG\n"
    2875             : // #abd
    2876             : "      IDENTIFIER \"div\"\n"
    2877             : "      WHITESPACE\n"
    2878             : // identifier
    2879             : "      IDENTIFIER \"q\"\n"
    2880             : "      COLON\n"
    2881             : "      FUNCTION \"lang\"\n"
    2882             : "        IDENTIFIER \"zu-za\"\n"
    2883             : // {color:#651}
    2884             : "    OPEN_CURLYBRACKET B:true\n"
    2885             : "      DECLARATION \"color\"\n"
    2886             : "        ARG\n"
    2887             : "          COLOR H:ff115566\n"
    2888             : 
    2889             :             );
    2890             : 
    2891             :         // no error left over
    2892           1 :         VERIFY_ERRORS("");
    2893             : 
    2894           1 :         CATCH_REQUIRE(c.get_root() == n);
    2895           1 :     }
    2896             : 
    2897             :     // test the lang() function with 3 parameters
    2898             :     {
    2899           1 :         std::stringstream ss;
    2900             :         ss << "div b:lang(fr-ca-nc)"
    2901           1 :            << "{color:brisque}";
    2902           3 :         csspp::position pos("test.css");
    2903           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2904             : 
    2905           2 :         csspp::parser p(l);
    2906             : 
    2907           1 :         csspp::node::pointer_t n(p.stylesheet());
    2908             : 
    2909             :         // no errors so far
    2910           1 :         VERIFY_ERRORS("");
    2911             : 
    2912           1 :         csspp::compiler c;
    2913           1 :         c.set_root(n);
    2914           1 :         c.clear_paths();
    2915           1 :         c.add_path(csspp_test::get_script_path());
    2916           1 :         c.add_path(csspp_test::get_version_script_path());
    2917             : 
    2918           1 :         c.compile(true);
    2919             : 
    2920             :         // no error left over
    2921           1 :         VERIFY_ERRORS("");
    2922             : 
    2923             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2924             : 
    2925           1 :         std::stringstream out;
    2926           1 :         out << *n;
    2927           1 :         VERIFY_TREES(out.str(),
    2928             : 
    2929             : "LIST\n"
    2930             : "  COMPONENT_VALUE\n"
    2931             : "    ARG\n"
    2932             : // #abd
    2933             : "      IDENTIFIER \"div\"\n"
    2934             : "      WHITESPACE\n"
    2935             : // identifier
    2936             : "      IDENTIFIER \"b\"\n"
    2937             : "      COLON\n"
    2938             : "      FUNCTION \"lang\"\n"
    2939             : "        IDENTIFIER \"fr-ca-nc\"\n"
    2940             : // {color:#651}
    2941             : "    OPEN_CURLYBRACKET B:true\n"
    2942             : "      DECLARATION \"color\"\n"
    2943             : "        ARG\n"
    2944             : "          IDENTIFIER \"brisque\"\n"
    2945             : 
    2946             :             );
    2947             : 
    2948             :         // no error left over
    2949           1 :         VERIFY_ERRORS("");
    2950             : 
    2951           1 :         CATCH_REQUIRE(c.get_root() == n);
    2952           1 :     }
    2953             : 
    2954             :     // test the lang() multiple times to verify that the cache works
    2955             :     {
    2956           1 :         std::stringstream ss;
    2957             :         ss << "div b:lang(qu-vg-rr),section i:lang(ks-sm-dp)"
    2958           1 :            << "{color:brisque}";
    2959           3 :         csspp::position pos("test.css");
    2960           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    2961             : 
    2962           2 :         csspp::parser p(l);
    2963             : 
    2964           1 :         csspp::node::pointer_t n(p.stylesheet());
    2965             : 
    2966             :         // no errors so far
    2967           1 :         VERIFY_ERRORS("");
    2968             : 
    2969           1 :         csspp::compiler c;
    2970           1 :         c.set_root(n);
    2971           1 :         c.clear_paths();
    2972           1 :         c.add_path(csspp_test::get_script_path());
    2973           1 :         c.add_path(csspp_test::get_version_script_path());
    2974             : 
    2975           1 :         c.compile(true);
    2976             : 
    2977             :         // no error left over
    2978           1 :         VERIFY_ERRORS("");
    2979             : 
    2980             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    2981             : 
    2982           1 :         std::stringstream out;
    2983           1 :         out << *n;
    2984           1 :         VERIFY_TREES(out.str(),
    2985             : 
    2986             : "LIST\n"
    2987             : "  COMPONENT_VALUE\n"
    2988             : "    ARG\n"
    2989             : // #abd
    2990             : "      IDENTIFIER \"div\"\n"
    2991             : "      WHITESPACE\n"
    2992             : // identifier
    2993             : "      IDENTIFIER \"b\"\n"
    2994             : "      COLON\n"
    2995             : "      FUNCTION \"lang\"\n"
    2996             : "        IDENTIFIER \"qu-vg-rr\"\n"
    2997             : "    ARG\n"
    2998             : // #abd
    2999             : "      IDENTIFIER \"section\"\n"
    3000             : "      WHITESPACE\n"
    3001             : // identifier
    3002             : "      IDENTIFIER \"i\"\n"
    3003             : "      COLON\n"
    3004             : "      FUNCTION \"lang\"\n"
    3005             : "        IDENTIFIER \"ks-sm-dp\"\n"
    3006             : // {color:#651}
    3007             : "    OPEN_CURLYBRACKET B:true\n"
    3008             : "      DECLARATION \"color\"\n"
    3009             : "        ARG\n"
    3010             : "          IDENTIFIER \"brisque\"\n"
    3011             : 
    3012             :             );
    3013             : 
    3014             :         // no error left over
    3015           1 :         VERIFY_ERRORS("");
    3016             : 
    3017           1 :         CATCH_REQUIRE(c.get_root() == n);
    3018           1 :     }
    3019             : 
    3020             :     // one :not(...)
    3021             :     {
    3022           1 :         std::stringstream ss;
    3023           1 :         ss << "div:not(.chocolate) {color:coral}";
    3024           3 :         csspp::position pos("test.css");
    3025           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3026             : 
    3027           2 :         csspp::parser p(l);
    3028             : 
    3029           1 :         csspp::node::pointer_t n(p.stylesheet());
    3030             : 
    3031             :         // no errors so far
    3032           1 :         VERIFY_ERRORS("");
    3033             : 
    3034           1 :         csspp::compiler c;
    3035           1 :         c.set_root(n);
    3036           1 :         c.clear_paths();
    3037           1 :         c.add_path(csspp_test::get_script_path());
    3038           1 :         c.add_path(csspp_test::get_version_script_path());
    3039             : 
    3040           1 :         c.compile(true);
    3041             : 
    3042             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    3043             : 
    3044           1 :         std::stringstream out;
    3045           1 :         out << *n;
    3046           1 :         VERIFY_TREES(out.str(),
    3047             : 
    3048             : "LIST\n"
    3049             : "  COMPONENT_VALUE\n"
    3050             : "    ARG\n"
    3051             : // #abd
    3052             : "      IDENTIFIER \"div\"\n"
    3053             : // :not(...)
    3054             : "      COLON\n"
    3055             : "      FUNCTION \"not\"\n"
    3056             : "        PERIOD\n"
    3057             : "        IDENTIFIER \"chocolate\"\n"
    3058             : // {color:coral}
    3059             : "    OPEN_CURLYBRACKET B:true\n"
    3060             : "      DECLARATION \"color\"\n"
    3061             : "        ARG\n"
    3062             : "          COLOR H:ff507fff\n"
    3063             : 
    3064             :             );
    3065             : 
    3066           1 :         VERIFY_ERRORS("");
    3067             : 
    3068           1 :         CATCH_REQUIRE(c.get_root() == n);
    3069           1 :     }
    3070             : 
    3071             :     // two :not(...) in a row
    3072             :     {
    3073           1 :         std::stringstream ss;
    3074           1 :         ss << "div:not(.red):not(.blue) {color:coral}";
    3075           3 :         csspp::position pos("test.css");
    3076           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3077             : 
    3078           2 :         csspp::parser p(l);
    3079             : 
    3080           1 :         csspp::node::pointer_t n(p.stylesheet());
    3081             : 
    3082             :         // no errors so far
    3083           1 :         VERIFY_ERRORS("");
    3084             : 
    3085           1 :         csspp::compiler c;
    3086           1 :         c.set_root(n);
    3087           1 :         c.clear_paths();
    3088           1 :         c.add_path(csspp_test::get_script_path());
    3089           1 :         c.add_path(csspp_test::get_version_script_path());
    3090             : 
    3091           1 :         c.compile(true);
    3092             : 
    3093             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    3094             : 
    3095           1 :         std::stringstream out;
    3096           1 :         out << *n;
    3097           1 :         VERIFY_TREES(out.str(),
    3098             : 
    3099             : "LIST\n"
    3100             : "  COMPONENT_VALUE\n"
    3101             : "    ARG\n"
    3102             : // #abd
    3103             : "      IDENTIFIER \"div\"\n"
    3104             : // :not(...)
    3105             : "      COLON\n"
    3106             : "      FUNCTION \"not\"\n"
    3107             : "        PERIOD\n"
    3108             : "        IDENTIFIER \"red\"\n"
    3109             : // :not(...)
    3110             : "      COLON\n"
    3111             : "      FUNCTION \"not\"\n"
    3112             : "        PERIOD\n"
    3113             : "        IDENTIFIER \"blue\"\n"
    3114             : // {color:coral}
    3115             : "    OPEN_CURLYBRACKET B:true\n"
    3116             : "      DECLARATION \"color\"\n"
    3117             : "        ARG\n"
    3118             : "          COLOR H:ff507fff\n"
    3119             : 
    3120             :             );
    3121             : 
    3122           1 :         VERIFY_ERRORS("");
    3123             : 
    3124           1 :         CATCH_REQUIRE(c.get_root() == n);
    3125           1 :     }
    3126             : 
    3127             :     // two #hash generate an information message
    3128             :     {
    3129           1 :         std::stringstream ss;
    3130           1 :         ss << "#first and #second {color:coral}";
    3131           3 :         csspp::position pos("test.css");
    3132           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3133             : 
    3134           2 :         csspp::parser p(l);
    3135             : 
    3136           1 :         csspp::node::pointer_t n(p.stylesheet());
    3137             : 
    3138             :         // no errors so far
    3139           1 :         VERIFY_ERRORS("");
    3140             : 
    3141           1 :         csspp::compiler c;
    3142           1 :         c.set_root(n);
    3143           1 :         c.clear_paths();
    3144           1 :         c.add_path(csspp_test::get_script_path());
    3145           1 :         c.add_path(csspp_test::get_version_script_path());
    3146             : 
    3147           1 :         c.compile(true);
    3148             : 
    3149             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    3150             : 
    3151           1 :         VERIFY_ERRORS("test.css(1): info: found multiple #id entries, note that in most cases, assuming your HTML is proper (identifiers are not repeated) then only the last #id is necessary.\n");
    3152             : 
    3153           1 :         std::stringstream out;
    3154           1 :         out << *n;
    3155           1 :         VERIFY_TREES(out.str(),
    3156             : 
    3157             : "LIST\n"
    3158             : "  COMPONENT_VALUE\n"
    3159             : "    ARG\n"
    3160             : // #first #second
    3161             : "      HASH \"first\"\n"
    3162             : "      WHITESPACE\n"
    3163             : "      IDENTIFIER \"and\"\n"
    3164             : "      WHITESPACE\n"
    3165             : "      HASH \"second\"\n"
    3166             : // {color:coral}
    3167             : "    OPEN_CURLYBRACKET B:true\n"
    3168             : "      DECLARATION \"color\"\n"
    3169             : "        ARG\n"
    3170             : "          COLOR H:ff507fff\n"
    3171             : 
    3172             :             );
    3173             : 
    3174           1 :         CATCH_REQUIRE(c.get_root() == n);
    3175           1 :     }
    3176           1 : }
    3177             : 
    3178           1 : CATCH_TEST_CASE("Invalid simple terms", "[compiler] [invalid]")
    3179             : {
    3180             :     // two terms in one :not(...)
    3181             :     {
    3182           1 :         std::stringstream ss;
    3183           1 :         ss << "div:not(.red.blue) {color:coral}";
    3184           3 :         csspp::position pos("test.css");
    3185           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3186             : 
    3187           2 :         csspp::parser p(l);
    3188             : 
    3189           1 :         csspp::node::pointer_t n(p.stylesheet());
    3190             : 
    3191             :         // no errors so far
    3192           1 :         VERIFY_ERRORS("");
    3193             : 
    3194           1 :         csspp::compiler c;
    3195           1 :         c.set_root(n);
    3196           1 :         c.clear_paths();
    3197           1 :         c.add_path(csspp_test::get_script_path());
    3198           1 :         c.add_path(csspp_test::get_version_script_path());
    3199             : 
    3200           1 :         c.compile(true);
    3201             : 
    3202           1 :         VERIFY_ERRORS("test.css(1): error: the :not() function accepts at most one simple term.\n");
    3203             : 
    3204           1 :         CATCH_REQUIRE(c.get_root() == n);
    3205           1 :     }
    3206             : 
    3207             :     // scope must be followed by * or IDENTIFIER
    3208             :     {
    3209           1 :         std::stringstream ss;
    3210           1 :         ss << "*| {color:red}";
    3211           3 :         csspp::position pos("test.css");
    3212           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3213             : 
    3214           2 :         csspp::parser p(l);
    3215             : 
    3216           1 :         csspp::node::pointer_t n(p.stylesheet());
    3217             : 
    3218             :         // no errors so far
    3219           1 :         VERIFY_ERRORS("");
    3220             : 
    3221           1 :         csspp::compiler c;
    3222           1 :         c.set_root(n);
    3223           1 :         c.clear_paths();
    3224           1 :         c.add_path(csspp_test::get_script_path());
    3225           1 :         c.add_path(csspp_test::get_version_script_path());
    3226             : 
    3227           1 :         c.compile(true);
    3228             : 
    3229           1 :         VERIFY_ERRORS("test.css(1): error: the scope operator (|) requires a right hand side identifier or '*'.\n");
    3230             : 
    3231           1 :         CATCH_REQUIRE(c.get_root() == n);
    3232           1 :     }
    3233             : 
    3234             :     // scope must be followed by * or IDENTIFIER
    3235             :     {
    3236           1 :         std::stringstream ss;
    3237           1 :         ss << "*|.white {color:red}";
    3238           3 :         csspp::position pos("test.css");
    3239           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3240             : 
    3241           2 :         csspp::parser p(l);
    3242             : 
    3243           1 :         csspp::node::pointer_t n(p.stylesheet());
    3244             : 
    3245             :         // no errors so far
    3246           1 :         VERIFY_ERRORS("");
    3247             : 
    3248           1 :         csspp::compiler c;
    3249           1 :         c.set_root(n);
    3250           1 :         c.clear_paths();
    3251           1 :         c.add_path(csspp_test::get_script_path());
    3252           1 :         c.add_path(csspp_test::get_version_script_path());
    3253             : 
    3254           1 :         c.compile(true);
    3255             : 
    3256           1 :         VERIFY_ERRORS("test.css(1): error: the right hand side of a scope operator (|) must be an identifier or '*'.\n");
    3257             : 
    3258           1 :         CATCH_REQUIRE(c.get_root() == n);
    3259           1 :     }
    3260             : 
    3261             :     // scope must be followed by * or IDENTIFIER
    3262             :     {
    3263           1 :         std::stringstream ss;
    3264           1 :         ss << "div.white | {color:red}";
    3265           3 :         csspp::position pos("test.css");
    3266           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3267             : 
    3268           2 :         csspp::parser p(l);
    3269             : 
    3270           1 :         csspp::node::pointer_t n(p.stylesheet());
    3271             : 
    3272             :         // no errors so far
    3273           1 :         VERIFY_ERRORS("");
    3274             : 
    3275           1 :         csspp::compiler c;
    3276           1 :         c.set_root(n);
    3277           1 :         c.clear_paths();
    3278           1 :         c.add_path(csspp_test::get_script_path());
    3279           1 :         c.add_path(csspp_test::get_version_script_path());
    3280             : 
    3281           1 :         c.compile(true);
    3282             : 
    3283           1 :         VERIFY_ERRORS("test.css(1): error: a scope selector (|) must be followed by an identifier or '*'.\n");
    3284             : 
    3285           1 :         CATCH_REQUIRE(c.get_root() == n);
    3286           1 :     }
    3287             : 
    3288             :     // scope must be followed by * or IDENTIFIER
    3289             :     {
    3290           1 :         std::stringstream ss;
    3291           1 :         ss << "div.white |#hash {color:red}";
    3292           3 :         csspp::position pos("test.css");
    3293           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3294             : 
    3295           2 :         csspp::parser p(l);
    3296             : 
    3297           1 :         csspp::node::pointer_t n(p.stylesheet());
    3298             : 
    3299             :         // no errors so far
    3300           1 :         VERIFY_ERRORS("");
    3301             : 
    3302           1 :         csspp::compiler c;
    3303           1 :         c.set_root(n);
    3304           1 :         c.clear_paths();
    3305           1 :         c.add_path(csspp_test::get_script_path());
    3306           1 :         c.add_path(csspp_test::get_version_script_path());
    3307             : 
    3308           1 :         c.compile(true);
    3309             : 
    3310           1 :         VERIFY_ERRORS("test.css(1): error: the right hand side of a scope operator (|) must be an identifier or '*'.\n");
    3311             : 
    3312           1 :         CATCH_REQUIRE(c.get_root() == n);
    3313           1 :     }
    3314             : 
    3315             :     // scope must be followed by * or IDENTIFIER
    3316             :     {
    3317           1 :         std::stringstream ss;
    3318           1 :         ss << "#hash and #hash {color:red}";
    3319           3 :         csspp::position pos("test.css");
    3320           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3321             : 
    3322           2 :         csspp::parser p(l);
    3323             : 
    3324           1 :         csspp::node::pointer_t n(p.stylesheet());
    3325             : 
    3326             :         // no errors so far
    3327           1 :         VERIFY_ERRORS("");
    3328             : 
    3329           1 :         csspp::compiler c;
    3330           1 :         c.set_root(n);
    3331           1 :         c.clear_paths();
    3332           1 :         c.add_path(csspp_test::get_script_path());
    3333           1 :         c.add_path(csspp_test::get_version_script_path());
    3334             : 
    3335           1 :         c.compile(true);
    3336             : 
    3337           1 :         VERIFY_ERRORS("test.css(1): error: found #hash twice in selector: \"#hash and #hash\".\n");
    3338             : 
    3339           1 :         CATCH_REQUIRE(c.get_root() == n);
    3340           1 :     }
    3341             : 
    3342             :     // ':' must be followed by an IDENTIFIER or a FUNCTION
    3343             :     {
    3344           1 :         std::stringstream ss;
    3345           1 :         ss << "div.white : {color:red}";
    3346           3 :         csspp::position pos("test.css");
    3347           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3348             : 
    3349           2 :         csspp::parser p(l);
    3350             : 
    3351           1 :         csspp::node::pointer_t n(p.stylesheet());
    3352             : 
    3353             :         // no errors so far
    3354           1 :         VERIFY_ERRORS("");
    3355             : 
    3356           1 :         csspp::compiler c;
    3357           1 :         c.set_root(n);
    3358           1 :         c.clear_paths();
    3359           1 :         c.add_path(csspp_test::get_script_path());
    3360           1 :         c.add_path(csspp_test::get_version_script_path());
    3361             : 
    3362           1 :         c.compile(true);
    3363             : 
    3364           1 :         VERIFY_ERRORS("test.css(1): error: a selector list cannot end with a standalone ':'.\n");
    3365             : 
    3366           1 :         CATCH_REQUIRE(c.get_root() == n);
    3367           1 :     }
    3368             : 
    3369             :     // ':' must be followed a known pseudo-class name
    3370             :     {
    3371           1 :         std::stringstream ss;
    3372           1 :         ss << "div.white :unknown {color:red}";
    3373           3 :         csspp::position pos("test.css");
    3374           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3375             : 
    3376           2 :         csspp::parser p(l);
    3377             : 
    3378           1 :         csspp::node::pointer_t n(p.stylesheet());
    3379             : 
    3380             :         // no errors so far
    3381           1 :         VERIFY_ERRORS("");
    3382             : 
    3383           1 :         csspp::compiler c;
    3384           1 :         c.set_root(n);
    3385           1 :         c.clear_paths();
    3386           1 :         c.add_path(csspp_test::get_script_path());
    3387           1 :         c.add_path(csspp_test::get_version_script_path());
    3388             : 
    3389           1 :         c.compile(true);
    3390             : 
    3391           1 :         VERIFY_ERRORS("scripts/validation/pseudo-classes.scss(38): error: unknown is not a valid name for a pseudo class; CSS only supports root, first-child, last-child, first-of-type, last-of-type, only-child, only-of-type, empty, link, visitived, active, hover, focus, target, enabled, disabled, and checked. (functions are not included in this list since you did not use '(' at the end of the word.)\n");
    3392             : 
    3393           1 :         CATCH_REQUIRE(c.get_root() == n);
    3394           1 :     }
    3395             : 
    3396             :     // ':' must be followed a known pseudo-function name
    3397             :     {
    3398           1 :         std::stringstream ss;
    3399           1 :         ss << "div.white :unknown() {color:red}";
    3400           3 :         csspp::position pos("test.css");
    3401           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3402             : 
    3403           2 :         csspp::parser p(l);
    3404             : 
    3405           1 :         csspp::node::pointer_t n(p.stylesheet());
    3406             : 
    3407             :         // no errors so far
    3408           1 :         VERIFY_ERRORS("");
    3409             : 
    3410           1 :         csspp::compiler c;
    3411           1 :         c.set_root(n);
    3412           1 :         c.clear_paths();
    3413           1 :         c.add_path(csspp_test::get_script_path());
    3414           1 :         c.add_path(csspp_test::get_version_script_path());
    3415             : 
    3416           1 :         c.compile(true);
    3417             : 
    3418           1 :         VERIFY_ERRORS("scripts/validation/pseudo-functions.scss(20): error: unknown is not a valid name for a pseudo function; CSS only supports lang() and not().\n");
    3419             : 
    3420           1 :         CATCH_REQUIRE(c.get_root() == n);
    3421           1 :     }
    3422             : 
    3423             :     // ':' must be followed an identifier or a function
    3424             :     {
    3425           1 :         std::stringstream ss;
    3426           1 :         ss << "div.white :.shark {color:red}";
    3427           3 :         csspp::position pos("test.css");
    3428           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3429             : 
    3430           2 :         csspp::parser p(l);
    3431             : 
    3432           1 :         csspp::node::pointer_t n(p.stylesheet());
    3433             : 
    3434             :         // no errors so far
    3435           1 :         VERIFY_ERRORS("");
    3436             : 
    3437           1 :         csspp::compiler c;
    3438           1 :         c.set_root(n);
    3439           1 :         c.clear_paths();
    3440           1 :         c.add_path(csspp_test::get_script_path());
    3441           1 :         c.add_path(csspp_test::get_version_script_path());
    3442             : 
    3443           1 :         c.compile(true);
    3444             : 
    3445           1 :         VERIFY_ERRORS("test.css(1): error: a ':' selector must be followed by an identifier or a function, a PERIOD was found instead.\n");
    3446             : 
    3447           1 :         CATCH_REQUIRE(c.get_root() == n);
    3448           1 :     }
    3449             : 
    3450             :     // '>' at the wrong place
    3451             :     {
    3452           1 :         std::stringstream ss;
    3453           1 :         ss << "div.white > {color:red}";
    3454           3 :         csspp::position pos("test.css");
    3455           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3456             : 
    3457           2 :         csspp::parser p(l);
    3458             : 
    3459           1 :         csspp::node::pointer_t n(p.stylesheet());
    3460             : 
    3461             :         // no errors so far
    3462           1 :         VERIFY_ERRORS("");
    3463             : 
    3464           1 :         csspp::compiler c;
    3465           1 :         c.set_root(n);
    3466           1 :         c.clear_paths();
    3467           1 :         c.add_path(csspp_test::get_script_path());
    3468           1 :         c.add_path(csspp_test::get_version_script_path());
    3469             : 
    3470           1 :         c.compile(true);
    3471             : 
    3472           1 :         VERIFY_ERRORS("test.css(1): error: found token GREATER_THAN, which is expected to be followed by another selector term.\n");
    3473             : 
    3474           1 :         CATCH_REQUIRE(c.get_root() == n);
    3475           1 :     }
    3476             : 
    3477             :     // :not(INTEGER) is not good
    3478             :     {
    3479           1 :         std::stringstream ss;
    3480           1 :         ss << "div.white:not(11) {color:red}";
    3481           3 :         csspp::position pos("test.css");
    3482           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3483             : 
    3484           2 :         csspp::parser p(l);
    3485             : 
    3486           1 :         csspp::node::pointer_t n(p.stylesheet());
    3487             : 
    3488             :         // no errors so far
    3489           1 :         VERIFY_ERRORS("");
    3490             : 
    3491           1 :         csspp::compiler c;
    3492           1 :         c.set_root(n);
    3493           1 :         c.clear_paths();
    3494           1 :         c.add_path(csspp_test::get_script_path());
    3495           1 :         c.add_path(csspp_test::get_version_script_path());
    3496             : 
    3497           1 :         c.compile(true);
    3498             : 
    3499           1 :         VERIFY_ERRORS("test.css(1): error: found token INTEGER, which is not a valid selector token (simple term).\n");
    3500             : 
    3501           1 :         CATCH_REQUIRE(c.get_root() == n);
    3502           1 :     }
    3503             : 
    3504             :     // :not(FUNCTION) is not good
    3505             :     {
    3506           1 :         std::stringstream ss;
    3507           1 :         ss << "div.white:not(func()) {color:red}";
    3508           3 :         csspp::position pos("test.css");
    3509           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3510             : 
    3511           2 :         csspp::parser p(l);
    3512             : 
    3513           1 :         csspp::node::pointer_t n(p.stylesheet());
    3514             : 
    3515             :         // no errors so far
    3516           1 :         VERIFY_ERRORS("");
    3517             : 
    3518           1 :         csspp::compiler c;
    3519           1 :         c.set_root(n);
    3520           1 :         c.clear_paths();
    3521           1 :         c.add_path(csspp_test::get_script_path());
    3522           1 :         c.add_path(csspp_test::get_version_script_path());
    3523             : 
    3524           1 :         c.compile(true);
    3525             : 
    3526           1 :         VERIFY_ERRORS("test.css(1): error: found function \"func()\", which may be a valid selector token but only if immediately preceeded by one ':' (simple term).\n");
    3527             : 
    3528           1 :         CATCH_REQUIRE(c.get_root() == n);
    3529           1 :     }
    3530             : 
    3531             :     // :not(>) is not good
    3532             :     {
    3533           1 :         std::stringstream ss;
    3534           1 :         ss << "div.white:not(>) {color:red}";
    3535           3 :         csspp::position pos("test.css");
    3536           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3537             : 
    3538           2 :         csspp::parser p(l);
    3539             : 
    3540           1 :         csspp::node::pointer_t n(p.stylesheet());
    3541             : 
    3542             :         // no errors so far
    3543           1 :         VERIFY_ERRORS("");
    3544             : 
    3545           1 :         csspp::compiler c;
    3546           1 :         c.set_root(n);
    3547           1 :         c.clear_paths();
    3548           1 :         c.add_path(csspp_test::get_script_path());
    3549           1 :         c.add_path(csspp_test::get_version_script_path());
    3550             : 
    3551           1 :         c.compile(true);
    3552             : 
    3553           1 :         VERIFY_ERRORS("test.css(1): error: found token GREATER_THAN, which cannot be used to start a selector expression.\n");
    3554             : 
    3555           1 :         CATCH_REQUIRE(c.get_root() == n);
    3556           1 :     }
    3557             : 
    3558             :     // :not(+) is not good
    3559             :     {
    3560           1 :         std::stringstream ss;
    3561           1 :         ss << "div.white:not(+) {color:red}";
    3562           3 :         csspp::position pos("test.css");
    3563           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3564             : 
    3565           2 :         csspp::parser p(l);
    3566             : 
    3567           1 :         csspp::node::pointer_t n(p.stylesheet());
    3568             : 
    3569             :         // no errors so far
    3570           1 :         VERIFY_ERRORS("");
    3571             : 
    3572           1 :         csspp::compiler c;
    3573           1 :         c.set_root(n);
    3574           1 :         c.clear_paths();
    3575           1 :         c.add_path(csspp_test::get_script_path());
    3576           1 :         c.add_path(csspp_test::get_version_script_path());
    3577             : 
    3578           1 :         c.compile(true);
    3579             : 
    3580           1 :         VERIFY_ERRORS("test.css(1): error: found token ADD, which cannot be used to start a selector expression.\n");
    3581             : 
    3582           1 :         CATCH_REQUIRE(c.get_root() == n);
    3583           1 :     }
    3584             : 
    3585             :     // :not(~) is not good
    3586             :     {
    3587           1 :         std::stringstream ss;
    3588           1 :         ss << "div.white:not(~) {color:red}";
    3589           3 :         csspp::position pos("test.css");
    3590           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3591             : 
    3592           2 :         csspp::parser p(l);
    3593             : 
    3594           1 :         csspp::node::pointer_t n(p.stylesheet());
    3595             : 
    3596             :         // no errors so far
    3597           1 :         VERIFY_ERRORS("");
    3598             : 
    3599           1 :         csspp::compiler c;
    3600           1 :         c.set_root(n);
    3601           1 :         c.clear_paths();
    3602           1 :         c.add_path(csspp_test::get_script_path());
    3603           1 :         c.add_path(csspp_test::get_version_script_path());
    3604             : 
    3605           1 :         c.compile(true);
    3606             : 
    3607           1 :         VERIFY_ERRORS("test.css(1): error: found token PRECEDED, which cannot be used to start a selector expression.\n");
    3608             : 
    3609           1 :         CATCH_REQUIRE(c.get_root() == n);
    3610           1 :     }
    3611             : 
    3612             :     // :not(:) is not good
    3613             :     {
    3614           1 :         std::stringstream ss;
    3615           1 :         ss << "div.white:not(:) {color:red}";
    3616           3 :         csspp::position pos("test.css");
    3617           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3618             : 
    3619           2 :         csspp::parser p(l);
    3620             : 
    3621           1 :         csspp::node::pointer_t n(p.stylesheet());
    3622             : 
    3623             :         // no errors so far
    3624           1 :         VERIFY_ERRORS("");
    3625             : 
    3626           1 :         csspp::compiler c;
    3627           1 :         c.set_root(n);
    3628           1 :         c.clear_paths();
    3629           1 :         c.add_path(csspp_test::get_script_path());
    3630           1 :         c.add_path(csspp_test::get_version_script_path());
    3631             : 
    3632           1 :         c.compile(true);
    3633             : 
    3634           1 :         VERIFY_ERRORS("test.css(1): error: a selector list cannot end with a standalone ':'.\n");
    3635             : 
    3636           1 :         CATCH_REQUIRE(c.get_root() == n);
    3637           1 :     }
    3638             : 
    3639             :     // '.' by itself (at the end)
    3640             :     {
    3641           1 :         std::stringstream ss;
    3642           1 :         ss << "div.lone . {color:red}";
    3643           3 :         csspp::position pos("test.css");
    3644           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3645             : 
    3646           2 :         csspp::parser p(l);
    3647             : 
    3648           1 :         csspp::node::pointer_t n(p.stylesheet());
    3649             : 
    3650             :         // no errors so far
    3651           1 :         VERIFY_ERRORS("");
    3652             : 
    3653           1 :         csspp::compiler c;
    3654           1 :         c.set_root(n);
    3655           1 :         c.clear_paths();
    3656           1 :         c.add_path(csspp_test::get_script_path());
    3657           1 :         c.add_path(csspp_test::get_version_script_path());
    3658             : 
    3659           1 :         c.compile(true);
    3660             : 
    3661           1 :         VERIFY_ERRORS("test.css(1): error: a selector list cannot end with a standalone '.'.\n");
    3662             : 
    3663           1 :         CATCH_REQUIRE(c.get_root() == n);
    3664           1 :     }
    3665             : 
    3666             :     // '.' must be followed by IDENTIFIER
    3667             :     {
    3668           1 :         std::stringstream ss;
    3669           1 :         ss << "div.lone .< {color:red}";
    3670           3 :         csspp::position pos("test.css");
    3671           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3672             : 
    3673           2 :         csspp::parser p(l);
    3674             : 
    3675           1 :         csspp::node::pointer_t n(p.stylesheet());
    3676             : 
    3677             :         // no errors so far
    3678           1 :         VERIFY_ERRORS("");
    3679             : 
    3680           1 :         csspp::compiler c;
    3681           1 :         c.set_root(n);
    3682           1 :         c.clear_paths();
    3683           1 :         c.add_path(csspp_test::get_script_path());
    3684           1 :         c.add_path(csspp_test::get_version_script_path());
    3685             : 
    3686           1 :         c.compile(true);
    3687             : 
    3688           1 :         VERIFY_ERRORS("test.css(1): error: a class selector (after a period: '.') must be an identifier.\n");
    3689             : 
    3690           1 :         CATCH_REQUIRE(c.get_root() == n);
    3691           1 :     }
    3692             : 
    3693             :     // test an invalid An+B in an :nth-child() function
    3694             :     {
    3695           1 :         std::stringstream ss;
    3696           1 :         ss << "div:nth-child(3+5) {color:red}";
    3697           3 :         csspp::position pos("test.css");
    3698           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3699             : 
    3700           2 :         csspp::parser p(l);
    3701             : 
    3702           1 :         csspp::node::pointer_t n(p.stylesheet());
    3703             : 
    3704             :         // no errors so far
    3705           1 :         VERIFY_ERRORS("");
    3706             : 
    3707           1 :         csspp::compiler c;
    3708           1 :         c.set_root(n);
    3709           1 :         c.clear_paths();
    3710           1 :         c.add_path(csspp_test::get_script_path());
    3711           1 :         c.add_path(csspp_test::get_version_script_path());
    3712             : 
    3713           1 :         c.compile(true);
    3714             : 
    3715           1 :         VERIFY_ERRORS("test.css(1): error: The first number has to be followed by the 'n' character.\n");
    3716             : 
    3717           1 :         CATCH_REQUIRE(c.get_root() == n);
    3718           1 :     }
    3719             : 
    3720             :     // :not(:not(...))
    3721             :     {
    3722           1 :         std::stringstream ss;
    3723           1 :         ss << "div:not(:not(.red)) {color:red}";
    3724           3 :         csspp::position pos("test.css");
    3725           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3726             : 
    3727           2 :         csspp::parser p(l);
    3728             : 
    3729           1 :         csspp::node::pointer_t n(p.stylesheet());
    3730             : 
    3731             :         // no errors so far
    3732           1 :         VERIFY_ERRORS("");
    3733             : 
    3734           1 :         csspp::compiler c;
    3735           1 :         c.set_root(n);
    3736           1 :         c.clear_paths();
    3737           1 :         c.add_path(csspp_test::get_script_path());
    3738           1 :         c.add_path(csspp_test::get_version_script_path());
    3739             : 
    3740           1 :         c.compile(true);
    3741             : 
    3742           1 :         VERIFY_ERRORS("test.css(1): error: the :not() selector does not accept an inner :not().\n");
    3743             : 
    3744           1 :         CATCH_REQUIRE(c.get_root() == n);
    3745           1 :     }
    3746             : 
    3747             :     // :not(:.white)
    3748             :     {
    3749           1 :         std::stringstream ss;
    3750           1 :         ss << "div:not(:.white) {color:red}";
    3751           3 :         csspp::position pos("test.css");
    3752           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3753             : 
    3754           2 :         csspp::parser p(l);
    3755             : 
    3756           1 :         csspp::node::pointer_t n(p.stylesheet());
    3757             : 
    3758             :         // no errors so far
    3759           1 :         VERIFY_ERRORS("");
    3760             : 
    3761           1 :         csspp::compiler c;
    3762           1 :         c.set_root(n);
    3763           1 :         c.clear_paths();
    3764           1 :         c.add_path(csspp_test::get_script_path());
    3765           1 :         c.add_path(csspp_test::get_version_script_path());
    3766             : 
    3767           1 :         c.compile(true);
    3768             : 
    3769           1 :         VERIFY_ERRORS("test.css(1): error: a ':' selector must be followed by an identifier or a function, a FUNCTION was found instead.\n");
    3770             : 
    3771           1 :         CATCH_REQUIRE(c.get_root() == n);
    3772           1 :     }
    3773             : 
    3774             :     // :lang() accepts only one argument
    3775             :     {
    3776           1 :         std::stringstream ss;
    3777           1 :         ss << "div:lang(red blue) {color:bisque}";
    3778           3 :         csspp::position pos("test.css");
    3779           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3780             : 
    3781           2 :         csspp::parser p(l);
    3782             : 
    3783           1 :         csspp::node::pointer_t n(p.stylesheet());
    3784             : 
    3785             :         // no errors so far
    3786           1 :         VERIFY_ERRORS("");
    3787             : 
    3788           1 :         csspp::compiler c;
    3789           1 :         c.set_root(n);
    3790           1 :         c.clear_paths();
    3791           1 :         c.add_path(csspp_test::get_script_path());
    3792           1 :         c.add_path(csspp_test::get_version_script_path());
    3793             : 
    3794           1 :         c.compile(true);
    3795             : 
    3796             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    3797             : 
    3798           1 :         VERIFY_ERRORS("test.css(1): error: a lang() function selector must have exactly one identifier as its parameter.\n");
    3799             : 
    3800           1 :         CATCH_REQUIRE(c.get_root() == n);
    3801           1 :     }
    3802             : 
    3803             :     // invalid name for :lang()
    3804             :     {
    3805           1 :         std::stringstream ss;
    3806           1 :         ss << "div:lang(notalanguagename) {color:bisque}";
    3807           3 :         csspp::position pos("test.css");
    3808           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3809             : 
    3810           2 :         csspp::parser p(l);
    3811             : 
    3812           1 :         csspp::node::pointer_t n(p.stylesheet());
    3813             : 
    3814             :         // no errors so far
    3815           1 :         VERIFY_ERRORS("");
    3816             : 
    3817           1 :         csspp::compiler c;
    3818           1 :         c.set_root(n);
    3819           1 :         c.clear_paths();
    3820           1 :         c.add_path(csspp_test::get_script_path());
    3821           1 :         c.add_path(csspp_test::get_version_script_path());
    3822             : 
    3823           1 :         c.compile(true);
    3824             : 
    3825             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    3826             : 
    3827           1 :         VERIFY_ERRORS("scripts/validation/languages.scss(154): error: notalanguagename is not a valid language name for :lang().\n");
    3828             : 
    3829           1 :         CATCH_REQUIRE(c.get_root() == n);
    3830           1 :     }
    3831             : 
    3832             :     // invalid name for :lang(), with a valid country
    3833             :     {
    3834           1 :         std::stringstream ss;
    3835           1 :         ss << "div:lang(stillnotalanguagename-us) {color:bisque}";
    3836           3 :         csspp::position pos("test.css");
    3837           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3838             : 
    3839           2 :         csspp::parser p(l);
    3840             : 
    3841           1 :         csspp::node::pointer_t n(p.stylesheet());
    3842             : 
    3843             :         // no errors so far
    3844           1 :         VERIFY_ERRORS("");
    3845             : 
    3846           1 :         csspp::compiler c;
    3847           1 :         c.set_root(n);
    3848           1 :         c.clear_paths();
    3849           1 :         c.add_path(csspp_test::get_script_path());
    3850           1 :         c.add_path(csspp_test::get_version_script_path());
    3851             : 
    3852           1 :         c.compile(true);
    3853             : 
    3854             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    3855             : 
    3856           1 :         VERIFY_ERRORS("scripts/validation/languages.scss(154): error: stillnotalanguagename is not a valid language name for :lang().\n");
    3857             : 
    3858           1 :         CATCH_REQUIRE(c.get_root() == n);
    3859           1 :     }
    3860             : 
    3861             :     // invalid name for :lang(), with a valid country
    3862             :     {
    3863           1 :         std::stringstream ss;
    3864           1 :         ss << "div:lang(mn-withaninvalidcountry-andmore) {color:bisque}";
    3865           3 :         csspp::position pos("test.css");
    3866           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3867             : 
    3868           2 :         csspp::parser p(l);
    3869             : 
    3870           1 :         csspp::node::pointer_t n(p.stylesheet());
    3871             : 
    3872             :         // no errors so far
    3873           1 :         VERIFY_ERRORS("");
    3874             : 
    3875           1 :         csspp::compiler c;
    3876           1 :         c.set_root(n);
    3877           1 :         c.clear_paths();
    3878           1 :         c.add_path(csspp_test::get_script_path());
    3879           1 :         c.add_path(csspp_test::get_version_script_path());
    3880             : 
    3881           1 :         c.compile(true);
    3882             : 
    3883             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    3884             : 
    3885           1 :         VERIFY_ERRORS("scripts/validation/countries.scss(267): error: withaninvalidcountry is not a valid country name for :lang().\n");
    3886             : 
    3887           1 :         CATCH_REQUIRE(c.get_root() == n);
    3888           1 :     }
    3889             : 
    3890             :     // :lang() name must be an identifier
    3891             :     {
    3892           1 :         std::stringstream ss;
    3893           1 :         ss << "div:lang(\"de\") {color:bisque}";
    3894           3 :         csspp::position pos("test.css");
    3895           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3896             : 
    3897           2 :         csspp::parser p(l);
    3898             : 
    3899           1 :         csspp::node::pointer_t n(p.stylesheet());
    3900             : 
    3901             :         // no errors so far
    3902           1 :         VERIFY_ERRORS("");
    3903             : 
    3904           1 :         csspp::compiler c;
    3905           1 :         c.set_root(n);
    3906           1 :         c.clear_paths();
    3907           1 :         c.add_path(csspp_test::get_script_path());
    3908           1 :         c.add_path(csspp_test::get_version_script_path());
    3909             : 
    3910           1 :         c.compile(true);
    3911             : 
    3912             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    3913             : 
    3914           1 :         VERIFY_ERRORS("test.css(1): error: a lang() function selector expects an identifier as its parameter.\n");
    3915             : 
    3916           1 :         CATCH_REQUIRE(c.get_root() == n);
    3917           1 :     }
    3918             : 
    3919             :     // no left over?
    3920           1 :     VERIFY_ERRORS("");
    3921           1 : }
    3922             : 
    3923           8 : CATCH_TEST_CASE("Complex terms", "[compiler] [stylesheet]")
    3924             : {
    3925             :     // [complex] terms are:
    3926             :     // term: simple-term
    3927             :     //     | PLACEHOLDER
    3928             :     //     | REFERENCE
    3929             :     //     | ':' FUNCTION (="not") component-value-list ')'
    3930             :     //     | ':' ':' IDENTIFIER
    3931             : 
    3932           8 :     CATCH_START_SECTION("test a placeholder")
    3933             :     {
    3934           1 :         std::stringstream ss;
    3935             :         ss << "div p%image"
    3936           1 :            << "{color:blue}";
    3937           3 :         csspp::position pos("test.css");
    3938           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3939             : 
    3940           2 :         csspp::parser p(l);
    3941             : 
    3942           1 :         csspp::node::pointer_t n(p.stylesheet());
    3943             : 
    3944             : //std::cerr << "Parser result is: [" << *n << "]\n";
    3945             : 
    3946             :         // no errors so far
    3947           1 :         VERIFY_ERRORS("");
    3948             : 
    3949           1 :         csspp::compiler c;
    3950           1 :         c.set_root(n);
    3951           1 :         c.clear_paths();
    3952           1 :         c.add_path(csspp_test::get_script_path());
    3953           1 :         c.add_path(csspp_test::get_version_script_path());
    3954             : 
    3955           1 :         c.compile(true);
    3956             : 
    3957             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    3958             : 
    3959             :         // no error left over
    3960           1 :         VERIFY_ERRORS("");
    3961             : 
    3962           1 :         std::stringstream out;
    3963           1 :         out << *n;
    3964           1 :         VERIFY_TREES(out.str(),
    3965             : 
    3966             : "LIST\n"
    3967             : "  COMPONENT_VALUE\n"
    3968             : "    ARG\n"
    3969             : // #abd
    3970             : "      IDENTIFIER \"div\"\n"
    3971             : "      WHITESPACE\n"
    3972             : // identifier
    3973             : "      IDENTIFIER \"p\"\n"
    3974             : "      PLACEHOLDER \"image\"\n"
    3975             : // {color:blue}
    3976             : "    OPEN_CURLYBRACKET B:true\n"
    3977             : "      DECLARATION \"color\"\n"
    3978             : "        ARG\n"
    3979             : "          COLOR H:ffff0000\n"
    3980             : 
    3981             :             );
    3982             : 
    3983             :         // no error left over
    3984           1 :         VERIFY_ERRORS("");
    3985             : 
    3986           1 :         CATCH_REQUIRE(c.get_root() == n);
    3987           1 :     }
    3988           8 :     CATCH_END_SECTION()
    3989             : 
    3990           8 :     CATCH_START_SECTION("test a reference")
    3991             :     {
    3992           1 :         std::stringstream ss;
    3993             :         ss << "div a"
    3994           1 :            << "{color:blue;&:hover{color:red}}";
    3995           3 :         csspp::position pos("test.css");
    3996           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    3997             : 
    3998           2 :         csspp::parser p(l);
    3999             : 
    4000           1 :         csspp::node::pointer_t n(p.stylesheet());
    4001             : 
    4002             :         // no errors so far
    4003           1 :         VERIFY_ERRORS("");
    4004             : 
    4005           1 :         csspp::compiler c;
    4006           1 :         c.set_root(n);
    4007           1 :         c.clear_paths();
    4008           1 :         c.add_path(csspp_test::get_script_path());
    4009           1 :         c.add_path(csspp_test::get_version_script_path());
    4010             : 
    4011           1 :         c.compile(true);
    4012             : 
    4013             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    4014             : 
    4015             :         // no error left over
    4016           1 :         VERIFY_ERRORS("");
    4017             : 
    4018           1 :         std::stringstream out;
    4019           1 :         out << *n;
    4020           1 :         VERIFY_TREES(out.str(),
    4021             : 
    4022             : "LIST\n"
    4023             : "  COMPONENT_VALUE\n"
    4024             : "    ARG\n"
    4025             : // #abd
    4026             : "      IDENTIFIER \"div\"\n"
    4027             : "      WHITESPACE\n"
    4028             : // identifier
    4029             : "      IDENTIFIER \"a\"\n"
    4030             : // {color:blue}
    4031             : "    OPEN_CURLYBRACKET B:true\n"
    4032             : "      LIST\n"
    4033             : "        DECLARATION \"color\"\n"
    4034             : "          ARG\n"
    4035             : "            COLOR H:ffff0000\n"
    4036             : "  COMPONENT_VALUE\n"
    4037             : "    ARG\n"
    4038             : // &:hover
    4039             : "      IDENTIFIER \"div\"\n"
    4040             : "      WHITESPACE\n"
    4041             : "      IDENTIFIER \"a\"\n"
    4042             : "      COLON\n"
    4043             : "      IDENTIFIER \"hover\"\n"
    4044             : "    OPEN_CURLYBRACKET B:true\n"
    4045             : "      DECLARATION \"color\"\n"
    4046             : "        ARG\n"
    4047             : "          COLOR H:ff0000ff\n"
    4048             : 
    4049             :             );
    4050             : 
    4051             :         // no error left over
    4052           1 :         VERIFY_ERRORS("");
    4053             : 
    4054           1 :         CATCH_REQUIRE(c.get_root() == n);
    4055           1 :     }
    4056           8 :     CATCH_END_SECTION()
    4057             : 
    4058           8 :     CATCH_START_SECTION("test the not() function")
    4059             :     {
    4060           1 :         std::stringstream ss;
    4061             :         ss << "div a:not(:hover)"
    4062           1 :            << "{color:#175}";
    4063           3 :         csspp::position pos("test.css");
    4064           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4065             : 
    4066           2 :         csspp::parser p(l);
    4067             : 
    4068           1 :         csspp::node::pointer_t n(p.stylesheet());
    4069             : 
    4070             :         // no errors so far
    4071           1 :         VERIFY_ERRORS("");
    4072             : 
    4073           1 :         csspp::compiler c;
    4074           1 :         c.set_root(n);
    4075           1 :         c.clear_paths();
    4076           1 :         c.add_path(csspp_test::get_script_path());
    4077           1 :         c.add_path(csspp_test::get_version_script_path());
    4078             : 
    4079           1 :         c.compile(true);
    4080             : 
    4081             :         // no error left over
    4082           1 :         VERIFY_ERRORS("");
    4083             : 
    4084             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    4085             : 
    4086           1 :         std::stringstream out;
    4087           1 :         out << *n;
    4088           1 :         VERIFY_TREES(out.str(),
    4089             : 
    4090             : "LIST\n"
    4091             : "  COMPONENT_VALUE\n"
    4092             : "    ARG\n"
    4093             : // #abd
    4094             : "      IDENTIFIER \"div\"\n"
    4095             : "      WHITESPACE\n"
    4096             : // identifier
    4097             : "      IDENTIFIER \"a\"\n"
    4098             : "      COLON\n"
    4099             : "      FUNCTION \"not\"\n"
    4100             : "        COLON\n"
    4101             : "        IDENTIFIER \"hover\"\n"
    4102             : // {color:blue}
    4103             : "    OPEN_CURLYBRACKET B:true\n"
    4104             : "      DECLARATION \"color\"\n"
    4105             : "        ARG\n"
    4106             : "          COLOR H:ff557711\n"
    4107             : 
    4108             :             );
    4109             : 
    4110             :         // no error left over
    4111           1 :         VERIFY_ERRORS("");
    4112             : 
    4113           1 :         CATCH_REQUIRE(c.get_root() == n);
    4114           1 :     }
    4115           8 :     CATCH_END_SECTION()
    4116             : 
    4117           8 :     CATCH_START_SECTION("test the not() function + a sub-function")
    4118             :     {
    4119           1 :         std::stringstream ss;
    4120             :         ss << "div a:not(:nth-last-of-type(5n+3))"
    4121           1 :            << "{color:#175}";
    4122           3 :         csspp::position pos("test.css");
    4123           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4124             : 
    4125           2 :         csspp::parser p(l);
    4126             : 
    4127           1 :         csspp::node::pointer_t n(p.stylesheet());
    4128             : 
    4129             :         // no errors so far
    4130           1 :         VERIFY_ERRORS("");
    4131             : 
    4132           1 :         csspp::compiler c;
    4133           1 :         c.set_root(n);
    4134           1 :         c.clear_paths();
    4135           1 :         c.add_path(csspp_test::get_script_path());
    4136           1 :         c.add_path(csspp_test::get_version_script_path());
    4137             : 
    4138           1 :         c.compile(true);
    4139             : 
    4140             :         // no error left over
    4141           1 :         VERIFY_ERRORS("");
    4142             : 
    4143             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    4144             : 
    4145           1 :         std::stringstream out;
    4146           1 :         out << *n;
    4147           1 :         VERIFY_TREES(out.str(),
    4148             : 
    4149             : "LIST\n"
    4150             : "  COMPONENT_VALUE\n"
    4151             : "    ARG\n"
    4152             : // #abd
    4153             : "      IDENTIFIER \"div\"\n"
    4154             : "      WHITESPACE\n"
    4155             : // identifier
    4156             : "      IDENTIFIER \"a\"\n"
    4157             : "      COLON\n"
    4158             : "      FUNCTION \"not\"\n"
    4159             : "        COLON\n"
    4160             : "        FUNCTION \"nth-last-of-type\"\n"
    4161             : "          AN_PLUS_B S:5n+3\n"
    4162             : // {color:blue}
    4163             : "    OPEN_CURLYBRACKET B:true\n"
    4164             : "      DECLARATION \"color\"\n"
    4165             : "        ARG\n"
    4166             : "          COLOR H:ff557711\n"
    4167             : 
    4168             :             );
    4169             : 
    4170             :         // no error left over
    4171           1 :         VERIFY_ERRORS("");
    4172             : 
    4173           1 :         CATCH_REQUIRE(c.get_root() == n);
    4174           1 :     }
    4175           8 :     CATCH_END_SECTION()
    4176             : 
    4177           8 :     CATCH_START_SECTION("check all pseudo-elements")
    4178             :     {
    4179           1 :         char const * pseudo_name_table[] =
    4180             :         {
    4181             :             "first-line",
    4182             :             "first-letter",
    4183             :             "before",
    4184             :             "after"
    4185             :         };
    4186             : 
    4187           5 :         for(auto pseudo_name : pseudo_name_table)
    4188             :         {
    4189           4 :             std::stringstream ss;
    4190             :             ss << "div ::"
    4191             :                << pseudo_name
    4192           4 :                << "{color:teal}\n";
    4193          12 :             csspp::position pos("test.css");
    4194           4 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4195             : 
    4196           8 :             csspp::parser p(l);
    4197             : 
    4198           4 :             csspp::node::pointer_t n(p.stylesheet());
    4199             : 
    4200             :             // no errors so far
    4201           4 :             VERIFY_ERRORS("");
    4202             : 
    4203           4 :             csspp::compiler c;
    4204           4 :             c.set_root(n);
    4205           4 :             c.clear_paths();
    4206           4 :             c.add_path(csspp_test::get_script_path());
    4207           4 :             c.add_path(csspp_test::get_version_script_path());
    4208             : 
    4209           4 :             c.compile(true);
    4210             : 
    4211             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    4212             : 
    4213           4 :             std::stringstream out;
    4214           4 :             out << *n;
    4215           4 :             VERIFY_TREES(out.str(),
    4216             : 
    4217             : "LIST\n"
    4218             : "  COMPONENT_VALUE\n"
    4219             : "    ARG\n"
    4220             : "      IDENTIFIER \"div\"\n"
    4221             : "      WHITESPACE\n"
    4222             : "      COLON\n"
    4223             : "      COLON\n"
    4224             : "      IDENTIFIER \"" + std::string(pseudo_name) + "\"\n"
    4225             : "    OPEN_CURLYBRACKET B:true\n"
    4226             : "      DECLARATION \"color\"\n"
    4227             : "        ARG\n"
    4228             : "          COLOR H:ff808000\n"
    4229             : 
    4230             :             );
    4231             : 
    4232           4 :             CATCH_REQUIRE(c.get_root() == n);
    4233           4 :         }
    4234             : 
    4235             :         // no error left over
    4236           1 :         VERIFY_ERRORS("");
    4237             :     }
    4238           8 :     CATCH_END_SECTION()
    4239             : 
    4240           8 :     CATCH_START_SECTION("check filter with alpha() function")
    4241             :     {
    4242           1 :         std::stringstream ss;
    4243             :         ss << "div {\n"
    4244             :            << "  font: 15px/150% helvetica;\n"
    4245             :            << "  filter: alpha(opacity=20);\n"
    4246           1 :            << "}\n";
    4247           3 :         csspp::position pos("test.css");
    4248           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4249             : 
    4250           2 :         csspp::parser p(l);
    4251             : 
    4252           1 :         csspp::node::pointer_t n(p.stylesheet());
    4253             : 
    4254             :         // no errors so far
    4255           1 :         VERIFY_ERRORS("");
    4256             : 
    4257           1 :         csspp::compiler c;
    4258           1 :         c.set_root(n);
    4259           1 :         c.clear_paths();
    4260           1 :         c.add_path(csspp_test::get_script_path());
    4261           1 :         c.add_path(csspp_test::get_version_script_path());
    4262             : 
    4263           1 :         c.compile(true);
    4264             : 
    4265             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    4266             : 
    4267           1 :         VERIFY_ERRORS("test.css(3): warning: the alpha(), chroma() and similar functions of the filter field are Internet Explorer specific extensions which are not supported across browsers.\n");
    4268             : 
    4269           1 :         std::stringstream out;
    4270           1 :         out << *n;
    4271           1 :         VERIFY_TREES(out.str(),
    4272             : 
    4273             : "LIST\n"
    4274             : "  COMPONENT_VALUE\n"
    4275             : "    ARG\n"
    4276             : "      IDENTIFIER \"div\"\n"
    4277             : "    OPEN_CURLYBRACKET B:true\n"
    4278             : "      LIST\n"
    4279             : "        DECLARATION \"font\"\n"
    4280             : "          ARG\n"
    4281             : "            FONT_METRICS FM:15px/150%\n"
    4282             : "            WHITESPACE\n"
    4283             : "            IDENTIFIER \"helvetica\"\n"
    4284             : "        DECLARATION \"filter\"\n"
    4285             : "          FUNCTION \"alpha\"\n"
    4286             : "            IDENTIFIER \"opacity\"\n"
    4287             : "            EQUAL\n"
    4288             : "            INTEGER \"\" I:20\n"
    4289             : 
    4290             :             );
    4291             : 
    4292           1 :         CATCH_REQUIRE(c.get_root() == n);
    4293             : 
    4294             :         // no error left over
    4295           1 :         VERIFY_ERRORS("");
    4296           1 :     }
    4297           8 :     CATCH_END_SECTION()
    4298             : 
    4299           8 :     CATCH_START_SECTION("check \"-filter\" with alpha() function")
    4300             :     {
    4301           1 :         std::stringstream ss;
    4302             :         ss << "div {\n"
    4303             :            << "  font: 15px/150% helvetica;\n"
    4304             :            << "  -filter: alpha(opacity=20);\n"
    4305           1 :            << "}\n";
    4306           3 :         csspp::position pos("test.css");
    4307           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4308             : 
    4309           2 :         csspp::parser p(l);
    4310             : 
    4311           1 :         csspp::node::pointer_t n(p.stylesheet());
    4312             : 
    4313             :         // no errors so far
    4314           1 :         VERIFY_ERRORS("");
    4315             : 
    4316           1 :         csspp::compiler c;
    4317           1 :         c.set_root(n);
    4318           1 :         c.clear_paths();
    4319           1 :         c.add_path(csspp_test::get_script_path());
    4320           1 :         c.add_path(csspp_test::get_version_script_path());
    4321             : 
    4322           1 :         c.compile(true);
    4323             : 
    4324             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    4325             : 
    4326           1 :         VERIFY_ERRORS("test.css(3): warning: the alpha(), chroma() and similar functions of the filter field are Internet Explorer specific extensions which are not supported across browsers.\n");
    4327             : 
    4328           1 :         std::stringstream out;
    4329           1 :         out << *n;
    4330           1 :         VERIFY_TREES(out.str(),
    4331             : 
    4332             : "LIST\n"
    4333             : "  COMPONENT_VALUE\n"
    4334             : "    ARG\n"
    4335             : "      IDENTIFIER \"div\"\n"
    4336             : "    OPEN_CURLYBRACKET B:true\n"
    4337             : "      LIST\n"
    4338             : "        DECLARATION \"font\"\n"
    4339             : "          ARG\n"
    4340             : "            FONT_METRICS FM:15px/150%\n"
    4341             : "            WHITESPACE\n"
    4342             : "            IDENTIFIER \"helvetica\"\n"
    4343             : "        DECLARATION \"-filter\"\n"
    4344             : "          FUNCTION \"alpha\"\n"
    4345             : "            IDENTIFIER \"opacity\"\n"
    4346             : "            EQUAL\n"
    4347             : "            INTEGER \"\" I:20\n"
    4348             : 
    4349             :             );
    4350             : 
    4351           1 :         CATCH_REQUIRE(c.get_root() == n);
    4352             : 
    4353             :         // no error left over
    4354           1 :         VERIFY_ERRORS("");
    4355           1 :     }
    4356           8 :     CATCH_END_SECTION()
    4357             : 
    4358           8 :     CATCH_START_SECTION("check progid:...")
    4359             :     {
    4360           1 :         std::stringstream ss;
    4361             :         ss << "div {\n"
    4362             :            << "  -filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(opacity=20);\n"
    4363             :            << "  font: 17.2px/1.35em;\n"
    4364           1 :            << "}\n";
    4365           3 :         csspp::position pos("test.css");
    4366           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4367             : 
    4368           2 :         csspp::parser p(l);
    4369             : 
    4370           1 :         csspp::node::pointer_t n(p.stylesheet());
    4371             : 
    4372             :         // no errors so far
    4373           1 :         VERIFY_ERRORS("");
    4374             : 
    4375           1 :         csspp::compiler c;
    4376           1 :         c.set_root(n);
    4377           1 :         c.clear_paths();
    4378           1 :         c.add_path(csspp_test::get_script_path());
    4379           1 :         c.add_path(csspp_test::get_version_script_path());
    4380             : 
    4381           1 :         c.compile(true);
    4382             : 
    4383             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    4384             : 
    4385           1 :         VERIFY_ERRORS("test.css(2): warning: the alpha(), chroma() and similar functions of the filter field are Internet Explorer specific extensions which are not supported across browsers.\n");
    4386             : 
    4387           1 :         std::stringstream out;
    4388           1 :         out << *n;
    4389           1 :         VERIFY_TREES(out.str(),
    4390             : 
    4391             : "LIST\n"
    4392             : "  COMPONENT_VALUE\n"
    4393             : "    ARG\n"
    4394             : "      IDENTIFIER \"div\"\n"
    4395             : "    OPEN_CURLYBRACKET B:true\n"
    4396             : "      LIST\n"
    4397             : "        DECLARATION \"-filter\"\n"
    4398             : "          IDENTIFIER \"progid\"\n"
    4399             : "          COLON\n"
    4400             : "          IDENTIFIER \"DXImageTransform\"\n"
    4401             : "          PERIOD\n"
    4402             : "          IDENTIFIER \"Microsoft\"\n"
    4403             : "          PERIOD\n"
    4404             : "          FUNCTION \"alphaimageloader\"\n"  // functions names always in lowercase...
    4405             : "            IDENTIFIER \"opacity\"\n"
    4406             : "            EQUAL\n"
    4407             : "            INTEGER \"\" I:20\n"
    4408             : "        DECLARATION \"font\"\n"
    4409             : "          ARG\n"
    4410             : "            FONT_METRICS FM:17.2px/1.35em\n"
    4411             : 
    4412             :             );
    4413             : 
    4414           1 :         CATCH_REQUIRE(c.get_root() == n);
    4415             : 
    4416             :         // no error left over
    4417           1 :         VERIFY_ERRORS("");
    4418           1 :     }
    4419           8 :     CATCH_END_SECTION()
    4420           8 : }
    4421             : 
    4422           1 : CATCH_TEST_CASE("Invalid complex terms", "[compiler] [invalid]")
    4423             : {
    4424             :     // '::' must be followed by an IDENTIFIER
    4425             :     {
    4426           1 :         std::stringstream ss;
    4427           1 :         ss << "div.white :: {color:red}";
    4428           3 :         csspp::position pos("test.css");
    4429           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4430             : 
    4431           2 :         csspp::parser p(l);
    4432             : 
    4433           1 :         csspp::node::pointer_t n(p.stylesheet());
    4434             : 
    4435             :         // no errors so far
    4436           1 :         VERIFY_ERRORS("");
    4437             : 
    4438           1 :         csspp::compiler c;
    4439           1 :         c.set_root(n);
    4440           1 :         c.clear_paths();
    4441           1 :         c.add_path(csspp_test::get_script_path());
    4442           1 :         c.add_path(csspp_test::get_version_script_path());
    4443             : 
    4444           1 :         c.compile(true);
    4445             : 
    4446           1 :         VERIFY_ERRORS("test.css(1): error: a selector list cannot end with a '::' without an identifier after it.\n");
    4447             : 
    4448           1 :         CATCH_REQUIRE(c.get_root() == n);
    4449           1 :     }
    4450             : 
    4451             :     // '::' must be followed a known pseudo-element name
    4452             :     {
    4453           1 :         std::stringstream ss;
    4454           1 :         ss << "div.white ::unknown {color:red}";
    4455           3 :         csspp::position pos("test.css");
    4456           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4457             : 
    4458           2 :         csspp::parser p(l);
    4459             : 
    4460           1 :         csspp::node::pointer_t n(p.stylesheet());
    4461             : 
    4462             :         // no errors so far
    4463           1 :         VERIFY_ERRORS("");
    4464             : 
    4465           1 :         csspp::compiler c;
    4466           1 :         c.set_root(n);
    4467           1 :         c.clear_paths();
    4468           1 :         c.add_path(csspp_test::get_script_path());
    4469           1 :         c.add_path(csspp_test::get_version_script_path());
    4470             : 
    4471           1 :         c.compile(true);
    4472             : 
    4473           1 :         VERIFY_ERRORS("scripts/validation/pseudo-elements.scss(39): error: unknown is not a valid name for a pseudo element; CSS only supports after, before, first-letter, first-line, grammar-error, marker, placeholder, selection, and spelling-error.\n");
    4474           1 :     }
    4475             : 
    4476             :     // '::' must be followed an IDENTIFIER
    4477             :     {
    4478           1 :         std::stringstream ss;
    4479           1 :         ss << "div.white ::.shark {color:red}";
    4480           3 :         csspp::position pos("test.css");
    4481           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4482             : 
    4483           2 :         csspp::parser p(l);
    4484             : 
    4485           1 :         csspp::node::pointer_t n(p.stylesheet());
    4486             : 
    4487             :         // no errors so far
    4488           1 :         VERIFY_ERRORS("");
    4489             : 
    4490           1 :         csspp::compiler c;
    4491           1 :         c.set_root(n);
    4492           1 :         c.clear_paths();
    4493           1 :         c.add_path(csspp_test::get_script_path());
    4494           1 :         c.add_path(csspp_test::get_version_script_path());
    4495             : 
    4496           1 :         c.compile(true);
    4497             : 
    4498           1 :         VERIFY_ERRORS("test.css(1): error: a pseudo element name (defined after a '::' in a list of selectors) must be defined using an identifier.\n");
    4499             : 
    4500           1 :         CATCH_REQUIRE(c.get_root() == n);
    4501           1 :     }
    4502             : 
    4503             :     // '>' cannot start a selector list
    4504             :     {
    4505           1 :         std::stringstream ss;
    4506           1 :         ss << "> div.white {color:red}";
    4507           3 :         csspp::position pos("test.css");
    4508           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4509             : 
    4510           2 :         csspp::parser p(l);
    4511             : 
    4512           1 :         csspp::node::pointer_t n(p.stylesheet());
    4513             : 
    4514             :         // no errors so far
    4515           1 :         VERIFY_ERRORS("");
    4516             : 
    4517           1 :         csspp::compiler c;
    4518           1 :         c.set_root(n);
    4519           1 :         c.clear_paths();
    4520           1 :         c.add_path(csspp_test::get_script_path());
    4521           1 :         c.add_path(csspp_test::get_version_script_path());
    4522             : 
    4523           1 :         c.compile(true);
    4524             : 
    4525           1 :         VERIFY_ERRORS("test.css(1): error: found token GREATER_THAN, which cannot be used to start a selector expression.\n");
    4526             : 
    4527           1 :         CATCH_REQUIRE(c.get_root() == n);
    4528           1 :     }
    4529             : 
    4530             :     // '+' cannot start a selector list
    4531             :     {
    4532           1 :         std::stringstream ss;
    4533           1 :         ss << "+ div.white {color:red}";
    4534           3 :         csspp::position pos("test.css");
    4535           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4536             : 
    4537           2 :         csspp::parser p(l);
    4538             : 
    4539           1 :         csspp::node::pointer_t n(p.stylesheet());
    4540             : 
    4541             :         // no errors so far
    4542           1 :         VERIFY_ERRORS("");
    4543             : 
    4544           1 :         csspp::compiler c;
    4545           1 :         c.set_root(n);
    4546           1 :         c.clear_paths();
    4547           1 :         c.add_path(csspp_test::get_script_path());
    4548           1 :         c.add_path(csspp_test::get_version_script_path());
    4549             : 
    4550           1 :         c.compile(true);
    4551             : 
    4552           1 :         VERIFY_ERRORS("test.css(1): error: found token ADD, which cannot be used to start a selector expression.\n");
    4553             : 
    4554           1 :         CATCH_REQUIRE(c.get_root() == n);
    4555           1 :     }
    4556             : 
    4557             :     // '~' cannot start a selector list
    4558             :     {
    4559           1 :         std::stringstream ss;
    4560           1 :         ss << "~ div.white {color:red}";
    4561           3 :         csspp::position pos("test.css");
    4562           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4563             : 
    4564           2 :         csspp::parser p(l);
    4565             : 
    4566           1 :         csspp::node::pointer_t n(p.stylesheet());
    4567             : 
    4568             :         // no errors so far
    4569           1 :         VERIFY_ERRORS("");
    4570             : 
    4571           1 :         csspp::compiler c;
    4572           1 :         c.set_root(n);
    4573           1 :         c.clear_paths();
    4574           1 :         c.add_path(csspp_test::get_script_path());
    4575           1 :         c.add_path(csspp_test::get_version_script_path());
    4576             : 
    4577           1 :         c.compile(true);
    4578             : 
    4579           1 :         VERIFY_ERRORS("test.css(1): error: found token PRECEDED, which cannot be used to start a selector expression.\n");
    4580             : 
    4581           1 :         CATCH_REQUIRE(c.get_root() == n);
    4582           1 :     }
    4583             : 
    4584             :     // selector cannot start with a FUNCTION
    4585             :     {
    4586           1 :         std::stringstream ss;
    4587           1 :         ss << "func() div.white {color:red}";
    4588           3 :         csspp::position pos("test.css");
    4589           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4590             : 
    4591           2 :         csspp::parser p(l);
    4592             : 
    4593           1 :         csspp::node::pointer_t n(p.stylesheet());
    4594             : 
    4595             :         // no errors so far
    4596           1 :         VERIFY_ERRORS("");
    4597             : 
    4598           1 :         csspp::compiler c;
    4599           1 :         c.set_root(n);
    4600           1 :         c.clear_paths();
    4601           1 :         c.add_path(csspp_test::get_script_path());
    4602           1 :         c.add_path(csspp_test::get_version_script_path());
    4603             : 
    4604           1 :         c.compile(true);
    4605             : 
    4606           1 :         VERIFY_ERRORS("test.css(1): error: found function \"func()\", which may be a valid selector token but only if immediately preceeded by one ':' (term).\n");
    4607             : 
    4608           1 :         CATCH_REQUIRE(c.get_root() == n);
    4609           1 :     }
    4610             : 
    4611             :     // selectors do not support INTEGER
    4612             :     {
    4613           1 :         std::stringstream ss;
    4614           1 :         ss << "13 div.white {color:red}";
    4615           3 :         csspp::position pos("test.css");
    4616           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4617             : 
    4618           2 :         csspp::parser p(l);
    4619             : 
    4620           1 :         csspp::node::pointer_t n(p.stylesheet());
    4621             : 
    4622             :         // no errors so far
    4623           1 :         VERIFY_ERRORS("");
    4624             : 
    4625           1 :         csspp::compiler c;
    4626           1 :         c.set_root(n);
    4627           1 :         c.clear_paths();
    4628           1 :         c.add_path(csspp_test::get_script_path());
    4629           1 :         c.add_path(csspp_test::get_version_script_path());
    4630             : 
    4631           1 :         c.compile(true);
    4632             : 
    4633           1 :         VERIFY_ERRORS("test.css(1): error: found token INTEGER, which is not a valid selector token (term).\n");
    4634             : 
    4635           1 :         CATCH_REQUIRE(c.get_root() == n);
    4636           1 :     }
    4637             : 
    4638             :     // selectors do not support DECIMAL_NUMBER
    4639             :     {
    4640           1 :         std::stringstream ss;
    4641           1 :         ss << "13.25 div.white {color:red}";
    4642           3 :         csspp::position pos("test.css");
    4643           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4644             : 
    4645           2 :         csspp::parser p(l);
    4646             : 
    4647           1 :         csspp::node::pointer_t n(p.stylesheet());
    4648             : 
    4649             :         // no errors so far
    4650           1 :         VERIFY_ERRORS("");
    4651             : 
    4652           1 :         csspp::compiler c;
    4653           1 :         c.set_root(n);
    4654           1 :         c.clear_paths();
    4655           1 :         c.add_path(csspp_test::get_script_path());
    4656           1 :         c.add_path(csspp_test::get_version_script_path());
    4657             : 
    4658           1 :         c.compile(true);
    4659             : 
    4660           1 :         VERIFY_ERRORS("test.css(1): error: found token DECIMAL_NUMBER, which is not a valid selector token (term).\n");
    4661             : 
    4662           1 :         CATCH_REQUIRE(c.get_root() == n);
    4663           1 :     }
    4664             : 
    4665             :     // selectors do not support PERCENT
    4666             :     {
    4667           1 :         std::stringstream ss;
    4668           1 :         ss << "13% div.white {color:red}";
    4669           3 :         csspp::position pos("test.css");
    4670           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4671             : 
    4672           2 :         csspp::parser p(l);
    4673             : 
    4674           1 :         csspp::node::pointer_t n(p.stylesheet());
    4675             : 
    4676             :         // no errors so far
    4677           1 :         VERIFY_ERRORS("");
    4678             : 
    4679           1 :         csspp::compiler c;
    4680           1 :         c.set_root(n);
    4681           1 :         c.clear_paths();
    4682           1 :         c.add_path(csspp_test::get_script_path());
    4683           1 :         c.add_path(csspp_test::get_version_script_path());
    4684             : 
    4685           1 :         c.compile(true);
    4686             : 
    4687           1 :         VERIFY_ERRORS("test.css(1): error: found token PERCENT, which is not a valid selector token (term).\n");
    4688             : 
    4689           1 :         CATCH_REQUIRE(c.get_root() == n);
    4690           1 :     }
    4691             : 
    4692             :     // check pseudo-elements not at the end
    4693             :     {
    4694           1 :         char const * pseudo_name_table[] =
    4695             :         {
    4696             :             "first-line",
    4697             :             "first-letter",
    4698             :             "before",
    4699             :             "after"
    4700             :         };
    4701             : 
    4702           5 :         for(auto pseudo_name : pseudo_name_table)
    4703             :         {
    4704           4 :             std::stringstream ss;
    4705             :             ss << "div ::"
    4706             :                << pseudo_name
    4707           4 :                << " span {color:teal}\n";
    4708          12 :             csspp::position pos("test.css");
    4709           4 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4710             : 
    4711           8 :             csspp::parser p(l);
    4712             : 
    4713           4 :             csspp::node::pointer_t n(p.stylesheet());
    4714             : 
    4715             :             // no errors so far
    4716           4 :             VERIFY_ERRORS("");
    4717             : 
    4718           4 :             csspp::compiler c;
    4719           4 :             c.set_root(n);
    4720           4 :             c.clear_paths();
    4721           4 :             c.add_path(csspp_test::get_script_path());
    4722           4 :             c.add_path(csspp_test::get_version_script_path());
    4723             : 
    4724           4 :             c.compile(true);
    4725             : 
    4726             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    4727             : 
    4728           4 :             VERIFY_ERRORS("test.css(1): error: a pseudo element name (defined after a '::' in a list of selectors) must be defined as the last element in the list of selectors.\n");
    4729             : 
    4730           4 :             CATCH_REQUIRE(c.get_root() == n);
    4731           4 :         }
    4732             : 
    4733             :         // no error left over
    4734           1 :         VERIFY_ERRORS("");
    4735             :     }
    4736             : 
    4737             :     // check the few invalid characters before "identifier ':' ..."
    4738             :     {
    4739           1 :         std::stringstream ss;
    4740             :         ss << "div {\n"
    4741             :            << "  *border: 1px solid #fff;\n"
    4742             :            << "  .filter: opacity(0.2);\n"
    4743             :            << "  #color: chocolate;\n"
    4744             :            << "  !exclamation: 100px * 3;\n"
    4745           1 :            << "}\n";
    4746           3 :         csspp::position pos("test.css");
    4747           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4748             : 
    4749           2 :         csspp::parser p(l);
    4750             : 
    4751           1 :         csspp::node::pointer_t n(p.stylesheet());
    4752             : 
    4753             :         // no errors so far
    4754           1 :         VERIFY_ERRORS("");
    4755             : 
    4756           1 :         csspp::compiler c;
    4757           1 :         c.set_root(n);
    4758           1 :         c.clear_paths();
    4759           1 :         c.add_path(csspp_test::get_script_path());
    4760           1 :         c.add_path(csspp_test::get_version_script_path());
    4761             : 
    4762           1 :         c.compile(true);
    4763             : 
    4764             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    4765             : 
    4766           1 :         VERIFY_ERRORS(
    4767             :                 "test.css(2): warning: the '[*|.|!]<field-name>: ...' syntax is not allowed in csspp, we offer other ways to control field names per browser and do not allow such tricks.\n"
    4768             :                 "test.css(3): warning: the '[*|.|!]<field-name>: ...' syntax is not allowed in csspp, we offer other ways to control field names per browser and do not allow such tricks.\n"
    4769             :                 "test.css(3): warning: the alpha(), chroma() and similar functions of the filter field are Internet Explorer specific extensions which are not supported across browsers.\n"
    4770             :                 "test.css(4): warning: the '#<field-name>: ...' syntax is not allowed in csspp, we offer other ways to control field names per browser and do not allow such tricks.\n"
    4771             :                 "test.css(5): warning: the '#<field-name>: ...' syntax is not allowed in csspp, we offer other ways to control field names per browser and do not allow such tricks.\n"
    4772             :             );
    4773             : 
    4774           1 :         std::stringstream out;
    4775           1 :         out << *n;
    4776           1 :         VERIFY_TREES(out.str(),
    4777             : 
    4778             : "LIST\n"
    4779             : "  COMPONENT_VALUE\n"
    4780             : "    ARG\n"
    4781             : "      IDENTIFIER \"div\"\n"
    4782             : "    OPEN_CURLYBRACKET B:true\n"
    4783             : "      LIST\n"
    4784             : "        DECLARATION \"border\"\n"
    4785             : "          ARG\n"
    4786             : "            INTEGER \"px\" I:1\n"
    4787             : "            WHITESPACE\n"
    4788             : "            IDENTIFIER \"solid\"\n"
    4789             : "            WHITESPACE\n"
    4790             : "            COLOR H:ffffffff\n"
    4791             : "        DECLARATION \"filter\"\n"
    4792             : "          FUNCTION \"opacity\"\n"
    4793             : "            DECIMAL_NUMBER \"\" D:0.2\n"
    4794             : "        DECLARATION \"color\"\n"
    4795             : "          ARG\n"
    4796             : "            COLOR H:ff1e69d2\n"
    4797             : "        DECLARATION \"exclamation\"\n"
    4798             : "          ARG\n"
    4799             : "            INTEGER \"px\" I:300\n"
    4800             : 
    4801             :             );
    4802             : 
    4803           1 :         CATCH_REQUIRE(c.get_root() == n);
    4804             : 
    4805             :         // no error left over
    4806           1 :         VERIFY_ERRORS("");
    4807           1 :     }
    4808             : 
    4809             :     // check that & cannot be used in the middle of a selector list
    4810             :     {
    4811           1 :         std::stringstream ss;
    4812             :         ss << "div {\n"
    4813             :            << "  span &:hover {\n"
    4814             :            << "    border: 1px solid #fff;\n"
    4815             :            << "  }\n"
    4816           1 :            << "}\n";
    4817           3 :         csspp::position pos("test.css");
    4818           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4819             : 
    4820           2 :         csspp::parser p(l);
    4821             : 
    4822           1 :         csspp::node::pointer_t n(p.stylesheet());
    4823             : 
    4824             :         // no errors so far
    4825           1 :         VERIFY_ERRORS("");
    4826             : 
    4827           1 :         csspp::compiler c;
    4828           1 :         c.set_root(n);
    4829           1 :         c.clear_paths();
    4830           1 :         c.add_path(csspp_test::get_script_path());
    4831           1 :         c.add_path(csspp_test::get_version_script_path());
    4832             : 
    4833           1 :         c.compile(true);
    4834             : 
    4835             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    4836             : 
    4837           1 :         VERIFY_ERRORS(
    4838             :                 "test.css(1): error: a selector reference (&) can only appear as the very first item in a list of selectors.\n"
    4839             :             );
    4840             : 
    4841           1 :         CATCH_REQUIRE(c.get_root() == n);
    4842           1 :     }
    4843             : 
    4844             :     // no left over?
    4845           1 :     VERIFY_ERRORS("");
    4846           1 : }
    4847             : 
    4848           1 : CATCH_TEST_CASE("Invalid node", "[compiler] [invalid]")
    4849             : {
    4850             :     // create a fake node tree with some invalid node types to
    4851             :     // exercise the compile() switch default entry
    4852             :     {
    4853           1 :         csspp::node_type_t invalid_types[] =
    4854             :         {
    4855             :             csspp::node_type_t::COMMA,
    4856             :             csspp::node_type_t::ADD,
    4857             :             csspp::node_type_t::CLOSE_CURLYBRACKET,
    4858             :         };
    4859             : 
    4860           4 :         for(size_t idx(0); idx < sizeof(invalid_types) / sizeof(invalid_types[0]); ++idx)
    4861             :         {
    4862           9 :             csspp::position pos("invalid-types.scss");
    4863           3 :             csspp::node::pointer_t n(new csspp::node(invalid_types[idx], pos));
    4864             : 
    4865           3 :             csspp::compiler c;
    4866           3 :             c.set_root(n);
    4867           3 :             c.clear_paths();
    4868           3 :             c.add_path(csspp_test::get_script_path());
    4869           3 :             c.add_path(csspp_test::get_version_script_path());
    4870             : 
    4871           3 :             CATCH_REQUIRE_THROWS_AS(c.compile(true), csspp::csspp_exception_unexpected_token);
    4872             : 
    4873           3 :             CATCH_REQUIRE(c.get_root() == n);
    4874           3 :         }
    4875             :     }
    4876             : 
    4877             :     // qualified rule must start with an identifier
    4878             :     {
    4879           1 :         std::stringstream ss;
    4880           1 :         ss << "{color:red}";
    4881           3 :         csspp::position pos("test.css");
    4882           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4883             : 
    4884           2 :         csspp::parser p(l);
    4885             : 
    4886           1 :         csspp::node::pointer_t n(p.stylesheet());
    4887             : 
    4888             :         // no errors so far
    4889           1 :         VERIFY_ERRORS("");
    4890             : 
    4891           1 :         csspp::compiler c;
    4892           1 :         c.set_root(n);
    4893           1 :         c.clear_paths();
    4894           1 :         c.add_path(csspp_test::get_script_path());
    4895           1 :         c.add_path(csspp_test::get_version_script_path());
    4896             : 
    4897           1 :         c.compile(true);
    4898             : 
    4899           1 :         VERIFY_ERRORS("test.css(1): error: a qualified rule without selectors is not valid.\n");
    4900             : 
    4901           1 :         CATCH_REQUIRE(c.get_root() == n);
    4902           1 :     }
    4903             : 
    4904             :     // qualified rule must start with an identifier
    4905             :     {
    4906           1 :         std::stringstream ss;
    4907           1 :         ss << "this would be a declaration without a colon;";
    4908           3 :         csspp::position pos("test.css");
    4909           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4910             : 
    4911           2 :         csspp::parser p(l);
    4912             : 
    4913           1 :         csspp::node::pointer_t n(p.stylesheet());
    4914             : 
    4915             :         // the qualified rule is invalid...
    4916           1 :         VERIFY_ERRORS("test.css(1): error: A qualified rule must end with a { ... } block.\n");
    4917             : 
    4918             :         // ...but we still compile it so we get a specific error that we do
    4919             :         // not get otherwise.
    4920           1 :         csspp::compiler c;
    4921           1 :         c.set_root(n);
    4922           1 :         c.clear_paths();
    4923           1 :         c.add_path(csspp_test::get_script_path());
    4924           1 :         c.add_path(csspp_test::get_version_script_path());
    4925             : 
    4926           1 :         c.compile(true);
    4927             : 
    4928           1 :         VERIFY_ERRORS("test.css(1): error: expected a ':' after the identifier of this declaration value; got a: COMPONENT_VALUE instead.\n");
    4929             : 
    4930           1 :         CATCH_REQUIRE(c.get_root() == n);
    4931           1 :     }
    4932             : 
    4933             :     // a declaration needs an identifier
    4934             :     {
    4935           1 :         std::stringstream ss;
    4936           1 :         ss << "rule{+: red;}";
    4937           3 :         csspp::position pos("test.css");
    4938           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4939             : 
    4940           2 :         csspp::parser p(l);
    4941             : 
    4942           1 :         csspp::node::pointer_t n(p.stylesheet());
    4943             : 
    4944             :         // no errors so far
    4945           1 :         VERIFY_ERRORS("");
    4946             : 
    4947           1 :         csspp::compiler c;
    4948           1 :         c.set_root(n);
    4949           1 :         c.clear_paths();
    4950           1 :         c.add_path(csspp_test::get_script_path());
    4951           1 :         c.add_path(csspp_test::get_version_script_path());
    4952             : 
    4953           1 :         c.compile(true);
    4954             : 
    4955           1 :         VERIFY_ERRORS("test.css(1): error: expected an identifier to start a declaration value; got a: ADD instead.\n");
    4956             : 
    4957           1 :         CATCH_REQUIRE(c.get_root() == n);
    4958           1 :     }
    4959             : 
    4960             :     // a declaration needs an identifier
    4961             :     {
    4962           1 :         std::stringstream ss;
    4963             :         ss << "div {\n"
    4964             :            << "  font-size: 80%;\n"
    4965             :            << "  font-style; italic;\n"
    4966             :            << "  text-align: right;\n"
    4967           1 :            << "}\n";
    4968           3 :         csspp::position pos("test.css");
    4969           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    4970             : 
    4971           2 :         csspp::parser p(l);
    4972             : 
    4973           1 :         csspp::node::pointer_t n(p.stylesheet());
    4974             : 
    4975             :         // no errors so far
    4976           1 :         VERIFY_ERRORS("");
    4977             : 
    4978           1 :         csspp::compiler c;
    4979           1 :         c.set_root(n);
    4980           1 :         c.clear_paths();
    4981           1 :         c.add_path(csspp_test::get_script_path());
    4982           1 :         c.add_path(csspp_test::get_version_script_path());
    4983             : 
    4984           1 :         c.compile(true);
    4985             : 
    4986           1 :         VERIFY_ERRORS(
    4987             :                 "test.css(2): error: somehow a declaration list is missing a field name or ':'.\n"
    4988             :                 "test.css(3): error: somehow a declaration list is missing a field name or ':'.\n"
    4989             :             );
    4990             : 
    4991           1 :         CATCH_REQUIRE(c.get_root() == n);
    4992           1 :     }
    4993             : 
    4994             :     // no left over?
    4995           1 :     VERIFY_ERRORS("");
    4996           1 : }
    4997             : 
    4998           1 : CATCH_TEST_CASE("Compile font metrics", "[compiler] [font-metrics]")
    4999             : {
    5000             :     // define a sub-declaration inside a declaration
    5001             :     {
    5002           1 :         std::stringstream ss;
    5003             :         ss << "body {\n"
    5004             :            << "\tbackground-color: white;\n"
    5005             :            << "\tcolor: #333;\n"
    5006             :            << "\tfont: 62.5%/1.5 \"Helvetica Neue\", Helvetica, Verdana, Arial, FreeSans, \"Liberation Sans\", sans-serif;\n"
    5007           1 :            << "}\n";
    5008           3 :         csspp::position pos("test.css");
    5009           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5010             : 
    5011           2 :         csspp::parser p(l);
    5012             : 
    5013           1 :         csspp::node::pointer_t n(p.stylesheet());
    5014             : 
    5015             :         // no errors so far
    5016           1 :         VERIFY_ERRORS("");
    5017             : 
    5018           1 :         csspp::compiler c;
    5019           1 :         c.set_root(n);
    5020           1 :         c.clear_paths();
    5021           1 :         c.add_path(csspp_test::get_script_path());
    5022           1 :         c.add_path(csspp_test::get_version_script_path());
    5023             : 
    5024           1 :         c.compile(true);
    5025             : 
    5026             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5027             : 
    5028             :         //VERIFY_ERRORS("");
    5029             : 
    5030           1 :         std::stringstream out;
    5031           1 :         out << *n;
    5032           1 :         VERIFY_TREES(out.str(),
    5033             : 
    5034             : "LIST\n"
    5035             : "  COMPONENT_VALUE\n"
    5036             : "    ARG\n"
    5037             : "      IDENTIFIER \"body\"\n"
    5038             : "    OPEN_CURLYBRACKET B:true\n"
    5039             : "      LIST\n"
    5040             : "        DECLARATION \"background-color\"\n"
    5041             : "          ARG\n"
    5042             : "            COLOR H:ffffffff\n"
    5043             : "        DECLARATION \"color\"\n"
    5044             : "          ARG\n"
    5045             : "            COLOR H:ff333333\n"
    5046             : "        DECLARATION \"font\"\n"
    5047             : "          ARG\n"
    5048             : "            FONT_METRICS FM:62.5%/1.5\n"
    5049             : "            WHITESPACE\n"
    5050             : "            STRING \"Helvetica Neue\"\n"
    5051             : "          ARG\n"
    5052             : "            IDENTIFIER \"Helvetica\"\n"
    5053             : "          ARG\n"
    5054             : "            IDENTIFIER \"Verdana\"\n"
    5055             : "          ARG\n"
    5056             : "            IDENTIFIER \"Arial\"\n"
    5057             : "          ARG\n"
    5058             : "            IDENTIFIER \"FreeSans\"\n"
    5059             : "          ARG\n"
    5060             : "            STRING \"Liberation Sans\"\n"
    5061             : "          ARG\n"
    5062             : "            IDENTIFIER \"sans-serif\"\n"
    5063             : 
    5064             :             );
    5065             : 
    5066           1 :         CATCH_REQUIRE(c.get_root() == n);
    5067           1 :     }
    5068             : 
    5069             :     // define a sub-declaration inside a declaration
    5070             :     {
    5071           1 :         std::stringstream ss;
    5072             :         ss << "body {\n"
    5073             :            << "\tfont: 15pt/135% \"Helvetica Neue\", Helvetica, Verdana, Arial, FreeSans, \"Liberation Sans\", sans-serif;\n"
    5074             :            << "\tcolor: #333;\n"
    5075             :            << "\tbackground-color: white;\n"
    5076           1 :            << "}\n";
    5077           3 :         csspp::position pos("test.css");
    5078           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5079             : 
    5080           2 :         csspp::parser p(l);
    5081             : 
    5082           1 :         csspp::node::pointer_t n(p.stylesheet());
    5083             : 
    5084             :         // no errors so far
    5085           1 :         VERIFY_ERRORS("");
    5086             : 
    5087           1 :         csspp::compiler c;
    5088           1 :         c.set_root(n);
    5089           1 :         c.clear_paths();
    5090           1 :         c.add_path(csspp_test::get_script_path());
    5091           1 :         c.add_path(csspp_test::get_version_script_path());
    5092             : 
    5093           1 :         c.compile(true);
    5094             : 
    5095             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5096             : 
    5097             :         //VERIFY_ERRORS("");
    5098             : 
    5099           1 :         std::stringstream out;
    5100           1 :         out << *n;
    5101           1 :         VERIFY_TREES(out.str(),
    5102             : 
    5103             : "LIST\n"
    5104             : "  COMPONENT_VALUE\n"
    5105             : "    ARG\n"
    5106             : "      IDENTIFIER \"body\"\n"
    5107             : "    OPEN_CURLYBRACKET B:true\n"
    5108             : "      LIST\n"
    5109             : "        DECLARATION \"font\"\n"
    5110             : "          ARG\n"
    5111             : "            FONT_METRICS FM:15pt/135%\n"
    5112             : "            WHITESPACE\n"
    5113             : "            STRING \"Helvetica Neue\"\n"
    5114             : "          ARG\n"
    5115             : "            IDENTIFIER \"Helvetica\"\n"
    5116             : "          ARG\n"
    5117             : "            IDENTIFIER \"Verdana\"\n"
    5118             : "          ARG\n"
    5119             : "            IDENTIFIER \"Arial\"\n"
    5120             : "          ARG\n"
    5121             : "            IDENTIFIER \"FreeSans\"\n"
    5122             : "          ARG\n"
    5123             : "            STRING \"Liberation Sans\"\n"
    5124             : "          ARG\n"
    5125             : "            IDENTIFIER \"sans-serif\"\n"
    5126             : "        DECLARATION \"color\"\n"
    5127             : "          ARG\n"
    5128             : "            COLOR H:ff333333\n"
    5129             : "        DECLARATION \"background-color\"\n"
    5130             : "          ARG\n"
    5131             : "            COLOR H:ffffffff\n"
    5132             : 
    5133             :             );
    5134             : 
    5135           1 :         CATCH_REQUIRE(c.get_root() == n);
    5136           1 :     }
    5137             : 
    5138             :     // still no errors
    5139           1 :     VERIFY_ERRORS("");
    5140           1 : }
    5141             : 
    5142           1 : CATCH_TEST_CASE("Nested declarations", "[compiler] [nested]")
    5143             : {
    5144             :     // define a sub-declaration inside a declaration
    5145             :     {
    5146           1 :         std::stringstream ss;
    5147             :         ss << "div\n"
    5148             :            << "{\n"
    5149             :            << "  font:\n"
    5150             :            << "  {\n"
    5151             :            << "    color: red;\n"
    5152             :            << "    family: 34px white \n"
    5153             :            << "    {\n"
    5154             :            << "      name: helvetica;\n"
    5155             :            << "      group: sans-serif;\n"
    5156             :            << "    };\n"
    5157             :            << "    size: 3px + 5px;\n"
    5158             :            << "  };\n"
    5159             :            << "  a\n"
    5160             :            << "  {\n"
    5161             :            << "    text-decoration: underline;\n"
    5162             :            << "    &:hover\n"
    5163             :            << "    {\n"
    5164             :            << "      text-align: center;\n"
    5165             :            << "    }\n"
    5166             :            << "  }\n"
    5167           1 :            << "}\n";
    5168           3 :         csspp::position pos("test.css");
    5169           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5170             : 
    5171           2 :         csspp::parser p(l);
    5172             : 
    5173           1 :         csspp::node::pointer_t n(p.stylesheet());
    5174             : 
    5175             :         // no errors so far
    5176           1 :         VERIFY_ERRORS("");
    5177             : 
    5178           1 :         csspp::compiler c;
    5179           1 :         c.set_root(n);
    5180           1 :         c.clear_paths();
    5181           1 :         c.add_path(csspp_test::get_script_path());
    5182           1 :         c.add_path(csspp_test::get_version_script_path());
    5183             : 
    5184           1 :         c.compile(true);
    5185             : 
    5186             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5187             : 
    5188           1 :         VERIFY_ERRORS("");
    5189             : 
    5190           1 :         std::stringstream out;
    5191           1 :         out << *n;
    5192           1 :         VERIFY_TREES(out.str(),
    5193             : 
    5194             : "LIST\n"
    5195             : "  COMPONENT_VALUE\n"
    5196             : "    ARG\n"
    5197             : "      IDENTIFIER \"div\"\n"
    5198             : "    OPEN_CURLYBRACKET B:true\n"
    5199             : "      LIST\n"
    5200             : "        DECLARATION \"font-color\"\n"
    5201             : "          ARG\n"
    5202             : "            COLOR H:ff0000ff\n"
    5203             : "        DECLARATION \"font-family\"\n"
    5204             : "          ARG\n"
    5205             : "            INTEGER \"px\" I:34\n"
    5206             : "            WHITESPACE\n"
    5207             : "            COLOR H:ffffffff\n"
    5208             : "        DECLARATION \"font-family-name\"\n"
    5209             : "          ARG\n"
    5210             : "            IDENTIFIER \"helvetica\"\n"
    5211             : "        DECLARATION \"font-family-group\"\n"
    5212             : "          ARG\n"
    5213             : "            IDENTIFIER \"sans-serif\"\n"
    5214             : "        DECLARATION \"font-size\"\n"
    5215             : "          ARG\n"
    5216             : "            INTEGER \"px\" I:8\n"
    5217             : "  COMPONENT_VALUE\n"
    5218             : "    ARG\n"
    5219             : "      IDENTIFIER \"div\"\n"
    5220             : "      WHITESPACE\n"
    5221             : "      IDENTIFIER \"a\"\n"
    5222             : "    OPEN_CURLYBRACKET B:true\n"
    5223             : "      LIST\n"
    5224             : "        DECLARATION \"text-decoration\"\n"
    5225             : "          ARG\n"
    5226             : "            IDENTIFIER \"underline\"\n"
    5227             : "  COMPONENT_VALUE\n"
    5228             : "    ARG\n"
    5229             : "      IDENTIFIER \"div\"\n"
    5230             : "      WHITESPACE\n"
    5231             : "      IDENTIFIER \"a\"\n"
    5232             : "      COLON\n"
    5233             : "      IDENTIFIER \"hover\"\n"
    5234             : "    OPEN_CURLYBRACKET B:true\n"
    5235             : "      DECLARATION \"text-align\"\n"
    5236             : "        ARG\n"
    5237             : "          IDENTIFIER \"center\"\n"
    5238             : 
    5239             :             );
    5240             : 
    5241           1 :         CATCH_REQUIRE(c.get_root() == n);
    5242           1 :     }
    5243             : 
    5244             :     // define a sub-declaration inside a declaration
    5245             :     {
    5246           1 :         std::stringstream ss;
    5247             :         ss << "div { margin: { left: 300px + 51px / 3; top: 3px + 5px }; }"
    5248             :            << " $size: 300px;"
    5249           1 :            << " p { margin: 10px + $size * 3 25px - $size * 3 }";
    5250           3 :         csspp::position pos("test.css");
    5251           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5252             : 
    5253           2 :         csspp::parser p(l);
    5254             : 
    5255           1 :         csspp::node::pointer_t n(p.stylesheet());
    5256             : 
    5257             :         // no errors so far
    5258           1 :         VERIFY_ERRORS("");
    5259             : 
    5260           1 :         csspp::compiler c;
    5261           1 :         c.set_root(n);
    5262           1 :         c.clear_paths();
    5263           1 :         c.add_path(csspp_test::get_script_path());
    5264           1 :         c.add_path(csspp_test::get_version_script_path());
    5265             : 
    5266           1 :         c.compile(true);
    5267             : 
    5268             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5269             : 
    5270           1 :         VERIFY_ERRORS("");
    5271             : 
    5272           1 :         std::stringstream out;
    5273           1 :         out << *n;
    5274           1 :         VERIFY_TREES(out.str(),
    5275             : 
    5276             : "LIST\n"
    5277             : "    V:size\n"
    5278             : "      LIST\n"
    5279             : "        VARIABLE \"size\"\n"
    5280             : "        INTEGER \"px\" I:300\n"
    5281             : "  COMPONENT_VALUE\n"
    5282             : "    ARG\n"
    5283             : "      IDENTIFIER \"div\"\n"
    5284             : "    OPEN_CURLYBRACKET B:true\n"
    5285             : "      DECLARATION \"margin-left\"\n"
    5286             : "        ARG\n"
    5287             : "          INTEGER \"px\" I:317\n"
    5288             : "      DECLARATION \"margin-top\"\n"
    5289             : "        ARG\n"
    5290             : "          INTEGER \"px\" I:8\n"
    5291             : "  COMPONENT_VALUE\n"
    5292             : "    ARG\n"
    5293             : "      IDENTIFIER \"p\"\n"
    5294             : "    OPEN_CURLYBRACKET B:true\n"
    5295             : "      DECLARATION \"margin\"\n"
    5296             : "        ARG\n"
    5297             : "          INTEGER \"px\" I:910\n"
    5298             : "          WHITESPACE\n"
    5299             : "          INTEGER \"px\" I:-875\n"
    5300             : 
    5301             :             );
    5302             : 
    5303           1 :         CATCH_REQUIRE(c.get_root() == n);
    5304           1 :     }
    5305             : 
    5306           1 :     CATCH_START_SECTION("just one sub-declaration inside a field definition")
    5307             :     {
    5308           1 :         std::stringstream ss;
    5309           1 :         ss << "p.boxed { border: { width: 25px + 5px; }; }";
    5310           3 :         csspp::position pos("test.css");
    5311           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5312             : 
    5313           2 :         csspp::parser p(l);
    5314             : 
    5315           1 :         csspp::node::pointer_t n(p.stylesheet());
    5316             : 
    5317             :         // no errors so far
    5318           1 :         VERIFY_ERRORS("");
    5319             : 
    5320           1 :         csspp::compiler c;
    5321           1 :         c.set_root(n);
    5322           1 :         c.clear_paths();
    5323           1 :         c.add_path(csspp_test::get_script_path());
    5324           1 :         c.add_path(csspp_test::get_version_script_path());
    5325             : 
    5326           1 :         c.compile(true);
    5327             : 
    5328             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5329             : 
    5330           1 :         VERIFY_ERRORS("");
    5331             : 
    5332           1 :         std::stringstream out;
    5333           1 :         out << *n;
    5334           1 :         VERIFY_TREES(out.str(),
    5335             : 
    5336             : "LIST\n"
    5337             : "  COMPONENT_VALUE\n"
    5338             : "    ARG\n"
    5339             : "      IDENTIFIER \"p\"\n"
    5340             : "      PERIOD\n"
    5341             : "      IDENTIFIER \"boxed\"\n"
    5342             : "    OPEN_CURLYBRACKET B:true\n"
    5343             : "      DECLARATION \"border-width\"\n"
    5344             : "        ARG\n"
    5345             : "          INTEGER \"px\" I:30\n"
    5346             : 
    5347             :             );
    5348             : 
    5349           1 :         CATCH_REQUIRE(c.get_root() == n);
    5350           1 :     }
    5351           1 :     CATCH_END_SECTION()
    5352             : 
    5353             :     // define the sub-declaration in a variable
    5354             :     {
    5355           1 :         std::stringstream ss;
    5356             :         ss << "$m : { left: 300px + 51px / 3; top: 3px + 5px };"
    5357           1 :            << " div { margin: $m; }";
    5358           3 :         csspp::position pos("test.css");
    5359           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5360             : 
    5361           2 :         csspp::parser p(l);
    5362             : 
    5363           1 :         csspp::node::pointer_t n(p.stylesheet());
    5364             : 
    5365             :         // no errors so far
    5366           1 :         VERIFY_ERRORS("");
    5367             : 
    5368           1 :         csspp::compiler c;
    5369           1 :         c.set_root(n);
    5370           1 :         c.clear_paths();
    5371           1 :         c.add_path(csspp_test::get_script_path());
    5372           1 :         c.add_path(csspp_test::get_version_script_path());
    5373             : 
    5374           1 :         c.compile(true);
    5375             : 
    5376             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5377             : 
    5378           1 :         VERIFY_ERRORS("");
    5379             : 
    5380           1 :         std::stringstream out;
    5381           1 :         out << *n;
    5382           1 :         VERIFY_TREES(out.str(),
    5383             : 
    5384             : "LIST\n"
    5385             : "    V:m\n"
    5386             : "      LIST\n"
    5387             : "        VARIABLE \"m\"\n"
    5388             : "        OPEN_CURLYBRACKET B:false\n"
    5389             : "          LIST\n"
    5390             : "            COMPONENT_VALUE\n"
    5391             : "              IDENTIFIER \"left\"\n"
    5392             : "              COLON\n"
    5393             : "              WHITESPACE\n"
    5394             : "              INTEGER \"px\" I:300\n"
    5395             : "              WHITESPACE\n"
    5396             : "              ADD\n"
    5397             : "              WHITESPACE\n"
    5398             : "              INTEGER \"px\" I:51\n"
    5399             : "              WHITESPACE\n"
    5400             : "              DIVIDE\n"
    5401             : "              WHITESPACE\n"
    5402             : "              INTEGER \"\" I:3\n"
    5403             : "            COMPONENT_VALUE\n"
    5404             : "              IDENTIFIER \"top\"\n"
    5405             : "              COLON\n"
    5406             : "              WHITESPACE\n"
    5407             : "              INTEGER \"px\" I:3\n"
    5408             : "              WHITESPACE\n"
    5409             : "              ADD\n"
    5410             : "              WHITESPACE\n"
    5411             : "              INTEGER \"px\" I:5\n"
    5412             : "  COMPONENT_VALUE\n"
    5413             : "    ARG\n"
    5414             : "      IDENTIFIER \"div\"\n"
    5415             : "    OPEN_CURLYBRACKET B:true\n"
    5416             : "      DECLARATION \"margin-left\"\n"
    5417             : "        ARG\n"
    5418             : "          INTEGER \"px\" I:317\n"
    5419             : "      DECLARATION \"margin-top\"\n"
    5420             : "        ARG\n"
    5421             : "          INTEGER \"px\" I:8\n"
    5422             : 
    5423             :             );
    5424             : 
    5425           1 :         CATCH_REQUIRE(c.get_root() == n);
    5426           1 :     }
    5427             : 
    5428             :     // 5 levels nested declarations
    5429             :     {
    5430           1 :         std::stringstream ss;
    5431             :         ss << "border {\n"
    5432             :            << "  left: 0;\n"
    5433             :            << "  width {\n"
    5434             :            << "    right {\n"
    5435             :            << "      height: 300px + 51px / 3;\n"
    5436             :            << "      top {\n"
    5437             :            << "        color { edge: white; };\n"
    5438             :            << "        position: 3px + 5px;\n"
    5439             :            << "        chain { key: attached; };\n"
    5440             :            << "      };"
    5441             :            << "    };"
    5442             :            << "  };"
    5443             :            << "  height {\n"
    5444             :            << "    position: 33px;\n"
    5445             :            << "  };\n"
    5446           1 :            << "}";
    5447           3 :         csspp::position pos("test.css");
    5448           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5449             : 
    5450           2 :         csspp::parser p(l);
    5451             : 
    5452           1 :         csspp::node::pointer_t n(p.stylesheet());
    5453             : 
    5454             : //std::cerr << "Parser result is: [" << *n << "]\n";
    5455             : 
    5456             :         // no errors so far
    5457           1 :         VERIFY_ERRORS("");
    5458             : 
    5459           1 :         csspp::compiler c;
    5460           1 :         c.set_root(n);
    5461           1 :         c.clear_paths();
    5462           1 :         c.add_path(csspp_test::get_script_path());
    5463           1 :         c.add_path(csspp_test::get_version_script_path());
    5464             : 
    5465           1 :         c.compile(true);
    5466             : 
    5467             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5468             : 
    5469           1 :         VERIFY_ERRORS("");
    5470             : 
    5471           1 :         std::stringstream out;
    5472           1 :         out << *n;
    5473           1 :         VERIFY_TREES(out.str(),
    5474             : 
    5475             : "LIST\n"
    5476             : "  COMPONENT_VALUE\n"
    5477             : "    ARG\n"
    5478             : "      IDENTIFIER \"border\"\n"
    5479             : "    OPEN_CURLYBRACKET B:true\n"
    5480             : "      LIST\n"
    5481             : "        DECLARATION \"left\"\n"
    5482             : "          ARG\n"
    5483             : "            INTEGER \"\" I:0\n"
    5484             : "  COMPONENT_VALUE\n"
    5485             : "    ARG\n"
    5486             : "      IDENTIFIER \"border\"\n"
    5487             : "      WHITESPACE\n"
    5488             : "      IDENTIFIER \"width\"\n"
    5489             : "    OPEN_CURLYBRACKET B:true\n"
    5490             : "  COMPONENT_VALUE\n"
    5491             : "    ARG\n"
    5492             : "      IDENTIFIER \"border\"\n"
    5493             : "      WHITESPACE\n"
    5494             : "      IDENTIFIER \"width\"\n"
    5495             : "      WHITESPACE\n"
    5496             : "      IDENTIFIER \"right\"\n"
    5497             : "    OPEN_CURLYBRACKET B:true\n"
    5498             : "      LIST\n"
    5499             : "        DECLARATION \"height\"\n"
    5500             : "          ARG\n"
    5501             : "            INTEGER \"px\" I:317\n"
    5502             : "  COMPONENT_VALUE\n"
    5503             : "    ARG\n"
    5504             : "      IDENTIFIER \"border\"\n"
    5505             : "      WHITESPACE\n"
    5506             : "      IDENTIFIER \"width\"\n"
    5507             : "      WHITESPACE\n"
    5508             : "      IDENTIFIER \"right\"\n"
    5509             : "      WHITESPACE\n"
    5510             : "      IDENTIFIER \"top\"\n"
    5511             : "    OPEN_CURLYBRACKET B:true\n"
    5512             : "      LIST\n"
    5513             : "        DECLARATION \"position\"\n"
    5514             : "          ARG\n"
    5515             : "            INTEGER \"px\" I:8\n"
    5516             : "  COMPONENT_VALUE\n"
    5517             : "    ARG\n"
    5518             : "      IDENTIFIER \"border\"\n"
    5519             : "      WHITESPACE\n"
    5520             : "      IDENTIFIER \"width\"\n"
    5521             : "      WHITESPACE\n"
    5522             : "      IDENTIFIER \"right\"\n"
    5523             : "      WHITESPACE\n"
    5524             : "      IDENTIFIER \"top\"\n"
    5525             : "      WHITESPACE\n"
    5526             : "      IDENTIFIER \"color\"\n"
    5527             : "    OPEN_CURLYBRACKET B:true\n"
    5528             : "      DECLARATION \"edge\"\n"
    5529             : "        ARG\n"
    5530             : "          COLOR H:ffffffff\n"
    5531             : "  COMPONENT_VALUE\n"
    5532             : "    ARG\n"
    5533             : "      IDENTIFIER \"border\"\n"
    5534             : "      WHITESPACE\n"
    5535             : "      IDENTIFIER \"width\"\n"
    5536             : "      WHITESPACE\n"
    5537             : "      IDENTIFIER \"right\"\n"
    5538             : "      WHITESPACE\n"
    5539             : "      IDENTIFIER \"top\"\n"
    5540             : "      WHITESPACE\n"
    5541             : "      IDENTIFIER \"chain\"\n"
    5542             : "    OPEN_CURLYBRACKET B:true\n"
    5543             : "      DECLARATION \"key\"\n"
    5544             : "        ARG\n"
    5545             : "          IDENTIFIER \"attached\"\n"
    5546             : "  COMPONENT_VALUE\n"
    5547             : "    ARG\n"
    5548             : "      IDENTIFIER \"border\"\n"
    5549             : "      WHITESPACE\n"
    5550             : "      IDENTIFIER \"height\"\n"
    5551             : "    OPEN_CURLYBRACKET B:true\n"
    5552             : "      DECLARATION \"position\"\n"
    5553             : "        ARG\n"
    5554             : "          INTEGER \"px\" I:33\n"
    5555             : 
    5556             :             );
    5557             : 
    5558           1 :         CATCH_REQUIRE(c.get_root() == n);
    5559           1 :     }
    5560             : 
    5561             :     // Test that functions prevent a field to look like a declaration
    5562             :     {
    5563           1 :         std::stringstream ss;
    5564             :         ss << "border {\n"
    5565             :            << "  left:not(.long) div{color: red};\n"
    5566           1 :            << "}";
    5567           3 :         csspp::position pos("test.css");
    5568           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5569             : 
    5570           2 :         csspp::parser p(l);
    5571             : 
    5572           1 :         csspp::node::pointer_t n(p.stylesheet());
    5573             : 
    5574             : //std::cerr << "Parser result is: [" << *n << "]\n";
    5575             : 
    5576             :         // no errors so far
    5577           1 :         VERIFY_ERRORS("");
    5578             : 
    5579           1 :         csspp::compiler c;
    5580           1 :         c.set_root(n);
    5581           1 :         c.clear_paths();
    5582           1 :         c.add_path(csspp_test::get_script_path());
    5583           1 :         c.add_path(csspp_test::get_version_script_path());
    5584             : 
    5585           1 :         c.compile(true);
    5586             : 
    5587             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5588             : 
    5589           1 :         VERIFY_ERRORS("");
    5590             : 
    5591           1 :         std::stringstream out;
    5592           1 :         out << *n;
    5593           1 :         VERIFY_TREES(out.str(),
    5594             : 
    5595             :         //ss << "border {\n"
    5596             :         //   << "  left:not(.long) div{color: red};\n"
    5597             :         //   << "}";
    5598             : "LIST\n"
    5599             : "  COMPONENT_VALUE\n"
    5600             : "    ARG\n"
    5601             : "      IDENTIFIER \"border\"\n"
    5602             : "    OPEN_CURLYBRACKET B:true\n"
    5603             : "  COMPONENT_VALUE\n"
    5604             : "    ARG\n"
    5605             : "      IDENTIFIER \"border\"\n"
    5606             : "      WHITESPACE\n"
    5607             : "      IDENTIFIER \"left\"\n"
    5608             : "      COLON\n"
    5609             : "      FUNCTION \"not\"\n"
    5610             : "        PERIOD\n"
    5611             : "        IDENTIFIER \"long\"\n"
    5612             : "      WHITESPACE\n"
    5613             : "      IDENTIFIER \"div\"\n"
    5614             : "    OPEN_CURLYBRACKET B:true\n"
    5615             : "      DECLARATION \"color\"\n"
    5616             : "        ARG\n"
    5617             : "          COLOR H:ff0000ff\n"
    5618             : 
    5619             :             );
    5620             : 
    5621           1 :         CATCH_REQUIRE(c.get_root() == n);
    5622           1 :     }
    5623             : 
    5624             : //    // define the sub-declaration in a variable
    5625             : //    {
    5626             : //std::cerr << "------------------------------------------------ WORKING ON straight entry\n";
    5627             : //        std::stringstream ss;
    5628             : //        ss << "$m : left: 300px + 51px / 3; top: 3px + 5px;"
    5629             : //           << " div { margin: $m; }";
    5630             : //        csspp::position pos("test.css");
    5631             : //        csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5632             : //
    5633             : //        csspp::parser p(l);
    5634             : //
    5635             : //        csspp::node::pointer_t n(p.stylesheet());
    5636             : //
    5637             : //        // no errors so far
    5638             : //        VERIFY_ERRORS("");
    5639             : //
    5640             : //        csspp::compiler c;
    5641             : //        c.set_root(n);
    5642             : //        c.clear_paths();
    5643             : //        c.add_path(csspp_test::get_script_path());
    5644             : //        c.add_path(csspp_test::get_version_script_path());
    5645             : //
    5646             : //        c.compile(true);
    5647             : //
    5648             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5649             : //
    5650             : //        VERIFY_ERRORS("");
    5651             : //
    5652             : //        std::stringstream out;
    5653             : //        out << *n;
    5654             : //        VERIFY_TREES(out.str(),
    5655             : //
    5656             : //"LIST\n"
    5657             : //"    V:m\n"
    5658             : //"      OPEN_CURLYBRACKET\n"
    5659             : //"        COMPONENT_VALUE\n"
    5660             : //"          IDENTIFIER \"left\"\n"
    5661             : ////"          COLON\n"
    5662             : ////"          WHITESPACE\n"
    5663             : ////"          INTEGER \"px\" I:300\n"
    5664             : ////"          WHITESPACE\n"
    5665             : ////"          ADD\n"
    5666             : ////"          WHITESPACE\n"
    5667             : ////"          INTEGER \"px\" I:51\n"
    5668             : ////"          WHITESPACE\n"
    5669             : ////"          DIVIDE\n"
    5670             : ////"          WHITESPACE\n"
    5671             : ////"          INTEGER \"\" I:3\n"
    5672             : //"        COMPONENT_VALUE\n"
    5673             : //"          IDENTIFIER \"top\"\n"
    5674             : ////"          COLON\n"
    5675             : ////"          WHITESPACE\n"
    5676             : ////"          INTEGER \"px\" I:3\n"
    5677             : ////"          WHITESPACE\n"
    5678             : ////"          ADD\n"
    5679             : ////"          WHITESPACE\n"
    5680             : ////"          INTEGER \"px\" I:5\n"
    5681             : //"  COMPONENT_VALUE\n"
    5682             : //"    ARG\n"
    5683             : //"      IDENTIFIER \"div\"\n"
    5684             : //"    OPEN_CURLYBRACKET\n"
    5685             : //"      DECLARATION \"margin\"\n"
    5686             : //"        DECLARATION \"left\"\n"
    5687             : //"          INTEGER \"px\" I:317\n"
    5688             : //"        DECLARATION \"top\"\n"
    5689             : //"          INTEGER \"px\" I:8\n"
    5690             : //
    5691             : //            );
    5692             : //
    5693             : //        CATCH_REQUIRE(c.get_root() == n);
    5694             : //    }
    5695             : 
    5696             :     // no left over?
    5697           1 :     VERIFY_ERRORS("");
    5698           1 : }
    5699             : 
    5700           1 : CATCH_TEST_CASE("Invalid nested declarations", "[compiler] [nested] [invalid]")
    5701             : {
    5702             :     // define a sub-declaration inside a declaration
    5703             :     {
    5704           1 :         std::stringstream ss;
    5705             :         ss << "div\n"
    5706             :            << "{\n"
    5707             :            << "  font:\n"
    5708             :            << "  {\n"
    5709             :            << "    color: red;\n"
    5710             :            << "    span { margin: 0; }" // <- you cannot do that
    5711             :            << "  };\n"
    5712           1 :            << "}\n";
    5713           3 :         csspp::position pos("test.css");
    5714           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5715             : 
    5716           2 :         csspp::parser p(l);
    5717             : 
    5718           1 :         csspp::node::pointer_t n(p.stylesheet());
    5719             : 
    5720             :         // no errors so far
    5721           1 :         VERIFY_ERRORS("");
    5722             : 
    5723           1 :         csspp::compiler c;
    5724           1 :         c.set_root(n);
    5725           1 :         c.clear_paths();
    5726           1 :         c.add_path(csspp_test::get_script_path());
    5727           1 :         c.add_path(csspp_test::get_version_script_path());
    5728             : 
    5729           1 :         c.compile(true);
    5730             : 
    5731             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5732             : 
    5733           1 :         VERIFY_ERRORS("test.css(5): error: a nested declaration cannot include a rule.\n");
    5734             : 
    5735           1 :         CATCH_REQUIRE(c.get_root() == n);
    5736           1 :     }
    5737             : 
    5738             :     // no left over?
    5739           1 :     VERIFY_ERRORS("");
    5740           1 : }
    5741             : 
    5742           1 : CATCH_TEST_CASE("Advanced variables", "[compiler] [variable]")
    5743             : {
    5744             :     // define a variable function with a parameter
    5745             :     {
    5746           1 :         std::stringstream ss;
    5747             :         ss << "$m( $width, $border: 1px ) : { left: $width + 51px / 3; top: $border + 5px };"
    5748           1 :            << " div { margin: $m(300px, 3px); }";
    5749           3 :         csspp::position pos("test.css");
    5750           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5751             : 
    5752           2 :         csspp::parser p(l);
    5753             : 
    5754           1 :         csspp::node::pointer_t n(p.stylesheet());
    5755             : 
    5756             : //std::cerr << "Parser result is: [" << *n << "]\n";
    5757             : 
    5758             :         // no errors so far
    5759           1 :         VERIFY_ERRORS("");
    5760             : 
    5761           1 :         csspp::compiler c;
    5762           1 :         c.set_root(n);
    5763           1 :         c.clear_paths();
    5764           1 :         c.add_path(csspp_test::get_script_path());
    5765           1 :         c.add_path(csspp_test::get_version_script_path());
    5766             : 
    5767           1 :         c.compile(true);
    5768             : 
    5769             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5770             : 
    5771           1 :         VERIFY_ERRORS("");
    5772             : 
    5773           1 :         std::stringstream out;
    5774           1 :         out << *n;
    5775           1 :         VERIFY_TREES(out.str(),
    5776             : 
    5777             : "LIST\n"
    5778             : "    V:m\n"
    5779             : "      LIST\n"
    5780             : "        VARIABLE_FUNCTION \"m\"\n"
    5781             : "          ARG\n"
    5782             : "            VARIABLE \"width\"\n"
    5783             : "          ARG\n"
    5784             : "            VARIABLE \"border\"\n"
    5785             : "            INTEGER \"px\" I:1\n"
    5786             : "        OPEN_CURLYBRACKET B:false\n"
    5787             : "          LIST\n"
    5788             : "            COMPONENT_VALUE\n"
    5789             : "              IDENTIFIER \"left\"\n"
    5790             : "              COLON\n"
    5791             : "              WHITESPACE\n"
    5792             : "              VARIABLE \"width\"\n"
    5793             : "              WHITESPACE\n"
    5794             : "              ADD\n"
    5795             : "              WHITESPACE\n"
    5796             : "              INTEGER \"px\" I:51\n"
    5797             : "              WHITESPACE\n"
    5798             : "              DIVIDE\n"
    5799             : "              WHITESPACE\n"
    5800             : "              INTEGER \"\" I:3\n"
    5801             : "            COMPONENT_VALUE\n"
    5802             : "              IDENTIFIER \"top\"\n"
    5803             : "              COLON\n"
    5804             : "              WHITESPACE\n"
    5805             : "              VARIABLE \"border\"\n"
    5806             : "              WHITESPACE\n"
    5807             : "              ADD\n"
    5808             : "              WHITESPACE\n"
    5809             : "              INTEGER \"px\" I:5\n"
    5810             : "  COMPONENT_VALUE\n"
    5811             : "    ARG\n"
    5812             : "      IDENTIFIER \"div\"\n"
    5813             : "    OPEN_CURLYBRACKET B:true\n"
    5814             : "      DECLARATION \"margin-left\"\n"
    5815             : "        ARG\n"
    5816             : "          INTEGER \"px\" I:317\n"
    5817             : "      DECLARATION \"margin-top\"\n"
    5818             : "        ARG\n"
    5819             : "          INTEGER \"px\" I:8\n"
    5820             : 
    5821             :             );
    5822             : 
    5823           1 :         CATCH_REQUIRE(c.get_root() == n);
    5824           1 :     }
    5825             : 
    5826             :     // define a variable function with a parameter and more spaces
    5827             :     {
    5828           1 :         std::stringstream ss;
    5829             :         ss << "$m( $width, $border : 1px ) : { left: $width + 51px / 3; top: $border + 5px };"
    5830           1 :            << " div { margin: $m(300px, 3px); }";
    5831           3 :         csspp::position pos("test.css");
    5832           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5833             : 
    5834           2 :         csspp::parser p(l);
    5835             : 
    5836           1 :         csspp::node::pointer_t n(p.stylesheet());
    5837             : 
    5838             :         // no errors so far
    5839           1 :         VERIFY_ERRORS("");
    5840             : 
    5841           1 :         csspp::compiler c;
    5842           1 :         c.set_root(n);
    5843           1 :         c.clear_paths();
    5844           1 :         c.add_path(csspp_test::get_script_path());
    5845           1 :         c.add_path(csspp_test::get_version_script_path());
    5846             : 
    5847           1 :         c.compile(true);
    5848             : 
    5849             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5850             : 
    5851           1 :         VERIFY_ERRORS("");
    5852             : 
    5853           1 :         std::stringstream out;
    5854           1 :         out << *n;
    5855           1 :         VERIFY_TREES(out.str(),
    5856             : 
    5857             : "LIST\n"
    5858             : "    V:m\n"
    5859             : "      LIST\n"
    5860             : "        VARIABLE_FUNCTION \"m\"\n"
    5861             : "          ARG\n"
    5862             : "            VARIABLE \"width\"\n"
    5863             : "          ARG\n"
    5864             : "            VARIABLE \"border\"\n"
    5865             : "            INTEGER \"px\" I:1\n"
    5866             : "        OPEN_CURLYBRACKET B:false\n"
    5867             : "          LIST\n"
    5868             : "            COMPONENT_VALUE\n"
    5869             : "              IDENTIFIER \"left\"\n"
    5870             : "              COLON\n"
    5871             : "              WHITESPACE\n"
    5872             : "              VARIABLE \"width\"\n"
    5873             : "              WHITESPACE\n"
    5874             : "              ADD\n"
    5875             : "              WHITESPACE\n"
    5876             : "              INTEGER \"px\" I:51\n"
    5877             : "              WHITESPACE\n"
    5878             : "              DIVIDE\n"
    5879             : "              WHITESPACE\n"
    5880             : "              INTEGER \"\" I:3\n"
    5881             : "            COMPONENT_VALUE\n"
    5882             : "              IDENTIFIER \"top\"\n"
    5883             : "              COLON\n"
    5884             : "              WHITESPACE\n"
    5885             : "              VARIABLE \"border\"\n"
    5886             : "              WHITESPACE\n"
    5887             : "              ADD\n"
    5888             : "              WHITESPACE\n"
    5889             : "              INTEGER \"px\" I:5\n"
    5890             : "  COMPONENT_VALUE\n"
    5891             : "    ARG\n"
    5892             : "      IDENTIFIER \"div\"\n"
    5893             : "    OPEN_CURLYBRACKET B:true\n"
    5894             : "      DECLARATION \"margin-left\"\n"
    5895             : "        ARG\n"
    5896             : "          INTEGER \"px\" I:317\n"
    5897             : "      DECLARATION \"margin-top\"\n"
    5898             : "        ARG\n"
    5899             : "          INTEGER \"px\" I:8\n"
    5900             : 
    5901             :             );
    5902             : 
    5903           1 :         CATCH_REQUIRE(c.get_root() == n);
    5904           1 :     }
    5905             : 
    5906             :     // test a variable function default parameter
    5907             :     {
    5908           1 :         std::stringstream ss;
    5909             :         ss << "$m( $width, $border: 1px ) : { left: $width + 51px / 3; top: $border + 5px };"
    5910           1 :            << " div { margin: $m(300px); }";
    5911           3 :         csspp::position pos("test.css");
    5912           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5913             : 
    5914           2 :         csspp::parser p(l);
    5915             : 
    5916           1 :         csspp::node::pointer_t n(p.stylesheet());
    5917             : 
    5918             :         // no errors so far
    5919           1 :         VERIFY_ERRORS("");
    5920             : 
    5921           1 :         csspp::compiler c;
    5922           1 :         c.set_root(n);
    5923           1 :         c.clear_paths();
    5924           1 :         c.add_path(csspp_test::get_script_path());
    5925           1 :         c.add_path(csspp_test::get_version_script_path());
    5926             : 
    5927           1 :         c.compile(true);
    5928             : 
    5929             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    5930             : 
    5931           1 :         VERIFY_ERRORS("");
    5932             : 
    5933           1 :         std::stringstream out;
    5934           1 :         out << *n;
    5935           1 :         VERIFY_TREES(out.str(),
    5936             : 
    5937             : "LIST\n"
    5938             : "    V:m\n"
    5939             : "      LIST\n"
    5940             : "        VARIABLE_FUNCTION \"m\"\n"
    5941             : "          ARG\n"
    5942             : "            VARIABLE \"width\"\n"
    5943             : "          ARG\n"
    5944             : "            VARIABLE \"border\"\n"
    5945             : "            INTEGER \"px\" I:1\n"
    5946             : "        OPEN_CURLYBRACKET B:false\n"
    5947             : "          LIST\n"
    5948             : "            COMPONENT_VALUE\n"
    5949             : "              IDENTIFIER \"left\"\n"
    5950             : "              COLON\n"
    5951             : "              WHITESPACE\n"
    5952             : "              VARIABLE \"width\"\n"
    5953             : "              WHITESPACE\n"
    5954             : "              ADD\n"
    5955             : "              WHITESPACE\n"
    5956             : "              INTEGER \"px\" I:51\n"
    5957             : "              WHITESPACE\n"
    5958             : "              DIVIDE\n"
    5959             : "              WHITESPACE\n"
    5960             : "              INTEGER \"\" I:3\n"
    5961             : "            COMPONENT_VALUE\n"
    5962             : "              IDENTIFIER \"top\"\n"
    5963             : "              COLON\n"
    5964             : "              WHITESPACE\n"
    5965             : "              VARIABLE \"border\"\n"
    5966             : "              WHITESPACE\n"
    5967             : "              ADD\n"
    5968             : "              WHITESPACE\n"
    5969             : "              INTEGER \"px\" I:5\n"
    5970             : "  COMPONENT_VALUE\n"
    5971             : "    ARG\n"
    5972             : "      IDENTIFIER \"div\"\n"
    5973             : "    OPEN_CURLYBRACKET B:true\n"
    5974             : "      DECLARATION \"margin-left\"\n"
    5975             : "        ARG\n"
    5976             : "          INTEGER \"px\" I:317\n"
    5977             : "      DECLARATION \"margin-top\"\n"
    5978             : "        ARG\n"
    5979             : "          INTEGER \"px\" I:6\n"
    5980             : 
    5981             :             );
    5982             : 
    5983           1 :         CATCH_REQUIRE(c.get_root() == n);
    5984           1 :     }
    5985             : 
    5986             :     // a multi value default
    5987             :     {
    5988           1 :         std::stringstream ss;
    5989             :         ss << "$m( $width, $border: 1px 3px ) : { left: $width + 51px / 3; top: $border };"
    5990           1 :            << " div { margin: $m(300px); }";
    5991           3 :         csspp::position pos("test.css");
    5992           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    5993             : 
    5994           2 :         csspp::parser p(l);
    5995             : 
    5996           1 :         csspp::node::pointer_t n(p.stylesheet());
    5997             : 
    5998             :         // no errors so far
    5999           1 :         VERIFY_ERRORS("");
    6000             : 
    6001           1 :         csspp::compiler c;
    6002           1 :         c.set_root(n);
    6003           1 :         c.clear_paths();
    6004           1 :         c.add_path(csspp_test::get_script_path());
    6005           1 :         c.add_path(csspp_test::get_version_script_path());
    6006             : 
    6007           1 :         c.compile(true);
    6008             : 
    6009             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6010             : 
    6011           1 :         VERIFY_ERRORS("");
    6012             : 
    6013           1 :         std::stringstream out;
    6014           1 :         out << *n;
    6015           1 :         VERIFY_TREES(out.str(),
    6016             : 
    6017             : "LIST\n"
    6018             : "    V:m\n"
    6019             : "      LIST\n"
    6020             : "        VARIABLE_FUNCTION \"m\"\n"
    6021             : "          ARG\n"
    6022             : "            VARIABLE \"width\"\n"
    6023             : "          ARG\n"
    6024             : "            VARIABLE \"border\"\n"
    6025             : "            INTEGER \"px\" I:1\n"
    6026             : "            WHITESPACE\n"
    6027             : "            INTEGER \"px\" I:3\n"
    6028             : "        OPEN_CURLYBRACKET B:false\n"
    6029             : "          LIST\n"
    6030             : "            COMPONENT_VALUE\n"
    6031             : "              IDENTIFIER \"left\"\n"
    6032             : "              COLON\n"
    6033             : "              WHITESPACE\n"
    6034             : "              VARIABLE \"width\"\n"
    6035             : "              WHITESPACE\n"
    6036             : "              ADD\n"
    6037             : "              WHITESPACE\n"
    6038             : "              INTEGER \"px\" I:51\n"
    6039             : "              WHITESPACE\n"
    6040             : "              DIVIDE\n"
    6041             : "              WHITESPACE\n"
    6042             : "              INTEGER \"\" I:3\n"
    6043             : "            COMPONENT_VALUE\n"
    6044             : "              IDENTIFIER \"top\"\n"
    6045             : "              COLON\n"
    6046             : "              WHITESPACE\n"
    6047             : "              VARIABLE \"border\"\n"
    6048             : "  COMPONENT_VALUE\n"
    6049             : "    ARG\n"
    6050             : "      IDENTIFIER \"div\"\n"
    6051             : "    OPEN_CURLYBRACKET B:true\n"
    6052             : "      DECLARATION \"margin-left\"\n"
    6053             : "        ARG\n"
    6054             : "          INTEGER \"px\" I:317\n"
    6055             : "      DECLARATION \"margin-top\"\n"
    6056             : "        ARG\n"
    6057             : "          INTEGER \"px\" I:1\n"
    6058             : "          WHITESPACE\n"
    6059             : "          INTEGER \"px\" I:3\n"
    6060             : 
    6061             :             );
    6062             : 
    6063           1 :         CATCH_REQUIRE(c.get_root() == n);
    6064           1 :     }
    6065             : 
    6066             :     // a variable function with multiple fields copied
    6067             :     {
    6068           1 :         std::stringstream ss;
    6069             :         ss << "$m( $border ) : { $border };"
    6070           1 :            << " br { border: $m(3px 1px 2px 4px); }";
    6071           3 :         csspp::position pos("test.css");
    6072           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6073             : 
    6074           2 :         csspp::parser p(l);
    6075             : 
    6076           1 :         csspp::node::pointer_t n(p.stylesheet());
    6077             : 
    6078             : //std::cerr << "Parser result is: [" << *n << "]\n";
    6079             : 
    6080             :         // no errors so far
    6081           1 :         VERIFY_ERRORS("");
    6082             : 
    6083           1 :         csspp::compiler c;
    6084           1 :         c.set_root(n);
    6085           1 :         c.clear_paths();
    6086           1 :         c.add_path(csspp_test::get_script_path());
    6087           1 :         c.add_path(csspp_test::get_version_script_path());
    6088             : 
    6089           1 :         c.compile(true);
    6090             : 
    6091             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6092             : 
    6093           1 :         VERIFY_ERRORS("");
    6094             : 
    6095           1 :         std::stringstream out;
    6096           1 :         out << *n;
    6097           1 :         VERIFY_TREES(out.str(),
    6098             : 
    6099             : "LIST\n"
    6100             : "    V:m\n"
    6101             : "      LIST\n"
    6102             : "        VARIABLE_FUNCTION \"m\"\n"
    6103             : "          ARG\n"
    6104             : "            VARIABLE \"border\"\n"
    6105             : "        OPEN_CURLYBRACKET B:false\n"
    6106             : "          COMPONENT_VALUE\n"
    6107             : "            VARIABLE \"border\"\n"
    6108             : "  COMPONENT_VALUE\n"
    6109             : "    ARG\n"
    6110             : "      IDENTIFIER \"br\"\n"
    6111             : "    OPEN_CURLYBRACKET B:true\n"
    6112             : "      DECLARATION \"border\"\n"
    6113             : "        ARG\n"
    6114             : "          INTEGER \"px\" I:3\n"
    6115             : "          WHITESPACE\n"
    6116             : "          INTEGER \"px\" I:1\n"
    6117             : "          WHITESPACE\n"
    6118             : "          INTEGER \"px\" I:2\n"
    6119             : "          WHITESPACE\n"
    6120             : "          INTEGER \"px\" I:4\n"
    6121             : 
    6122             :             );
    6123             : 
    6124           1 :         CATCH_REQUIRE(c.get_root() == n);
    6125           1 :     }
    6126             : 
    6127             :     // test a default variable
    6128             :     {
    6129           1 :         std::stringstream ss;
    6130             :         ss << "$m : 300px;\n"
    6131             :            << "$m : 53px !default;\n"
    6132           1 :            << "div { margin: $m; }";
    6133           3 :         csspp::position pos("test.css");
    6134           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6135             : 
    6136           2 :         csspp::parser p(l);
    6137             : 
    6138           1 :         csspp::node::pointer_t n(p.stylesheet());
    6139             : 
    6140             :         // no errors so far
    6141           1 :         VERIFY_ERRORS("");
    6142             : 
    6143           1 :         csspp::compiler c;
    6144           1 :         c.set_root(n);
    6145           1 :         c.clear_paths();
    6146           1 :         c.add_path(csspp_test::get_script_path());
    6147           1 :         c.add_path(csspp_test::get_version_script_path());
    6148             : 
    6149           1 :         c.compile(true);
    6150             : 
    6151             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6152             : 
    6153           1 :         VERIFY_ERRORS("");
    6154             : 
    6155           1 :         std::stringstream out;
    6156           1 :         out << *n;
    6157           1 :         VERIFY_TREES(out.str(),
    6158             : 
    6159             : "LIST\n"
    6160             : "    V:m\n"
    6161             : "      LIST\n"
    6162             : "        VARIABLE \"m\"\n"
    6163             : "        INTEGER \"px\" I:300\n"
    6164             : "  COMPONENT_VALUE\n"
    6165             : "    ARG\n"
    6166             : "      IDENTIFIER \"div\"\n"
    6167             : "    OPEN_CURLYBRACKET B:true\n"
    6168             : "      DECLARATION \"margin\"\n"
    6169             : "        ARG\n"
    6170             : "          INTEGER \"px\" I:300\n"
    6171             : 
    6172             :             );
    6173             : 
    6174           1 :         CATCH_REQUIRE(c.get_root() == n);
    6175           1 :     }
    6176             : 
    6177             :     // test a variable inside a qualified rule {}-block
    6178             :     {
    6179           1 :         std::stringstream ss;
    6180             :         ss << "div { $size: 300px;\n"
    6181             :            << " entry: {\n"
    6182             :            << "   width: $size;\n"
    6183             :            << "   height: $size * 3 / 4;\n"
    6184             :            << " };\n"
    6185             :            << " junior: $size + 13px;\n"
    6186           1 :            << "}";
    6187           3 :         csspp::position pos("test.css");
    6188           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6189             : 
    6190           2 :         csspp::parser p(l);
    6191             : 
    6192           1 :         csspp::node::pointer_t n(p.stylesheet());
    6193             : 
    6194             : //std::cerr << "Parser result is: [" << *n << "]\n";
    6195             : 
    6196             :         // no errors so far
    6197           1 :         VERIFY_ERRORS("");
    6198             : 
    6199           1 :         csspp::compiler c;
    6200           1 :         c.set_root(n);
    6201           1 :         c.clear_paths();
    6202           1 :         c.add_path(csspp_test::get_script_path());
    6203           1 :         c.add_path(csspp_test::get_version_script_path());
    6204             : 
    6205           1 :         c.compile(true);
    6206             : 
    6207             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6208             : 
    6209           1 :         VERIFY_ERRORS("");
    6210             : 
    6211           1 :         std::stringstream out;
    6212           1 :         out << *n;
    6213           1 :         VERIFY_TREES(out.str(),
    6214             : 
    6215             : "LIST\n"
    6216             : "  COMPONENT_VALUE\n"
    6217             : "    ARG\n"
    6218             : "      IDENTIFIER \"div\"\n"
    6219             : "    OPEN_CURLYBRACKET B:true\n"
    6220             : "        V:size\n"
    6221             : "          LIST\n"
    6222             : "            VARIABLE \"size\"\n"
    6223             : "            INTEGER \"px\" I:300\n"
    6224             : "      LIST\n"
    6225             : "        DECLARATION \"entry-width\"\n"
    6226             : "          ARG\n"
    6227             : "            INTEGER \"px\" I:300\n"
    6228             : "        DECLARATION \"entry-height\"\n"
    6229             : "          ARG\n"
    6230             : "            INTEGER \"px\" I:225\n"
    6231             : "        DECLARATION \"junior\"\n"
    6232             : "          ARG\n"
    6233             : "            INTEGER \"px\" I:313\n"
    6234             : 
    6235             :             );
    6236             : 
    6237           1 :         CATCH_REQUIRE(c.get_root() == n);
    6238           1 :     }
    6239             : 
    6240             :     // test that blocks define locations to save variables as expected
    6241             :     {
    6242           1 :         std::stringstream ss;
    6243             :         ss << "$size: 100px;\n"
    6244             :            << "div { $size: 300px;\n"
    6245             :            << " entry: {\n"
    6246             :            << "   $size: 50px;\n"
    6247             :            << "   width: $size;\n"
    6248             :            << "   height: $size * 3 / 4;\n"
    6249             :            << " };\n"
    6250             :            << " junior: $size + 13px;\n"
    6251             :            << "}\n"
    6252           1 :            << "section { diameter: $size }\n";
    6253           3 :         csspp::position pos("test.css");
    6254           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6255             : 
    6256           2 :         csspp::parser p(l);
    6257             : 
    6258           1 :         csspp::node::pointer_t n(p.stylesheet());
    6259             : 
    6260             :         // no errors so far
    6261           1 :         VERIFY_ERRORS("");
    6262             : 
    6263           1 :         csspp::compiler c;
    6264           1 :         c.set_root(n);
    6265           1 :         c.clear_paths();
    6266           1 :         c.add_path(csspp_test::get_script_path());
    6267           1 :         c.add_path(csspp_test::get_version_script_path());
    6268             : 
    6269           1 :         c.compile(true);
    6270             : 
    6271             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6272             : 
    6273           1 :         VERIFY_ERRORS("");
    6274             : 
    6275           1 :         std::stringstream out;
    6276           1 :         out << *n;
    6277           1 :         VERIFY_TREES(out.str(),
    6278             : 
    6279             : "LIST\n"
    6280             : "    V:size\n"
    6281             : "      LIST\n"
    6282             : "        VARIABLE \"size\"\n"
    6283             : "        INTEGER \"px\" I:100\n"
    6284             : "  COMPONENT_VALUE\n"
    6285             : "    ARG\n"
    6286             : "      IDENTIFIER \"div\"\n"
    6287             : "    OPEN_CURLYBRACKET B:true\n"
    6288             : "        V:size\n"
    6289             : "          LIST\n"
    6290             : "            VARIABLE \"size\"\n"
    6291             : "            INTEGER \"px\" I:300\n"
    6292             : "      LIST\n"
    6293             : "        DECLARATION \"entry-width\"\n"
    6294             : "          ARG\n"
    6295             : "            INTEGER \"px\" I:50\n"
    6296             : "        DECLARATION \"entry-height\"\n"
    6297             : "          ARG\n"
    6298             : "            INTEGER \"px\" I:37\n"
    6299             : "        DECLARATION \"junior\"\n"
    6300             : "          ARG\n"
    6301             : "            INTEGER \"px\" I:313\n"
    6302             : "  COMPONENT_VALUE\n"
    6303             : "    ARG\n"
    6304             : "      IDENTIFIER \"section\"\n"
    6305             : "    OPEN_CURLYBRACKET B:true\n"
    6306             : "      DECLARATION \"diameter\"\n"
    6307             : "        ARG\n"
    6308             : "          INTEGER \"px\" I:100\n"
    6309             : 
    6310             :             );
    6311             : 
    6312           1 :         CATCH_REQUIRE(c.get_root() == n);
    6313           1 :     }
    6314             : 
    6315             :     // test that !global forces definitions to be global
    6316             :     {
    6317           1 :         std::stringstream ss;
    6318             :         ss << "$size: 100px;\n"
    6319             :            << "div { $size: 300px !global;\n"
    6320             :            << "  entry: {\n"
    6321             :            << "    $size: 50px ! global;\n"
    6322             :            << "    width: $size;\n"
    6323             :            << "    height: $size * 3 / 4;\n"
    6324             :            << "  };\n"
    6325             :            << "  junior: $size + 13px;\n"
    6326             :            << "}\n"
    6327           1 :            << "section { diameter: $size }\n";
    6328           3 :         csspp::position pos("test.css");
    6329           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6330             : 
    6331           2 :         csspp::parser p(l);
    6332             : 
    6333           1 :         csspp::node::pointer_t n(p.stylesheet());
    6334             : 
    6335             :         // no errors so far
    6336           1 :         VERIFY_ERRORS("");
    6337             : 
    6338           1 :         csspp::compiler c;
    6339           1 :         c.set_root(n);
    6340           1 :         c.clear_paths();
    6341           1 :         c.add_path(csspp_test::get_script_path());
    6342           1 :         c.add_path(csspp_test::get_version_script_path());
    6343             : 
    6344           1 :         c.compile(true);
    6345             : 
    6346             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6347             : 
    6348           1 :         VERIFY_ERRORS("");
    6349             : 
    6350           1 :         std::stringstream out;
    6351           1 :         out << *n;
    6352           1 :         VERIFY_TREES(out.str(),
    6353             : 
    6354             : "LIST\n"
    6355             : "    V:size\n"
    6356             : "      LIST\n"
    6357             : "        VARIABLE \"size\"\n"
    6358             : "        INTEGER \"px\" I:50\n"
    6359             : "  COMPONENT_VALUE\n"
    6360             : "    ARG\n"
    6361             : "      IDENTIFIER \"div\"\n"
    6362             : "    OPEN_CURLYBRACKET B:true\n"
    6363             : "      LIST\n"
    6364             : "        DECLARATION \"entry-width\"\n"
    6365             : "          ARG\n"
    6366             : "            INTEGER \"px\" I:50\n"
    6367             : "        DECLARATION \"entry-height\"\n"
    6368             : "          ARG\n"
    6369             : "            INTEGER \"px\" I:37\n"
    6370             : "        DECLARATION \"junior\"\n"
    6371             : "          ARG\n"
    6372             : "            INTEGER \"px\" I:63\n"
    6373             : "  COMPONENT_VALUE\n"
    6374             : "    ARG\n"
    6375             : "      IDENTIFIER \"section\"\n"
    6376             : "    OPEN_CURLYBRACKET B:true\n"
    6377             : "      DECLARATION \"diameter\"\n"
    6378             : "        ARG\n"
    6379             : "          INTEGER \"px\" I:50\n"
    6380             : 
    6381             :             );
    6382             : 
    6383           1 :         CATCH_REQUIRE(c.get_root() == n);
    6384           1 :     }
    6385             : 
    6386             :     // test that !default prevents redefinitions of existing variables
    6387             :     {
    6388           1 :         std::stringstream ss;
    6389             :         ss << "$size: 100px;\n"
    6390             :            << "div { $size: 300px !default;\n"
    6391             :            << "  entry: {\n"
    6392             :            << "    $size: 50px ! default;\n"
    6393             :            << "    width: $size;\n"
    6394             :            << "    height: $size * 3 / 4;\n"
    6395             :            << "  };\n"
    6396             :            << "  junior: $size + 13px;\n"
    6397             :            << "}\n"
    6398           1 :            << "section { diameter: $size }\n";
    6399           3 :         csspp::position pos("test.css");
    6400           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6401             : 
    6402           2 :         csspp::parser p(l);
    6403             : 
    6404           1 :         csspp::node::pointer_t n(p.stylesheet());
    6405             : 
    6406             :         // no errors so far
    6407           1 :         VERIFY_ERRORS("");
    6408             : 
    6409           1 :         csspp::compiler c;
    6410           1 :         c.set_root(n);
    6411           1 :         c.clear_paths();
    6412           1 :         c.add_path(csspp_test::get_script_path());
    6413           1 :         c.add_path(csspp_test::get_version_script_path());
    6414             : 
    6415           1 :         c.compile(true);
    6416             : 
    6417             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6418             : 
    6419           1 :         VERIFY_ERRORS("");
    6420             : 
    6421           1 :         std::stringstream out;
    6422           1 :         out << *n;
    6423           1 :         VERIFY_TREES(out.str(),
    6424             : 
    6425             : "LIST\n"
    6426             : "    V:size\n"
    6427             : "      LIST\n"
    6428             : "        VARIABLE \"size\"\n"
    6429             : "        INTEGER \"px\" I:100\n"
    6430             : "  COMPONENT_VALUE\n"
    6431             : "    ARG\n"
    6432             : "      IDENTIFIER \"div\"\n"
    6433             : "    OPEN_CURLYBRACKET B:true\n"
    6434             : "      LIST\n"
    6435             : "        DECLARATION \"entry-width\"\n"
    6436             : "          ARG\n"
    6437             : "            INTEGER \"px\" I:100\n"
    6438             : "        DECLARATION \"entry-height\"\n"
    6439             : "          ARG\n"
    6440             : "            INTEGER \"px\" I:75\n"
    6441             : "        DECLARATION \"junior\"\n"
    6442             : "          ARG\n"
    6443             : "            INTEGER \"px\" I:113\n"
    6444             : "  COMPONENT_VALUE\n"
    6445             : "    ARG\n"
    6446             : "      IDENTIFIER \"section\"\n"
    6447             : "    OPEN_CURLYBRACKET B:true\n"
    6448             : "      DECLARATION \"diameter\"\n"
    6449             : "        ARG\n"
    6450             : "          INTEGER \"px\" I:100\n"
    6451             : 
    6452             :             );
    6453             : 
    6454           1 :         CATCH_REQUIRE(c.get_root() == n);
    6455           1 :     }
    6456             : 
    6457             :     // test a null variable
    6458             :     {
    6459           1 :         std::stringstream ss;
    6460             :         ss << "$empty-variable: null;\n"
    6461           1 :            << "div { border: 1px solid $empty-variable; }\n";
    6462           3 :         csspp::position pos("test.css");
    6463           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6464             : 
    6465           2 :         csspp::parser p(l);
    6466             : 
    6467           1 :         csspp::node::pointer_t n(p.stylesheet());
    6468             : 
    6469             :         // no errors so far
    6470           1 :         VERIFY_ERRORS("");
    6471             : 
    6472           1 :         csspp::compiler c;
    6473           1 :         c.set_root(n);
    6474           1 :         c.clear_paths();
    6475           1 :         c.add_path(csspp_test::get_script_path());
    6476           1 :         c.add_path(csspp_test::get_version_script_path());
    6477             : 
    6478           1 :         c.compile(true);
    6479             : 
    6480             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6481             : 
    6482           1 :         VERIFY_ERRORS("");
    6483             : 
    6484           1 :         std::stringstream out;
    6485           1 :         out << *n;
    6486           1 :         VERIFY_TREES(out.str(),
    6487             : 
    6488             : "LIST\n"
    6489             : "    V:empty_variable\n"
    6490             : "      LIST\n"
    6491             : "        VARIABLE \"empty_variable\"\n"
    6492             : "        NULL_TOKEN\n"
    6493             : "  COMPONENT_VALUE\n"
    6494             : "    ARG\n"
    6495             : "      IDENTIFIER \"div\"\n"
    6496             : "    OPEN_CURLYBRACKET B:true\n"
    6497             : "      DECLARATION \"border\"\n"
    6498             : "        ARG\n"
    6499             : "          INTEGER \"px\" I:1\n"
    6500             : "          WHITESPACE\n"
    6501             : "          IDENTIFIER \"solid\"\n"
    6502             : 
    6503             :             );
    6504             : 
    6505           1 :         CATCH_REQUIRE(c.get_root() == n);
    6506           1 :     }
    6507             : 
    6508             :     // test inexistant variable when 'accept empty' flag is ON
    6509             :     {
    6510           1 :         std::stringstream ss;
    6511           1 :         ss << "div { border: 1px solid $undefined; }\n";
    6512           3 :         csspp::position pos("test.css");
    6513           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6514             : 
    6515           2 :         csspp::parser p(l);
    6516             : 
    6517           1 :         csspp::node::pointer_t n(p.stylesheet());
    6518             : 
    6519             :         // no errors so far
    6520           1 :         VERIFY_ERRORS("");
    6521             : 
    6522           1 :         csspp::compiler c;
    6523           1 :         c.set_root(n);
    6524           1 :         c.clear_paths();
    6525           1 :         c.set_empty_on_undefined_variable(true);
    6526           1 :         c.add_path(csspp_test::get_script_path());
    6527           1 :         c.add_path(csspp_test::get_version_script_path());
    6528             : 
    6529           1 :         c.compile(true);
    6530             : 
    6531             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6532             : 
    6533           1 :         VERIFY_ERRORS("");
    6534             : 
    6535           1 :         std::stringstream out;
    6536           1 :         out << *n;
    6537           1 :         VERIFY_TREES(out.str(),
    6538             : 
    6539             : "LIST\n"
    6540             : "  COMPONENT_VALUE\n"
    6541             : "    ARG\n"
    6542             : "      IDENTIFIER \"div\"\n"
    6543             : "    OPEN_CURLYBRACKET B:true\n"
    6544             : "      DECLARATION \"border\"\n"
    6545             : "        ARG\n"
    6546             : "          INTEGER \"px\" I:1\n"
    6547             : "          WHITESPACE\n"
    6548             : "          IDENTIFIER \"solid\"\n"
    6549             : 
    6550             :             );
    6551             : 
    6552           1 :         CATCH_REQUIRE(c.get_root() == n);
    6553           1 :     }
    6554             : 
    6555             :     // test @include instead of $blah
    6556             :     {
    6557           1 :         std::stringstream ss;
    6558             :         ss << "$var: { div { border: 1px solid #ffe093; } };"
    6559           1 :            << "@include var;\n";
    6560           3 :         csspp::position pos("test.css");
    6561           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6562             : 
    6563           2 :         csspp::parser p(l);
    6564             : 
    6565           1 :         csspp::node::pointer_t n(p.stylesheet());
    6566             : 
    6567             :         // no errors so far
    6568           1 :         VERIFY_ERRORS("");
    6569             : 
    6570           1 :         csspp::compiler c;
    6571           1 :         c.set_root(n);
    6572           1 :         c.clear_paths();
    6573           1 :         c.set_empty_on_undefined_variable(true);
    6574           1 :         c.add_path(csspp_test::get_script_path());
    6575           1 :         c.add_path(csspp_test::get_version_script_path());
    6576             : 
    6577           1 :         c.compile(true);
    6578             : 
    6579             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6580             : 
    6581           1 :         VERIFY_ERRORS("");
    6582             : 
    6583           1 :         std::stringstream out;
    6584           1 :         out << *n;
    6585           1 :         VERIFY_TREES(out.str(),
    6586             : 
    6587             : "LIST\n"
    6588             : "    V:var\n"
    6589             : "      LIST\n"
    6590             : "        VARIABLE \"var\"\n"
    6591             : "        OPEN_CURLYBRACKET B:false\n"
    6592             : "          COMPONENT_VALUE\n"
    6593             : "            IDENTIFIER \"div\"\n"
    6594             : "            OPEN_CURLYBRACKET B:true\n"
    6595             : "              COMPONENT_VALUE\n"
    6596             : "                IDENTIFIER \"border\"\n"
    6597             : "                COLON\n"
    6598             : "                WHITESPACE\n"
    6599             : "                INTEGER \"px\" I:1\n"
    6600             : "                WHITESPACE\n"
    6601             : "                IDENTIFIER \"solid\"\n"
    6602             : "                WHITESPACE\n"
    6603             : "                HASH \"ffe093\"\n"
    6604             : "  COMPONENT_VALUE\n"
    6605             : "    ARG\n"
    6606             : "      IDENTIFIER \"div\"\n"
    6607             : "    OPEN_CURLYBRACKET B:true\n"
    6608             : "      DECLARATION \"border\"\n"
    6609             : "        ARG\n"
    6610             : "          INTEGER \"px\" I:1\n"
    6611             : "          WHITESPACE\n"
    6612             : "          IDENTIFIER \"solid\"\n"
    6613             : "          WHITESPACE\n"
    6614             : "          COLOR H:ff93e0ff\n"
    6615             : 
    6616             :             );
    6617             : 
    6618           1 :         CATCH_REQUIRE(c.get_root() == n);
    6619           1 :     }
    6620             : 
    6621             :     // test @include with a function definition
    6622             :     {
    6623           1 :         std::stringstream ss;
    6624             :         ss << "$var($width): { div { border: $width solid #ffe093; } };"
    6625           1 :            << "@include var(7px);\n";
    6626           3 :         csspp::position pos("test.css");
    6627           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6628             : 
    6629           2 :         csspp::parser p(l);
    6630             : 
    6631           1 :         csspp::node::pointer_t n(p.stylesheet());
    6632             : 
    6633             :         // no errors so far
    6634           1 :         VERIFY_ERRORS("");
    6635             : 
    6636           1 :         csspp::compiler c;
    6637           1 :         c.set_root(n);
    6638           1 :         c.clear_paths();
    6639           1 :         c.set_empty_on_undefined_variable(true);
    6640           1 :         c.add_path(csspp_test::get_script_path());
    6641           1 :         c.add_path(csspp_test::get_version_script_path());
    6642             : 
    6643           1 :         c.compile(true);
    6644             : 
    6645             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6646             : 
    6647           1 :         VERIFY_ERRORS("");
    6648             : 
    6649           1 :         std::stringstream out;
    6650           1 :         out << *n;
    6651           1 :         VERIFY_TREES(out.str(),
    6652             : 
    6653             : "LIST\n"
    6654             : "    V:var\n"
    6655             : "      LIST\n"
    6656             : "        VARIABLE_FUNCTION \"var\"\n"
    6657             : "          ARG\n"
    6658             : "            VARIABLE \"width\"\n"
    6659             : "        OPEN_CURLYBRACKET B:false\n"
    6660             : "          COMPONENT_VALUE\n"
    6661             : "            IDENTIFIER \"div\"\n"
    6662             : "            OPEN_CURLYBRACKET B:true\n"
    6663             : "              COMPONENT_VALUE\n"
    6664             : "                IDENTIFIER \"border\"\n"
    6665             : "                COLON\n"
    6666             : "                WHITESPACE\n"
    6667             : "                VARIABLE \"width\"\n"
    6668             : "                WHITESPACE\n"
    6669             : "                IDENTIFIER \"solid\"\n"
    6670             : "                WHITESPACE\n"
    6671             : "                HASH \"ffe093\"\n"
    6672             : "  COMPONENT_VALUE\n"
    6673             : "    ARG\n"
    6674             : "      IDENTIFIER \"div\"\n"
    6675             : "    OPEN_CURLYBRACKET B:true\n"
    6676             : "      DECLARATION \"border\"\n"
    6677             : "        ARG\n"
    6678             : "          INTEGER \"px\" I:7\n"
    6679             : "          WHITESPACE\n"
    6680             : "          IDENTIFIER \"solid\"\n"
    6681             : "          WHITESPACE\n"
    6682             : "          COLOR H:ff93e0ff\n"
    6683             : 
    6684             :             );
    6685             : 
    6686           1 :         CATCH_REQUIRE(c.get_root() == n);
    6687           1 :     }
    6688             : 
    6689             :     // test @include with @mixin
    6690             :     {
    6691           1 :         std::stringstream ss;
    6692             :         ss << "@mixin nice-button { div { border: 3px solid #ffe093; } }"
    6693           1 :            << "@include nice-button;\n";
    6694           3 :         csspp::position pos("test.css");
    6695           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6696             : 
    6697           2 :         csspp::parser p(l);
    6698             : 
    6699           1 :         csspp::node::pointer_t n(p.stylesheet());
    6700             : 
    6701             : //std::cerr << "Parser result is: [" << *n << "]\n";
    6702             : 
    6703             :         // no errors so far
    6704           1 :         VERIFY_ERRORS("");
    6705             : 
    6706           1 :         csspp::compiler c;
    6707           1 :         c.set_root(n);
    6708           1 :         c.clear_paths();
    6709           1 :         c.set_empty_on_undefined_variable(true);
    6710           1 :         c.add_path(csspp_test::get_script_path());
    6711           1 :         c.add_path(csspp_test::get_version_script_path());
    6712             : 
    6713           1 :         c.compile(true);
    6714             : 
    6715             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6716             : 
    6717           1 :         VERIFY_ERRORS("");
    6718             : 
    6719           1 :         std::stringstream out;
    6720           1 :         out << *n;
    6721           1 :         VERIFY_TREES(out.str(),
    6722             : 
    6723             : "LIST\n"
    6724             : "    V:nice-button\n"
    6725             : "      LIST\n"
    6726             : "        IDENTIFIER \"nice-button\"\n"
    6727             : "        OPEN_CURLYBRACKET B:true\n"
    6728             : "          COMPONENT_VALUE\n"
    6729             : "            IDENTIFIER \"div\"\n"
    6730             : "            OPEN_CURLYBRACKET B:true\n"
    6731             : "              COMPONENT_VALUE\n"
    6732             : "                IDENTIFIER \"border\"\n"
    6733             : "                COLON\n"
    6734             : "                WHITESPACE\n"
    6735             : "                INTEGER \"px\" I:3\n"
    6736             : "                WHITESPACE\n"
    6737             : "                IDENTIFIER \"solid\"\n"
    6738             : "                WHITESPACE\n"
    6739             : "                HASH \"ffe093\"\n"
    6740             : "  COMPONENT_VALUE\n"
    6741             : "    ARG\n"
    6742             : "      IDENTIFIER \"div\"\n"
    6743             : "    OPEN_CURLYBRACKET B:true\n"
    6744             : "      DECLARATION \"border\"\n"
    6745             : "        ARG\n"
    6746             : "          INTEGER \"px\" I:3\n"
    6747             : "          WHITESPACE\n"
    6748             : "          IDENTIFIER \"solid\"\n"
    6749             : "          WHITESPACE\n"
    6750             : "          COLOR H:ff93e0ff\n"
    6751             : 
    6752             :             );
    6753             : 
    6754           1 :         CATCH_REQUIRE(c.get_root() == n);
    6755           1 :     }
    6756             : 
    6757             :     // test @include with @mixin
    6758             :     {
    6759           1 :         std::stringstream ss;
    6760             :         ss << "@mixin var($width) { div { border: $width solid #ffe093; } }"
    6761           1 :            << "@include var(7px);\n";
    6762           3 :         csspp::position pos("test.css");
    6763           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6764             : 
    6765           2 :         csspp::parser p(l);
    6766             : 
    6767           1 :         csspp::node::pointer_t n(p.stylesheet());
    6768             : 
    6769             : //std::cerr << "Parser result is: [" << *n << "]\n";
    6770             : 
    6771             :         // no errors so far
    6772           1 :         VERIFY_ERRORS("");
    6773             : 
    6774           1 :         csspp::compiler c;
    6775           1 :         c.set_root(n);
    6776           1 :         c.clear_paths();
    6777           1 :         c.set_empty_on_undefined_variable(true);
    6778           1 :         c.add_path(csspp_test::get_script_path());
    6779           1 :         c.add_path(csspp_test::get_version_script_path());
    6780             : 
    6781           1 :         c.compile(true);
    6782             : 
    6783             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6784             : 
    6785           1 :         VERIFY_ERRORS("");
    6786             : 
    6787           1 :         std::stringstream out;
    6788           1 :         out << *n;
    6789           1 :         VERIFY_TREES(out.str(),
    6790             : 
    6791             : "LIST\n"
    6792             : "    V:var\n"
    6793             : "      LIST\n"
    6794             : "        FUNCTION \"var\"\n"
    6795             : "          ARG\n"
    6796             : "            VARIABLE \"width\"\n"
    6797             : "        OPEN_CURLYBRACKET B:true\n"
    6798             : "          COMPONENT_VALUE\n"
    6799             : "            IDENTIFIER \"div\"\n"
    6800             : "            OPEN_CURLYBRACKET B:true\n"
    6801             : "              COMPONENT_VALUE\n"
    6802             : "                IDENTIFIER \"border\"\n"
    6803             : "                COLON\n"
    6804             : "                WHITESPACE\n"
    6805             : "                VARIABLE \"width\"\n"
    6806             : "                WHITESPACE\n"
    6807             : "                IDENTIFIER \"solid\"\n"
    6808             : "                WHITESPACE\n"
    6809             : "                HASH \"ffe093\"\n"
    6810             : "  COMPONENT_VALUE\n"
    6811             : "    ARG\n"
    6812             : "      IDENTIFIER \"div\"\n"
    6813             : "    OPEN_CURLYBRACKET B:true\n"
    6814             : "      DECLARATION \"border\"\n"
    6815             : "        ARG\n"
    6816             : "          INTEGER \"px\" I:7\n"
    6817             : "          WHITESPACE\n"
    6818             : "          IDENTIFIER \"solid\"\n"
    6819             : "          WHITESPACE\n"
    6820             : "          COLOR H:ff93e0ff\n"
    6821             : 
    6822             :             );
    6823             : 
    6824           1 :         CATCH_REQUIRE(c.get_root() == n);
    6825           1 :     }
    6826             : 
    6827             :     // test $var with @mixin definition
    6828             :     {
    6829           1 :         std::stringstream ss;
    6830             :         ss << "@mixin var { 1px solid #ff0000 }"
    6831           1 :            << "div {border:$var}\n";
    6832           3 :         csspp::position pos("test.css");
    6833           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6834             : 
    6835           2 :         csspp::parser p(l);
    6836             : 
    6837           1 :         csspp::node::pointer_t n(p.stylesheet());
    6838             : 
    6839             : //std::cerr << "Parser result is: [" << *n << "]\n";
    6840             : 
    6841             :         // no errors so far
    6842           1 :         VERIFY_ERRORS("");
    6843             : 
    6844           1 :         csspp::compiler c;
    6845           1 :         c.set_root(n);
    6846           1 :         c.clear_paths();
    6847           1 :         c.set_empty_on_undefined_variable(true);
    6848           1 :         c.add_path(csspp_test::get_script_path());
    6849           1 :         c.add_path(csspp_test::get_version_script_path());
    6850             : 
    6851           1 :         c.compile(true);
    6852             : 
    6853             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6854             : 
    6855           1 :         VERIFY_ERRORS("");
    6856             : 
    6857           1 :         std::stringstream out;
    6858           1 :         out << *n;
    6859           1 :         VERIFY_TREES(out.str(),
    6860             : 
    6861             : "LIST\n"
    6862             : "    V:var\n"
    6863             : "      LIST\n"
    6864             : "        IDENTIFIER \"var\"\n"
    6865             : "        OPEN_CURLYBRACKET B:true\n"
    6866             : "          COMPONENT_VALUE\n"
    6867             : "            INTEGER \"px\" I:1\n"
    6868             : "            WHITESPACE\n"
    6869             : "            IDENTIFIER \"solid\"\n"
    6870             : "            WHITESPACE\n"
    6871             : "            HASH \"ff0000\"\n"
    6872             : "  COMPONENT_VALUE\n"
    6873             : "    ARG\n"
    6874             : "      IDENTIFIER \"div\"\n"
    6875             : "    OPEN_CURLYBRACKET B:true\n"
    6876             : "      DECLARATION \"border\"\n"
    6877             : "        ARG\n"
    6878             : "          INTEGER \"px\" I:1\n"
    6879             : "          WHITESPACE\n"
    6880             : "          IDENTIFIER \"solid\"\n"
    6881             : "          WHITESPACE\n"
    6882             : "          COLOR H:ff0000ff\n"
    6883             : 
    6884             :             );
    6885             : 
    6886           1 :         CATCH_REQUIRE(c.get_root() == n);
    6887           1 :     }
    6888             : 
    6889             :     // test $var with @mixin definition
    6890             :     {
    6891           1 :         std::stringstream ss;
    6892             :         ss << "@mixin var { rock.paper#scissors }"
    6893           1 :            << "$var {border:blue}\n";
    6894           3 :         csspp::position pos("test.css");
    6895           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6896             : 
    6897           2 :         csspp::parser p(l);
    6898             : 
    6899           1 :         csspp::node::pointer_t n(p.stylesheet());
    6900             : 
    6901             : //std::cerr << "Parser result is: [" << *n << "]\n";
    6902             : 
    6903             :         // no errors so far
    6904           1 :         VERIFY_ERRORS("");
    6905             : 
    6906           1 :         csspp::compiler c;
    6907           1 :         c.set_root(n);
    6908           1 :         c.clear_paths();
    6909           1 :         c.set_empty_on_undefined_variable(true);
    6910           1 :         c.add_path(csspp_test::get_script_path());
    6911           1 :         c.add_path(csspp_test::get_version_script_path());
    6912             : 
    6913           1 :         c.compile(true);
    6914             : 
    6915             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6916             : 
    6917             :         //VERIFY_ERRORS("test.css(1): info: found an #id entry which is not at the beginning of the list of selectors; unless your HTML changes that much, #id should be the first selector only.\n");
    6918           1 :         VERIFY_ERRORS("");
    6919             : 
    6920           1 :         std::stringstream out;
    6921           1 :         out << *n;
    6922           1 :         VERIFY_TREES(out.str(),
    6923             : 
    6924             : "LIST\n"
    6925             : "    V:var\n"
    6926             : "      LIST\n"
    6927             : "        IDENTIFIER \"var\"\n"
    6928             : "        OPEN_CURLYBRACKET B:true\n"
    6929             : "          COMPONENT_VALUE\n"
    6930             : "            IDENTIFIER \"rock\"\n"
    6931             : "            PERIOD\n"
    6932             : "            IDENTIFIER \"paper\"\n"
    6933             : "            HASH \"scissors\"\n"
    6934             : "  COMPONENT_VALUE\n"
    6935             : "    ARG\n"
    6936             : "      IDENTIFIER \"rock\"\n"
    6937             : "      PERIOD\n"
    6938             : "      IDENTIFIER \"paper\"\n"
    6939             : "      HASH \"scissors\"\n"
    6940             : "    OPEN_CURLYBRACKET B:true\n"
    6941             : "      DECLARATION \"border\"\n"
    6942             : "        ARG\n"
    6943             : "          COLOR H:ffff0000\n"
    6944             : 
    6945             :             );
    6946             : 
    6947           1 :         CATCH_REQUIRE(c.get_root() == n);
    6948           1 :     }
    6949             : 
    6950             :     // test $var with @mixin definition
    6951             :     {
    6952           1 :         std::stringstream ss;
    6953             :         ss << "@mixin var { rock.paper#scissors, with.more#selectors }"
    6954           1 :            << "$var {border:blue}\n";
    6955           3 :         csspp::position pos("test.css");
    6956           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    6957             : 
    6958           2 :         csspp::parser p(l);
    6959             : 
    6960           1 :         csspp::node::pointer_t n(p.stylesheet());
    6961             : 
    6962             : //std::cerr << "Parser result is: [" << *n << "]\n";
    6963             : 
    6964             :         // no errors so far
    6965           1 :         VERIFY_ERRORS("");
    6966             : 
    6967           1 :         csspp::compiler c;
    6968           1 :         c.set_root(n);
    6969           1 :         c.clear_paths();
    6970           1 :         c.set_empty_on_undefined_variable(true);
    6971           1 :         c.add_path(csspp_test::get_script_path());
    6972           1 :         c.add_path(csspp_test::get_version_script_path());
    6973             : 
    6974           1 :         c.compile(true);
    6975             : 
    6976             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    6977             : 
    6978             :         //VERIFY_ERRORS(
    6979             :         //        "test.css(1): info: found an #id entry which is not at the beginning of the list of selectors; unless your HTML changes that much, #id should be the first selector only.\n"
    6980             :         //        "test.css(1): info: found an #id entry which is not at the beginning of the list of selectors; unless your HTML changes that much, #id should be the first selector only.\n"
    6981             :         //    );
    6982           1 :         VERIFY_ERRORS("");
    6983             : 
    6984           1 :         std::stringstream out;
    6985           1 :         out << *n;
    6986           1 :         VERIFY_TREES(out.str(),
    6987             : 
    6988             : "LIST\n"
    6989             : "    V:var\n"
    6990             : "      LIST\n"
    6991             : "        IDENTIFIER \"var\"\n"
    6992             : "        OPEN_CURLYBRACKET B:true\n"
    6993             : "          COMPONENT_VALUE\n"
    6994             : "            IDENTIFIER \"rock\"\n"
    6995             : "            PERIOD\n"
    6996             : "            IDENTIFIER \"paper\"\n"
    6997             : "            HASH \"scissors\"\n"
    6998             : "            COMMA\n"
    6999             : "            WHITESPACE\n"
    7000             : "            IDENTIFIER \"with\"\n"
    7001             : "            PERIOD\n"
    7002             : "            IDENTIFIER \"more\"\n"
    7003             : "            HASH \"selectors\"\n"
    7004             : "  COMPONENT_VALUE\n"
    7005             : "    ARG\n"
    7006             : "      IDENTIFIER \"rock\"\n"
    7007             : "      PERIOD\n"
    7008             : "      IDENTIFIER \"paper\"\n"
    7009             : "      HASH \"scissors\"\n"
    7010             : "    ARG\n"
    7011             : "      IDENTIFIER \"with\"\n"
    7012             : "      PERIOD\n"
    7013             : "      IDENTIFIER \"more\"\n"
    7014             : "      HASH \"selectors\"\n"
    7015             : "    OPEN_CURLYBRACKET B:true\n"
    7016             : "      DECLARATION \"border\"\n"
    7017             : "        ARG\n"
    7018             : "          COLOR H:ffff0000\n"
    7019             : 
    7020             :             );
    7021             : 
    7022           1 :         CATCH_REQUIRE(c.get_root() == n);
    7023           1 :     }
    7024             : 
    7025             :     // test $var with @mixin definition
    7026             :     {
    7027           1 :         std::stringstream ss;
    7028             :         ss << "@mixin var { rock.paper#scissors{border:blue} }"
    7029           1 :            << "div {$var}\n";
    7030           3 :         csspp::position pos("test.css");
    7031           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7032             : 
    7033           2 :         csspp::parser p(l);
    7034             : 
    7035           1 :         csspp::node::pointer_t n(p.stylesheet());
    7036             : 
    7037             : //std::cerr << "Parser result is: [" << *n << "]\n";
    7038             : 
    7039             :         // no errors so far
    7040           1 :         VERIFY_ERRORS("");
    7041             : 
    7042           1 :         csspp::compiler c;
    7043           1 :         c.set_root(n);
    7044           1 :         c.clear_paths();
    7045           1 :         c.set_empty_on_undefined_variable(true);
    7046           1 :         c.add_path(csspp_test::get_script_path());
    7047           1 :         c.add_path(csspp_test::get_version_script_path());
    7048             : 
    7049           1 :         c.compile(true);
    7050             : 
    7051             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7052             : 
    7053             :         //VERIFY_ERRORS("test.css(1): info: found an #id entry which is not at the beginning of the list of selectors; unless your HTML changes that much, #id should be the first selector only.\n");
    7054           1 :         VERIFY_ERRORS("");
    7055             : 
    7056           1 :         std::stringstream out;
    7057           1 :         out << *n;
    7058           1 :         VERIFY_TREES(out.str(),
    7059             : 
    7060             : "LIST\n"
    7061             : "    V:var\n"
    7062             : "      LIST\n"
    7063             : "        IDENTIFIER \"var\"\n"
    7064             : "        OPEN_CURLYBRACKET B:true\n"
    7065             : "          COMPONENT_VALUE\n"
    7066             : "            IDENTIFIER \"rock\"\n"
    7067             : "            PERIOD\n"
    7068             : "            IDENTIFIER \"paper\"\n"
    7069             : "            HASH \"scissors\"\n"
    7070             : "            OPEN_CURLYBRACKET B:true\n"
    7071             : "              COMPONENT_VALUE\n"
    7072             : "                IDENTIFIER \"border\"\n"
    7073             : "                COLON\n"
    7074             : "                IDENTIFIER \"blue\"\n"
    7075             : "  COMPONENT_VALUE\n"
    7076             : "    ARG\n"
    7077             : "      IDENTIFIER \"div\"\n"
    7078             : "    OPEN_CURLYBRACKET B:true\n"
    7079             : "  COMPONENT_VALUE\n"
    7080             : "    ARG\n"
    7081             : "      IDENTIFIER \"div\"\n"
    7082             : "      WHITESPACE\n"
    7083             : "      IDENTIFIER \"rock\"\n"
    7084             : "      PERIOD\n"
    7085             : "      IDENTIFIER \"paper\"\n"
    7086             : "      HASH \"scissors\"\n"
    7087             : "    OPEN_CURLYBRACKET B:true\n"
    7088             : "      DECLARATION \"border\"\n"
    7089             : "        ARG\n"
    7090             : "          COLOR H:ffff0000\n"
    7091             : 
    7092             :             );
    7093             : 
    7094           1 :         CATCH_REQUIRE(c.get_root() == n);
    7095           1 :     }
    7096             : 
    7097             :     // test $var with @mixin definition
    7098             :     {
    7099           1 :         std::stringstream ss;
    7100             :         ss << "@mixin var { border : 1px solid #eeeeee }"
    7101           1 :            << "div {$var}\n";
    7102           3 :         csspp::position pos("test.css");
    7103           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7104             : 
    7105           2 :         csspp::parser p(l);
    7106             : 
    7107           1 :         csspp::node::pointer_t n(p.stylesheet());
    7108             : 
    7109             : //std::cerr << "Parser result is: [" << *n << "]\n";
    7110             : 
    7111             :         // no errors so far
    7112           1 :         VERIFY_ERRORS("");
    7113             : 
    7114           1 :         csspp::compiler c;
    7115           1 :         c.set_root(n);
    7116           1 :         c.clear_paths();
    7117           1 :         c.set_empty_on_undefined_variable(true);
    7118           1 :         c.add_path(csspp_test::get_script_path());
    7119           1 :         c.add_path(csspp_test::get_version_script_path());
    7120             : 
    7121           1 :         c.compile(true);
    7122             : 
    7123             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7124             : 
    7125           1 :         VERIFY_ERRORS("");
    7126             : 
    7127           1 :         std::stringstream out;
    7128           1 :         out << *n;
    7129           1 :         VERIFY_TREES(out.str(),
    7130             : 
    7131             : "LIST\n"
    7132             : "    V:var\n"
    7133             : "      LIST\n"
    7134             : "        IDENTIFIER \"var\"\n"
    7135             : "        OPEN_CURLYBRACKET B:true\n"
    7136             : "          COMPONENT_VALUE\n"
    7137             : "            IDENTIFIER \"border\"\n"
    7138             : "            WHITESPACE\n"
    7139             : "            COLON\n"
    7140             : "            WHITESPACE\n"
    7141             : "            INTEGER \"px\" I:1\n"
    7142             : "            WHITESPACE\n"
    7143             : "            IDENTIFIER \"solid\"\n"
    7144             : "            WHITESPACE\n"
    7145             : "            HASH \"eeeeee\"\n"
    7146             : "  COMPONENT_VALUE\n"
    7147             : "    ARG\n"
    7148             : "      IDENTIFIER \"div\"\n"
    7149             : "    OPEN_CURLYBRACKET B:true\n"
    7150             : "      DECLARATION \"border\"\n"
    7151             : "        ARG\n"
    7152             : "          INTEGER \"px\" I:1\n"
    7153             : "          WHITESPACE\n"
    7154             : "          IDENTIFIER \"solid\"\n"
    7155             : "          WHITESPACE\n"
    7156             : "          COLOR H:ffeeeeee\n"
    7157             : 
    7158             :             );
    7159             : 
    7160           1 :         CATCH_REQUIRE(c.get_root() == n);
    7161           1 :     }
    7162             : 
    7163             :     // test $var with @mixin definition
    7164             :     {
    7165           1 :         std::stringstream ss;
    7166             :         ss << "@mixin var{border:1px solid #eeeeee}"
    7167           1 :            << "div{$var}\n";
    7168           3 :         csspp::position pos("test.css");
    7169           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7170             : 
    7171           2 :         csspp::parser p(l);
    7172             : 
    7173           1 :         csspp::node::pointer_t n(p.stylesheet());
    7174             : 
    7175             : //std::cerr << "Parser result is: [" << *n << "]\n";
    7176             : 
    7177             :         // no errors so far
    7178           1 :         VERIFY_ERRORS("");
    7179             : 
    7180           1 :         csspp::compiler c;
    7181           1 :         c.set_root(n);
    7182           1 :         c.clear_paths();
    7183           1 :         c.set_empty_on_undefined_variable(true);
    7184           1 :         c.add_path(csspp_test::get_script_path());
    7185           1 :         c.add_path(csspp_test::get_version_script_path());
    7186             : 
    7187           1 :         c.compile(true);
    7188             : 
    7189             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7190             : 
    7191           1 :         VERIFY_ERRORS("");
    7192             : 
    7193           1 :         std::stringstream out;
    7194           1 :         out << *n;
    7195           1 :         VERIFY_TREES(out.str(),
    7196             : 
    7197             : "LIST\n"
    7198             : "    V:var\n"
    7199             : "      LIST\n"
    7200             : "        IDENTIFIER \"var\"\n"
    7201             : "        OPEN_CURLYBRACKET B:true\n"
    7202             : "          COMPONENT_VALUE\n"
    7203             : "            IDENTIFIER \"border\"\n"
    7204             : "            COLON\n"
    7205             : "            INTEGER \"px\" I:1\n"
    7206             : "            WHITESPACE\n"
    7207             : "            IDENTIFIER \"solid\"\n"
    7208             : "            WHITESPACE\n"
    7209             : "            HASH \"eeeeee\"\n"
    7210             : "  COMPONENT_VALUE\n"
    7211             : "    ARG\n"
    7212             : "      IDENTIFIER \"div\"\n"
    7213             : "    OPEN_CURLYBRACKET B:true\n"
    7214             : "      DECLARATION \"border\"\n"
    7215             : "        ARG\n"
    7216             : "          INTEGER \"px\" I:1\n"
    7217             : "          WHITESPACE\n"
    7218             : "          IDENTIFIER \"solid\"\n"
    7219             : "          WHITESPACE\n"
    7220             : "          COLOR H:ffeeeeee\n"
    7221             : 
    7222             :             );
    7223             : 
    7224           1 :         CATCH_REQUIRE(c.get_root() == n);
    7225           1 :     }
    7226             : 
    7227             :     // test $var with @mixin definition
    7228             :     {
    7229             :         struct mixin_info_t
    7230             :         {
    7231           5 :             mixin_info_t(char const *selector, char const *v1, char const *r1, char const *r2 = nullptr, char const *r3 = nullptr, char const *r4 = nullptr, char const *r5 = nullptr)
    7232           5 :                 : f_selector(selector)
    7233             :             {
    7234           5 :                 f_result.push_back(r1);
    7235           5 :                 if(r2)
    7236             :                 {
    7237           5 :                     f_result.push_back(r2);
    7238           5 :                     if(r3)
    7239             :                     {
    7240           2 :                         f_result.push_back(r3);
    7241           2 :                         if(r4)
    7242             :                         {
    7243           1 :                             f_result.push_back(r4);
    7244           1 :                             if(r5)
    7245             :                             {
    7246           1 :                                 f_result.push_back(r5);
    7247             :                             }
    7248             :                         }
    7249             :                     }
    7250             :                 }
    7251             : 
    7252           5 :                 if(v1)
    7253             :                 {
    7254           1 :                     f_variable.push_back(v1);
    7255             :                 }
    7256           5 :                 if(strcmp(r1, "WHITESPACE") != 0)
    7257             :                 {
    7258           1 :                     f_variable.push_back(r1);
    7259             :                 }
    7260           5 :                 if(r2)
    7261             :                 {
    7262           5 :                     f_variable.push_back(r2);
    7263           5 :                     if(r3)
    7264             :                     {
    7265           2 :                         f_variable.push_back(r3);
    7266           2 :                         if(r4)
    7267             :                         {
    7268           1 :                             f_variable.push_back(r4);
    7269           1 :                             if(r5)
    7270             :                             {
    7271           1 :                                 f_variable.push_back(r5);
    7272             :                             }
    7273             :                         }
    7274             :                     }
    7275             :                 }
    7276           5 :             }
    7277             : 
    7278             :             std::string                             f_selector = std::string();
    7279             :             std::vector<std::string>                f_variable = std::vector<std::string>();
    7280             :             std::vector<std::string>                f_result = std::vector<std::string>();
    7281             :         };
    7282           1 :         mixin_info_t * start[5];
    7283           1 :         start[0] = new mixin_info_t("*", nullptr, "WHITESPACE", "MULTIPLY");
    7284           1 :         start[1] = new mixin_info_t("[foo='bar']", nullptr, "WHITESPACE", "OPEN_SQUAREBRACKET", "  IDENTIFIER \"foo\"", "  EQUAL", "  STRING \"bar\"");
    7285           1 :         start[2] = new mixin_info_t(".color", nullptr, "WHITESPACE", "PERIOD", "IDENTIFIER \"color\"");
    7286           1 :         start[3] = new mixin_info_t("&:hover", "REFERENCE", "COLON", "IDENTIFIER \"hover\"");
    7287           1 :         start[4] = new mixin_info_t("#peculiar", nullptr, "WHITESPACE", "HASH \"peculiar\"");
    7288             : 
    7289           6 :         for(size_t i(0); i < sizeof(start) / sizeof(start[0]); ++i)
    7290             :         {
    7291             : 
    7292           5 :             std::stringstream ss;
    7293           5 :             ss << "@mixin var{" << start[i]->f_selector << " div p{color:#eeeeee}}"
    7294           5 :                << "div{$var}\n";
    7295          15 :             csspp::position pos("test.css");
    7296           5 :             csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7297             : 
    7298          10 :             csspp::parser p(l);
    7299             : 
    7300           5 :             csspp::node::pointer_t n(p.stylesheet());
    7301             : 
    7302             : //std::cerr << "Parser result is: [" << *n << "]\n";
    7303             : 
    7304             :             // no errors so far
    7305           5 :             VERIFY_ERRORS("");
    7306             : 
    7307           5 :             csspp::compiler c;
    7308           5 :             c.set_root(n);
    7309           5 :             c.clear_paths();
    7310           5 :             c.set_empty_on_undefined_variable(true);
    7311           5 :             c.add_path(csspp_test::get_script_path());
    7312           5 :             c.add_path(csspp_test::get_version_script_path());
    7313             : 
    7314           5 :             c.compile(true);
    7315             : 
    7316             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7317             : 
    7318           5 :             VERIFY_ERRORS("");
    7319             : 
    7320           5 :             std::stringstream out;
    7321           5 :             out << *n;
    7322             : 
    7323           5 :             std::stringstream expected;
    7324             :             expected <<
    7325             : "LIST\n"
    7326             : "    V:var\n"
    7327             : "      LIST\n"
    7328             : "        IDENTIFIER \"var\"\n"
    7329             : "        OPEN_CURLYBRACKET B:true\n"
    7330           5 : "          COMPONENT_VALUE\n";
    7331             : 
    7332          16 :             for(auto s : start[i]->f_variable)
    7333             :             {
    7334          11 :                 expected << "            " << s << "\n";
    7335          11 :             }
    7336             : 
    7337             :             expected <<
    7338             : "            WHITESPACE\n"
    7339             : "            IDENTIFIER \"div\"\n"
    7340             : "            WHITESPACE\n"
    7341             : "            IDENTIFIER \"p\"\n"
    7342             : "            OPEN_CURLYBRACKET B:true\n"
    7343             : "              COMPONENT_VALUE\n"
    7344             : "                IDENTIFIER \"color\"\n"
    7345             : "                COLON\n"
    7346             : "                HASH \"eeeeee\"\n"
    7347             : "  COMPONENT_VALUE\n"
    7348             : "    ARG\n"
    7349             : "      IDENTIFIER \"div\"\n"
    7350             : "    OPEN_CURLYBRACKET B:true\n"
    7351             : "  COMPONENT_VALUE\n"
    7352             : "    ARG\n"
    7353           5 : "      IDENTIFIER \"div\"\n";
    7354             : 
    7355          19 :             for(auto s : start[i]->f_result)
    7356             :             {
    7357          14 :                 expected << "      " << s << "\n";
    7358          14 :             }
    7359             : 
    7360             :             expected <<
    7361             : "      WHITESPACE\n"
    7362             : "      IDENTIFIER \"div\"\n"
    7363             : "      WHITESPACE\n"
    7364             : "      IDENTIFIER \"p\"\n"
    7365             : "    OPEN_CURLYBRACKET B:true\n"
    7366             : "      DECLARATION \"color\"\n"
    7367             : "        ARG\n"
    7368           5 : "          COLOR H:ffeeeeee\n";
    7369             : 
    7370           5 :             VERIFY_TREES(out.str(), expected.str());
    7371             : 
    7372           5 :             CATCH_REQUIRE(c.get_root() == n);
    7373           5 :         }
    7374             : 
    7375           1 :         delete start[0];
    7376           1 :         delete start[1];
    7377           1 :         delete start[2];
    7378           1 :         delete start[3];
    7379           1 :         delete start[4];
    7380             :     }
    7381             : 
    7382             :     // test $var with @mixin definition
    7383             :     {
    7384           1 :         std::stringstream ss;
    7385             :         ss << "$var: { * div p { color: #eeeeee } };\n"
    7386           1 :            << "div { $var }\n";
    7387           3 :         csspp::position pos("test.css");
    7388           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7389             : 
    7390           2 :         csspp::parser p(l);
    7391             : 
    7392           1 :         csspp::node::pointer_t n(p.stylesheet());
    7393             : 
    7394             : //std::cerr << "Parser result is: [" << *n << "]\n";
    7395             : 
    7396             :         // no errors so far
    7397           1 :         VERIFY_ERRORS("");
    7398             : 
    7399           1 :         csspp::compiler c;
    7400           1 :         c.set_root(n);
    7401           1 :         c.clear_paths();
    7402           1 :         c.set_empty_on_undefined_variable(true);
    7403           1 :         c.add_path(csspp_test::get_script_path());
    7404           1 :         c.add_path(csspp_test::get_version_script_path());
    7405             : 
    7406           1 :         c.compile(true);
    7407             : 
    7408             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7409             : 
    7410           1 :         VERIFY_ERRORS("");
    7411             : 
    7412           1 :         std::stringstream out;
    7413           1 :         out << *n;
    7414             : 
    7415           1 :         VERIFY_TREES(out.str(),
    7416             : 
    7417             : "LIST\n"
    7418             : "    V:var\n"
    7419             : "      LIST\n"
    7420             : "        VARIABLE \"var\"\n"
    7421             : "        OPEN_CURLYBRACKET B:false\n"
    7422             : "          COMPONENT_VALUE\n"
    7423             : "            MULTIPLY\n"
    7424             : "            WHITESPACE\n"
    7425             : "            IDENTIFIER \"div\"\n"
    7426             : "            WHITESPACE\n"
    7427             : "            IDENTIFIER \"p\"\n"
    7428             : "            OPEN_CURLYBRACKET B:true\n"
    7429             : "              COMPONENT_VALUE\n"
    7430             : "                IDENTIFIER \"color\"\n"
    7431             : "                COLON\n"
    7432             : "                WHITESPACE\n"
    7433             : "                HASH \"eeeeee\"\n"
    7434             : "  COMPONENT_VALUE\n"
    7435             : "    ARG\n"
    7436             : "      IDENTIFIER \"div\"\n"
    7437             : "    OPEN_CURLYBRACKET B:true\n"
    7438             : "  COMPONENT_VALUE\n"
    7439             : "    ARG\n"
    7440             : "      IDENTIFIER \"div\"\n"
    7441             : "      WHITESPACE\n"
    7442             : "      MULTIPLY\n"
    7443             : "      WHITESPACE\n"
    7444             : "      IDENTIFIER \"div\"\n"
    7445             : "      WHITESPACE\n"
    7446             : "      IDENTIFIER \"p\"\n"
    7447             : "    OPEN_CURLYBRACKET B:true\n"
    7448             : "      DECLARATION \"color\"\n"
    7449             : "        ARG\n"
    7450             : "          COLOR H:ffeeeeee\n"
    7451             : 
    7452             :             );
    7453             : 
    7454           1 :         CATCH_REQUIRE(c.get_root() == n);
    7455           1 :     }
    7456             : 
    7457             :     // wrote this test out of a mistake really,
    7458             :     // but it generates an empty {}-block which is a good test
    7459             :     {
    7460           1 :         std::stringstream ss;
    7461             :         ss << "$b: border;"
    7462             :            << "$v: 1px solid white;"
    7463           1 :            << "div{$b: $v}\n";
    7464           3 :         csspp::position pos("test.css");
    7465           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7466             : 
    7467           2 :         csspp::parser p(l);
    7468             : 
    7469           1 :         csspp::node::pointer_t n(p.stylesheet());
    7470             : 
    7471             : //std::cerr << "Parser result is: [" << *n << "]\n";
    7472             : 
    7473             :         // no errors so far
    7474           1 :         VERIFY_ERRORS("");
    7475             : 
    7476           1 :         csspp::compiler c;
    7477           1 :         c.set_root(n);
    7478           1 :         c.clear_paths();
    7479           1 :         c.set_empty_on_undefined_variable(true);
    7480           1 :         c.add_path(csspp_test::get_script_path());
    7481           1 :         c.add_path(csspp_test::get_version_script_path());
    7482             : 
    7483           1 :         c.compile(true);
    7484             : 
    7485             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7486             : 
    7487           1 :         VERIFY_ERRORS("");
    7488             : 
    7489           1 :         std::stringstream out;
    7490           1 :         out << *n;
    7491           1 :         VERIFY_TREES(out.str(),
    7492             : 
    7493             : "LIST\n"
    7494             : "    V:b\n"
    7495             : "      LIST\n"
    7496             : "        VARIABLE \"b\"\n"
    7497             : "        IDENTIFIER \"border\"\n"
    7498             : "    V:v\n"
    7499             : "      LIST\n"
    7500             : "        VARIABLE \"v\"\n"
    7501             : "        LIST\n"
    7502             : "          INTEGER \"px\" I:1\n"
    7503             : "          WHITESPACE\n"
    7504             : "          IDENTIFIER \"solid\"\n"
    7505             : "          WHITESPACE\n"
    7506             : "          IDENTIFIER \"white\"\n"
    7507             : 
    7508             :             );
    7509             : 
    7510           1 :         CATCH_REQUIRE(c.get_root() == n);
    7511           1 :     }
    7512             : 
    7513             :     // no left over?
    7514           1 :     VERIFY_ERRORS("");
    7515           1 : }
    7516             : 
    7517           1 : CATCH_TEST_CASE("Invalid variables", "[compiler] [variable] [invalid]")
    7518             : {
    7519             :     // undefined variable with whitespace before
    7520             :     {
    7521           1 :         std::stringstream ss;
    7522           1 :         ss << "div { margin: $m; }";
    7523           3 :         csspp::position pos("test.css");
    7524           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7525             : 
    7526           2 :         csspp::parser p(l);
    7527             : 
    7528           1 :         csspp::node::pointer_t n(p.stylesheet());
    7529             : 
    7530             :         // no errors so far
    7531           1 :         VERIFY_ERRORS("");
    7532             : 
    7533           1 :         csspp::compiler c;
    7534           1 :         c.set_root(n);
    7535           1 :         c.clear_paths();
    7536           1 :         c.add_path(csspp_test::get_script_path());
    7537           1 :         c.add_path(csspp_test::get_version_script_path());
    7538             : 
    7539           1 :         c.compile(true);
    7540             : 
    7541             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7542             : 
    7543           1 :         VERIFY_ERRORS(
    7544             :                 "test.css(1): error: variable named \"m\" is not set.\n"
    7545             :                 "test.css(1): error: somehow a declaration list is missing fields, this happens if you used an invalid variable.\n"
    7546             :             );
    7547             : 
    7548           1 :         CATCH_REQUIRE(c.get_root() == n);
    7549           1 :     }
    7550             : 
    7551             :     // null variable in a place where something is required
    7552             :     {
    7553           1 :         std::stringstream ss;
    7554             :         ss << "$m: null;\n"
    7555           1 :            << "div { margin: $m; }\n";
    7556           3 :         csspp::position pos("test.css");
    7557           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7558             : 
    7559           2 :         csspp::parser p(l);
    7560             : 
    7561           1 :         csspp::node::pointer_t n(p.stylesheet());
    7562             : 
    7563             :         // no errors so far
    7564           1 :         VERIFY_ERRORS("");
    7565             : 
    7566           1 :         csspp::compiler c;
    7567           1 :         c.set_root(n);
    7568           1 :         c.clear_paths();
    7569           1 :         c.add_path(csspp_test::get_script_path());
    7570           1 :         c.add_path(csspp_test::get_version_script_path());
    7571             : 
    7572           1 :         c.compile(true);
    7573             : 
    7574             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7575             : 
    7576           1 :         VERIFY_ERRORS(
    7577             :                 "test.css(2): error: somehow a declaration list is missing fields, this happens if you used an invalid variable.\n"
    7578             :             );
    7579             : 
    7580           1 :         CATCH_REQUIRE(c.get_root() == n);
    7581           1 :     }
    7582             : 
    7583             :     // undefined variable without whitespace
    7584             :     {
    7585           1 :         std::stringstream ss;
    7586           1 :         ss << "div{margin:$m;}";
    7587           3 :         csspp::position pos("test.css");
    7588           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7589             : 
    7590           2 :         csspp::parser p(l);
    7591             : 
    7592           1 :         csspp::node::pointer_t n(p.stylesheet());
    7593             : 
    7594             :         // no errors so far
    7595           1 :         VERIFY_ERRORS("");
    7596             : 
    7597           1 :         csspp::compiler c;
    7598           1 :         c.set_root(n);
    7599           1 :         c.clear_paths();
    7600           1 :         c.add_path(csspp_test::get_script_path());
    7601           1 :         c.add_path(csspp_test::get_version_script_path());
    7602             : 
    7603           1 :         c.compile(true);
    7604             : 
    7605             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7606             : 
    7607           1 :         VERIFY_ERRORS(
    7608             :                 "test.css(1): error: variable named \"m\" is not set.\n"
    7609             :                 "test.css(1): error: somehow a declaration list is missing fields, this happens if you used an invalid variable.\n"
    7610             :             );
    7611             : 
    7612           1 :         CATCH_REQUIRE(c.get_root() == n);
    7613           1 :     }
    7614             : 
    7615             :     // variable type mismatch (func/var)
    7616             :     {
    7617           1 :         std::stringstream ss;
    7618             :         ss << "$m($p): $p / 3;"
    7619           1 :            << "div { margin: $m; }";
    7620           3 :         csspp::position pos("test.css");
    7621           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7622             : 
    7623           2 :         csspp::parser p(l);
    7624             : 
    7625           1 :         csspp::node::pointer_t n(p.stylesheet());
    7626             : 
    7627             :         // no errors so far
    7628           1 :         VERIFY_ERRORS("");
    7629             : 
    7630           1 :         csspp::compiler c;
    7631           1 :         c.set_root(n);
    7632           1 :         c.clear_paths();
    7633           1 :         c.add_path(csspp_test::get_script_path());
    7634           1 :         c.add_path(csspp_test::get_version_script_path());
    7635             : 
    7636           1 :         c.compile(true);
    7637             : 
    7638             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7639             : 
    7640           1 :         VERIFY_ERRORS(
    7641             :                 "test.css(1): error: variable named \"m\" is not a function and it cannot be referenced as such.\n"
    7642             :                 "test.css(1): error: somehow a declaration list is missing fields, this happens if you used an invalid variable.\n"
    7643             :             );
    7644             : 
    7645           1 :         CATCH_REQUIRE(c.get_root() == n);
    7646           1 :     }
    7647             : 
    7648             :     // variable type mismatch (var/func)
    7649             :     {
    7650           1 :         std::stringstream ss;
    7651             :         ss << "$m: 3px;"
    7652           1 :            << "div { margin: $m(6px); }";
    7653           3 :         csspp::position pos("test.css");
    7654           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7655             : 
    7656           2 :         csspp::parser p(l);
    7657             : 
    7658           1 :         csspp::node::pointer_t n(p.stylesheet());
    7659             : 
    7660             :         // no errors so far
    7661           1 :         VERIFY_ERRORS("");
    7662             : 
    7663           1 :         csspp::compiler c;
    7664           1 :         c.set_root(n);
    7665           1 :         c.clear_paths();
    7666           1 :         c.add_path(csspp_test::get_script_path());
    7667           1 :         c.add_path(csspp_test::get_version_script_path());
    7668             : 
    7669           1 :         c.compile(true);
    7670             : 
    7671             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7672             : 
    7673           1 :         VERIFY_ERRORS(
    7674             :                 "test.css(1): error: variable named \"m\" is a function and it can only be referenced with a function ($m() or @include m;).\n"
    7675             :                 "test.css(1): error: somehow a declaration list is missing fields, this happens if you used an invalid variable.\n"
    7676             :             );
    7677             : 
    7678           1 :         CATCH_REQUIRE(c.get_root() == n);
    7679           1 :     }
    7680             : 
    7681             :     // variable is missing in function call
    7682             :     {
    7683           1 :         std::stringstream ss;
    7684             :         ss << "$sum($a1, $a2, $a3): $a1 + $a2 + $a3;"
    7685           1 :            << "div { margin: $sum(6px, 309px); }";
    7686           3 :         csspp::position pos("test.css");
    7687           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7688             : 
    7689           2 :         csspp::parser p(l);
    7690             : 
    7691           1 :         csspp::node::pointer_t n(p.stylesheet());
    7692             : 
    7693             :         // no errors so far
    7694           1 :         VERIFY_ERRORS("");
    7695             : 
    7696           1 :         csspp::compiler c;
    7697           1 :         c.set_root(n);
    7698           1 :         c.clear_paths();
    7699           1 :         c.add_path(csspp_test::get_script_path());
    7700           1 :         c.add_path(csspp_test::get_version_script_path());
    7701             : 
    7702           1 :         c.compile(true);
    7703             : 
    7704             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7705             : 
    7706           1 :         VERIFY_ERRORS(
    7707             :                 "test.css(1): error: missing function variable named \"a3\" when calling sum() or using @include sum();).\n"
    7708             :                 "test.css(1): error: somehow a declaration list is missing fields, this happens if you used an invalid variable.\n"
    7709             :             );
    7710             : 
    7711           1 :         CATCH_REQUIRE(c.get_root() == n);
    7712           1 :     }
    7713             : 
    7714             :     // variable parameter is not a variable
    7715             :     {
    7716           1 :         std::stringstream ss;
    7717             :         ss << "$sum(a1): $a1;"
    7718           1 :            << "div { margin: $sum(6px); }";
    7719           3 :         csspp::position pos("test.css");
    7720           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7721             : 
    7722           2 :         csspp::parser p(l);
    7723             : 
    7724           1 :         csspp::node::pointer_t n(p.stylesheet());
    7725             : 
    7726             :         // no errors so far
    7727           1 :         VERIFY_ERRORS("");
    7728             : 
    7729           1 :         csspp::compiler c;
    7730           1 :         c.set_root(n);
    7731           1 :         c.clear_paths();
    7732           1 :         c.add_path(csspp_test::get_script_path());
    7733           1 :         c.add_path(csspp_test::get_version_script_path());
    7734             : 
    7735           1 :         c.compile(true);
    7736             : 
    7737             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7738             : 
    7739           1 :         VERIFY_ERRORS(
    7740             :                 "test.css(1): error: function declarations expect variables for each of their arguments, not a IDENTIFIER.\n"
    7741             :                 //"test.css(1): error: function declaration requires all parameters to be variables, IDENTIFIER is not acceptable.\n" -- removed not useful
    7742             :                 "test.css(1): error: somehow a declaration list is missing fields, this happens if you used an invalid variable.\n"
    7743             :             );
    7744             : 
    7745           1 :         CATCH_REQUIRE(c.get_root() == n);
    7746           1 :     }
    7747             : 
    7748             :     // missing value for optional parameter
    7749             :     {
    7750           1 :         std::stringstream ss;
    7751             :         ss << "$sum($a1, $a2: 3px, $a3): ($a1+$a2)/$a3;"
    7752           1 :            << "div { margin: $sum(6px, 7px, 3); }";
    7753           3 :         csspp::position pos("test.css");
    7754           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7755             : 
    7756           2 :         csspp::parser p(l);
    7757             : 
    7758           1 :         csspp::node::pointer_t n(p.stylesheet());
    7759             : 
    7760             :         // no errors so far
    7761           1 :         VERIFY_ERRORS("");
    7762             : 
    7763           1 :         csspp::compiler c;
    7764           1 :         c.set_root(n);
    7765           1 :         c.clear_paths();
    7766           1 :         c.add_path(csspp_test::get_script_path());
    7767           1 :         c.add_path(csspp_test::get_version_script_path());
    7768             : 
    7769           1 :         c.compile(true);
    7770             : 
    7771             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7772             : 
    7773           1 :         VERIFY_ERRORS(
    7774             :                 "test.css(1): error: function declarations with optional parameters must make all parameters optional from the first one that is given an optional value up to the end of the list of arguments.\n"
    7775             :                 //"test.css(1): error: unsupported type LIST as a unary expression token.\n"
    7776             :             );
    7777             : 
    7778           1 :         CATCH_REQUIRE(c.get_root() == n);
    7779           1 :     }
    7780             : 
    7781             :     // missing ':' to define the optional value
    7782             :     {
    7783           1 :         std::stringstream ss;
    7784             :         ss << "$sum($a1, $a2 3px, $a3): ($a1+$a2)/$a3;"
    7785           1 :            << "div { margin: $sum(6px, 7px, 3); }";
    7786           3 :         csspp::position pos("test.css");
    7787           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7788             : 
    7789           2 :         csspp::parser p(l);
    7790             : 
    7791           1 :         csspp::node::pointer_t n(p.stylesheet());
    7792             : 
    7793             :         // no errors so far
    7794           1 :         VERIFY_ERRORS("");
    7795             : 
    7796           1 :         csspp::compiler c;
    7797           1 :         c.set_root(n);
    7798           1 :         c.clear_paths();
    7799           1 :         c.add_path(csspp_test::get_script_path());
    7800           1 :         c.add_path(csspp_test::get_version_script_path());
    7801             : 
    7802           1 :         c.compile(true);
    7803             : 
    7804             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7805             : 
    7806           1 :         VERIFY_ERRORS(
    7807             :                 "test.css(1): error: function declarations expect variable with optional parameters to use a ':' after the variable name and before the optional value.\n"
    7808             :                 //"test.css(1): error: unsupported type LIST as a unary expression token.\n"
    7809             :             );
    7810             : 
    7811           1 :         CATCH_REQUIRE(c.get_root() == n);
    7812           1 :     }
    7813             : 
    7814             :     // test @include with something else than an identifier or function
    7815             :     {
    7816           1 :         std::stringstream ss;
    7817           1 :         ss << "@include url(invalid/token/for/include);\n";
    7818           3 :         csspp::position pos("test.css");
    7819           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7820             : 
    7821           2 :         csspp::parser p(l);
    7822             : 
    7823           1 :         csspp::node::pointer_t n(p.stylesheet());
    7824             : 
    7825             :         // no errors so far
    7826           1 :         VERIFY_ERRORS("");
    7827             : 
    7828           1 :         csspp::compiler c;
    7829           1 :         c.set_root(n);
    7830           1 :         c.clear_paths();
    7831           1 :         c.set_empty_on_undefined_variable(true);
    7832           1 :         c.add_path(csspp_test::get_script_path());
    7833           1 :         c.add_path(csspp_test::get_version_script_path());
    7834             : 
    7835           1 :         c.compile(true);
    7836             : 
    7837             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7838             : 
    7839           1 :         VERIFY_ERRORS("test.css(1): error: @include is expected to be followed by an IDENTIFIER or a FUNCTION naming the variable/mixin to include.\n");
    7840             : 
    7841           1 :         CATCH_REQUIRE(c.get_root() == n);
    7842           1 :     }
    7843             : 
    7844             :     // test @include with something else than an identifier or function
    7845             :     {
    7846           1 :         std::stringstream ss;
    7847             :         ss << "$empty:null;\n"
    7848           1 :            << "$empty{color:pink;}\n";
    7849           3 :         csspp::position pos("test.css");
    7850           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7851             : 
    7852           2 :         csspp::parser p(l);
    7853             : 
    7854           1 :         csspp::node::pointer_t n(p.stylesheet());
    7855             : 
    7856             :         // no errors so far
    7857           1 :         VERIFY_ERRORS("");
    7858             : 
    7859           1 :         csspp::compiler c;
    7860           1 :         c.set_root(n);
    7861           1 :         c.clear_paths();
    7862           1 :         c.set_empty_on_undefined_variable(true);
    7863           1 :         c.add_path(csspp_test::get_script_path());
    7864           1 :         c.add_path(csspp_test::get_version_script_path());
    7865             : 
    7866           1 :         c.compile(true);
    7867             : 
    7868             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7869             : 
    7870           1 :         VERIFY_ERRORS("test.css(2): error: a qualified rule without selectors is not valid.\n");
    7871             : 
    7872           1 :         CATCH_REQUIRE(c.get_root() == n);
    7873           1 :     }
    7874             : 
    7875             :     // @mixin with one parameter
    7876             :     {
    7877           1 :         std::stringstream ss;
    7878           1 :         ss << "@mixin nice-button;";
    7879           3 :         csspp::position pos("test.css");
    7880           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7881             : 
    7882           2 :         csspp::parser p(l);
    7883             : 
    7884           1 :         csspp::node::pointer_t n(p.stylesheet());
    7885             : 
    7886             : //std::cerr << "Parser result is: [" << *n << "]\n";
    7887             : 
    7888             :         // no errors so far
    7889           1 :         VERIFY_ERRORS("");
    7890             : 
    7891           1 :         csspp::compiler c;
    7892           1 :         c.set_root(n);
    7893           1 :         c.clear_paths();
    7894           1 :         c.set_empty_on_undefined_variable(true);
    7895           1 :         c.add_path(csspp_test::get_script_path());
    7896           1 :         c.add_path(csspp_test::get_version_script_path());
    7897             : 
    7898           1 :         c.compile(true);
    7899             : 
    7900             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7901             : 
    7902           1 :         VERIFY_ERRORS("test.css(1): error: a @mixin definition expects exactly two parameters: an identifier or function and a {}-block.\n");
    7903             : 
    7904           1 :         CATCH_REQUIRE(c.get_root() == n);
    7905           1 :     }
    7906             : 
    7907             :     // @mixin with one parameter
    7908             :     {
    7909           1 :         std::stringstream ss;
    7910           1 :         ss << "@mixin { div { border: 3px solid #ffe093; } }";
    7911           3 :         csspp::position pos("test.css");
    7912           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7913             : 
    7914           2 :         csspp::parser p(l);
    7915             : 
    7916           1 :         csspp::node::pointer_t n(p.stylesheet());
    7917             : 
    7918             : //std::cerr << "Parser result is: [" << *n << "]\n";
    7919             : 
    7920             :         // no errors so far
    7921           1 :         VERIFY_ERRORS("");
    7922             : 
    7923           1 :         csspp::compiler c;
    7924           1 :         c.set_root(n);
    7925           1 :         c.clear_paths();
    7926           1 :         c.set_empty_on_undefined_variable(true);
    7927           1 :         c.add_path(csspp_test::get_script_path());
    7928           1 :         c.add_path(csspp_test::get_version_script_path());
    7929             : 
    7930           1 :         c.compile(true);
    7931             : 
    7932             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7933             : 
    7934           1 :         VERIFY_ERRORS("test.css(1): error: a @mixin definition expects exactly two parameters: an identifier or function and a {}-block.\n");
    7935             : 
    7936           1 :         CATCH_REQUIRE(c.get_root() == n);
    7937           1 :     }
    7938             : 
    7939             :     // @mixin with too many entries (i.e. "color" " " "#ff3241")
    7940             :     {
    7941           1 :         std::stringstream ss;
    7942           1 :         ss << "@mixin color #ff3241;";
    7943           3 :         csspp::position pos("test.css");
    7944           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7945             : 
    7946           2 :         csspp::parser p(l);
    7947             : 
    7948           1 :         csspp::node::pointer_t n(p.stylesheet());
    7949             : 
    7950             : //std::cerr << "Parser result is: [" << *n << "]\n";
    7951             : 
    7952             :         // no errors so far
    7953           1 :         VERIFY_ERRORS("");
    7954             : 
    7955           1 :         csspp::compiler c;
    7956           1 :         c.set_root(n);
    7957           1 :         c.clear_paths();
    7958           1 :         c.set_empty_on_undefined_variable(true);
    7959           1 :         c.add_path(csspp_test::get_script_path());
    7960           1 :         c.add_path(csspp_test::get_version_script_path());
    7961             : 
    7962           1 :         c.compile(true);
    7963             : 
    7964             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7965             : 
    7966           1 :         VERIFY_ERRORS("test.css(1): error: a @mixin definition expects exactly two parameters: an identifier or function and a {}-block.\n");
    7967             : 
    7968           1 :         CATCH_REQUIRE(c.get_root() == n);
    7969           1 :     }
    7970             : 
    7971             :     // @mixin not with a {}-block
    7972             :     {
    7973           1 :         std::stringstream ss;
    7974           1 :         ss << "@mixin color#ff3241;";
    7975           3 :         csspp::position pos("test.css");
    7976           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    7977             : 
    7978           2 :         csspp::parser p(l);
    7979             : 
    7980           1 :         csspp::node::pointer_t n(p.stylesheet());
    7981             : 
    7982             : //std::cerr << "Parser result is: [" << *n << "]\n";
    7983             : 
    7984             :         // no errors so far
    7985           1 :         VERIFY_ERRORS("");
    7986             : 
    7987           1 :         csspp::compiler c;
    7988           1 :         c.set_root(n);
    7989           1 :         c.clear_paths();
    7990           1 :         c.set_empty_on_undefined_variable(true);
    7991           1 :         c.add_path(csspp_test::get_script_path());
    7992           1 :         c.add_path(csspp_test::get_version_script_path());
    7993             : 
    7994           1 :         c.compile(true);
    7995             : 
    7996             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    7997             : 
    7998           1 :         VERIFY_ERRORS("test.css(1): error: a @mixin definition expects a {}-block as its second parameter.\n");
    7999             : 
    8000           1 :         CATCH_REQUIRE(c.get_root() == n);
    8001           1 :     }
    8002             : 
    8003             :     // @mixin not with a IDENTIFIER or FUNCTION as first parameter
    8004             :     {
    8005           1 :         std::stringstream ss;
    8006           1 :         ss << "@mixin #ff3241 { color: full; }";
    8007           3 :         csspp::position pos("test.css");
    8008           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8009             : 
    8010           2 :         csspp::parser p(l);
    8011             : 
    8012           1 :         csspp::node::pointer_t n(p.stylesheet());
    8013             : 
    8014             : //std::cerr << "Parser result is: [" << *n << "]\n";
    8015             : 
    8016             :         // no errors so far
    8017           1 :         VERIFY_ERRORS("");
    8018             : 
    8019           1 :         csspp::compiler c;
    8020           1 :         c.set_root(n);
    8021           1 :         c.clear_paths();
    8022           1 :         c.set_empty_on_undefined_variable(true);
    8023           1 :         c.add_path(csspp_test::get_script_path());
    8024           1 :         c.add_path(csspp_test::get_version_script_path());
    8025             : 
    8026           1 :         c.compile(true);
    8027             : 
    8028             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8029             : 
    8030           1 :         VERIFY_ERRORS("test.css(1): error: a @mixin expects either an IDENTIFIER or a FUNCTION as its first parameter.\n");
    8031             : 
    8032           1 :         CATCH_REQUIRE(c.get_root() == n);
    8033           1 :     }
    8034             : 
    8035             :     // @mixin with VARIABLE generates an special error
    8036             :     {
    8037           1 :         std::stringstream ss;
    8038           1 :         ss << "@mixin $var { color: full; }";
    8039           3 :         csspp::position pos("test.css");
    8040           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8041             : 
    8042           2 :         csspp::parser p(l);
    8043             : 
    8044           1 :         csspp::node::pointer_t n(p.stylesheet());
    8045             : 
    8046             : //std::cerr << "Parser result is: [" << *n << "]\n";
    8047             : 
    8048             :         // no errors so far
    8049           1 :         VERIFY_ERRORS("");
    8050             : 
    8051           1 :         csspp::compiler c;
    8052           1 :         c.set_root(n);
    8053           1 :         c.clear_paths();
    8054           1 :         c.set_empty_on_undefined_variable(true);
    8055           1 :         c.add_path(csspp_test::get_script_path());
    8056           1 :         c.add_path(csspp_test::get_version_script_path());
    8057             : 
    8058           1 :         c.compile(true);
    8059             : 
    8060             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8061             : 
    8062           1 :         VERIFY_ERRORS("test.css(1): error: a @mixin must use an IDENTIFIER or FUNCTION and no a VARIABLE or VARIABLE_FUNCTION.\n");
    8063             : 
    8064           1 :         CATCH_REQUIRE(c.get_root() == n);
    8065           1 :     }
    8066             : 
    8067             :     // @mixin with VARIABLE generates an special error
    8068             :     {
    8069           1 :         std::stringstream ss;
    8070           1 :         ss << "@mixin $var($a1, $a2) { color: $a1 + $a2 / 2.5; }";
    8071           3 :         csspp::position pos("test.css");
    8072           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8073             : 
    8074           2 :         csspp::parser p(l);
    8075             : 
    8076           1 :         csspp::node::pointer_t n(p.stylesheet());
    8077             : 
    8078             : //std::cerr << "Parser result is: [" << *n << "]\n";
    8079             : 
    8080             :         // no errors so far
    8081           1 :         VERIFY_ERRORS("");
    8082             : 
    8083           1 :         csspp::compiler c;
    8084           1 :         c.set_root(n);
    8085           1 :         c.clear_paths();
    8086           1 :         c.set_empty_on_undefined_variable(true);
    8087           1 :         c.add_path(csspp_test::get_script_path());
    8088           1 :         c.add_path(csspp_test::get_version_script_path());
    8089             : 
    8090           1 :         c.compile(true);
    8091             : 
    8092             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8093             : 
    8094           1 :         VERIFY_ERRORS("test.css(1): error: a @mixin must use an IDENTIFIER or FUNCTION and no a VARIABLE or VARIABLE_FUNCTION.\n");
    8095             : 
    8096           1 :         CATCH_REQUIRE(c.get_root() == n);
    8097           1 :     }
    8098             : 
    8099             :     // try !global at the wrong place and see the warning
    8100             :     {
    8101           1 :         std::stringstream ss;
    8102             :         ss << "$size: 100px;\n"
    8103             :            << "div { $size: !global 300px;\n"
    8104             :            << "  entry: {\n"
    8105             :            << "    $size: ! global 50px;\n"
    8106             :            << "    width: $size;\n"
    8107             :            << "    height: $size * 3 / 4;\n"
    8108             :            << "  };\n"
    8109             :            << "  junior: $size + 13px;\n"
    8110             :            << "}\n"
    8111           1 :            << "section { diameter: $size }\n";
    8112           3 :         csspp::position pos("test.css");
    8113           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8114             : 
    8115           2 :         csspp::parser p(l);
    8116             : 
    8117           1 :         csspp::node::pointer_t n(p.stylesheet());
    8118             : 
    8119             :         // no errors so far
    8120           1 :         VERIFY_ERRORS("");
    8121             : 
    8122           1 :         csspp::compiler c;
    8123           1 :         c.set_root(n);
    8124           1 :         c.clear_paths();
    8125           1 :         c.add_path(csspp_test::get_script_path());
    8126           1 :         c.add_path(csspp_test::get_version_script_path());
    8127             : 
    8128           1 :         c.compile(true);
    8129             : 
    8130             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8131             : 
    8132           1 :         VERIFY_ERRORS(
    8133             :                 "test.css(2): warning: A special flag, !global in this case, must only appear at the end of a declaration.\n"
    8134             :                 "test.css(3): warning: A special flag, !global in this case, must only appear at the end of a declaration.\n"
    8135             :             );
    8136             : 
    8137           1 :         std::stringstream out;
    8138           1 :         out << *n;
    8139           1 :         VERIFY_TREES(out.str(),
    8140             : 
    8141             : "LIST\n"
    8142             : "    V:size\n"
    8143             : "      LIST\n"
    8144             : "        VARIABLE \"size\"\n"
    8145             : "        INTEGER \"px\" I:50\n"
    8146             : "  COMPONENT_VALUE\n"
    8147             : "    ARG\n"
    8148             : "      IDENTIFIER \"div\"\n"
    8149             : "    OPEN_CURLYBRACKET B:true\n"
    8150             : "      LIST\n"
    8151             : "        DECLARATION \"entry-width\"\n"
    8152             : "          ARG\n"
    8153             : "            INTEGER \"px\" I:50\n"
    8154             : "        DECLARATION \"entry-height\"\n"
    8155             : "          ARG\n"
    8156             : "            INTEGER \"px\" I:37\n"
    8157             : "        DECLARATION \"junior\"\n"
    8158             : "          ARG\n"
    8159             : "            INTEGER \"px\" I:63\n"
    8160             : "  COMPONENT_VALUE\n"
    8161             : "    ARG\n"
    8162             : "      IDENTIFIER \"section\"\n"
    8163             : "    OPEN_CURLYBRACKET B:true\n"
    8164             : "      DECLARATION \"diameter\"\n"
    8165             : "        ARG\n"
    8166             : "          INTEGER \"px\" I:50\n"
    8167             : 
    8168             :             );
    8169             : 
    8170           1 :         CATCH_REQUIRE(c.get_root() == n);
    8171           1 :     }
    8172             : 
    8173             :     // try !default at the wrong place and see the warning
    8174             :     {
    8175           1 :         std::stringstream ss;
    8176             :         ss << "$size: 100px;\n"
    8177             :            << "div { $size: !default 300px;\n"
    8178             :            << "  entry: {\n"
    8179             :            << "    $size: ! default 50px;\n"
    8180             :            << "    width: $size;\n"
    8181             :            << "    height: $size * 3 / 4;\n"
    8182             :            << "  };\n"
    8183             :            << "  junior: $size + 13px;\n"
    8184             :            << "}\n"
    8185           1 :            << "section { diameter: $size }\n";
    8186           3 :         csspp::position pos("test.css");
    8187           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8188             : 
    8189           2 :         csspp::parser p(l);
    8190             : 
    8191           1 :         csspp::node::pointer_t n(p.stylesheet());
    8192             : 
    8193             :         // no errors so far
    8194           1 :         VERIFY_ERRORS("");
    8195             : 
    8196           1 :         csspp::compiler c;
    8197           1 :         c.set_root(n);
    8198           1 :         c.clear_paths();
    8199           1 :         c.add_path(csspp_test::get_script_path());
    8200           1 :         c.add_path(csspp_test::get_version_script_path());
    8201             : 
    8202           1 :         c.compile(true);
    8203             : 
    8204             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8205             : 
    8206           1 :         VERIFY_ERRORS(
    8207             :                 "test.css(2): warning: A special flag, !default in this case, must only appear at the end of a declaration.\n"
    8208             :                 "test.css(3): warning: A special flag, !default in this case, must only appear at the end of a declaration.\n"
    8209             :             );
    8210             : 
    8211           1 :         std::stringstream out;
    8212           1 :         out << *n;
    8213           1 :         VERIFY_TREES(out.str(),
    8214             : 
    8215             : "LIST\n"
    8216             : "    V:size\n"
    8217             : "      LIST\n"
    8218             : "        VARIABLE \"size\"\n"
    8219             : "        INTEGER \"px\" I:100\n"
    8220             : "  COMPONENT_VALUE\n"
    8221             : "    ARG\n"
    8222             : "      IDENTIFIER \"div\"\n"
    8223             : "    OPEN_CURLYBRACKET B:true\n"
    8224             : "      LIST\n"
    8225             : "        DECLARATION \"entry-width\"\n"
    8226             : "          ARG\n"
    8227             : "            INTEGER \"px\" I:100\n"
    8228             : "        DECLARATION \"entry-height\"\n"
    8229             : "          ARG\n"
    8230             : "            INTEGER \"px\" I:75\n"
    8231             : "        DECLARATION \"junior\"\n"
    8232             : "          ARG\n"
    8233             : "            INTEGER \"px\" I:113\n"
    8234             : "  COMPONENT_VALUE\n"
    8235             : "    ARG\n"
    8236             : "      IDENTIFIER \"section\"\n"
    8237             : "    OPEN_CURLYBRACKET B:true\n"
    8238             : "      DECLARATION \"diameter\"\n"
    8239             : "        ARG\n"
    8240             : "          INTEGER \"px\" I:100\n"
    8241             : 
    8242             :             );
    8243             : 
    8244           1 :         CATCH_REQUIRE(c.get_root() == n);
    8245           1 :     }
    8246             : 
    8247             :     // no left over?
    8248           1 :     VERIFY_ERRORS("");
    8249           1 : }
    8250             : 
    8251           1 : CATCH_TEST_CASE("At-Keyword ignored", "[compiler] [at-keyword]")
    8252             : {
    8253             :     // make sure @<not supported> is left alone as expected by CSS 3
    8254             :     {
    8255           1 :         std::stringstream ss;
    8256           1 :         ss << "@unknown \"This works?\";";
    8257           3 :         csspp::position pos("test.css");
    8258           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8259             : 
    8260           2 :         csspp::parser p(l);
    8261             : 
    8262           1 :         csspp::node::pointer_t n(p.stylesheet());
    8263             : 
    8264             :         // no errors so far
    8265           1 :         VERIFY_ERRORS("");
    8266             : 
    8267           1 :         csspp::compiler c;
    8268           1 :         c.set_root(n);
    8269           1 :         c.clear_paths();
    8270           1 :         c.add_path(csspp_test::get_script_path());
    8271           1 :         c.add_path(csspp_test::get_version_script_path());
    8272             : 
    8273           1 :         c.compile(true);
    8274             : 
    8275           1 :         VERIFY_ERRORS("");
    8276             : 
    8277           1 :         std::stringstream out;
    8278           1 :         out << *n;
    8279           1 :         VERIFY_TREES(out.str(),
    8280             : 
    8281             : "LIST\n"
    8282             : "  AT_KEYWORD \"unknown\" I:0\n"
    8283             : "    STRING \"This works?\"\n"
    8284             : 
    8285             :             );
    8286             : 
    8287           1 :         CATCH_REQUIRE(c.get_root() == n);
    8288           1 :     }
    8289             : 
    8290             :     // make sure @<not supported> is left alone as expected by CSS 3
    8291             :     {
    8292           1 :         std::stringstream ss;
    8293           1 :         ss << "@unknown \"Question?\" { this one has a block }";
    8294           3 :         csspp::position pos("test.css");
    8295           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8296             : 
    8297           2 :         csspp::parser p(l);
    8298             : 
    8299           1 :         csspp::node::pointer_t n(p.stylesheet());
    8300             : 
    8301             :         // no errors so far
    8302           1 :         VERIFY_ERRORS("");
    8303             : 
    8304           1 :         csspp::compiler c;
    8305           1 :         c.set_root(n);
    8306           1 :         c.clear_paths();
    8307           1 :         c.add_path(csspp_test::get_script_path());
    8308           1 :         c.add_path(csspp_test::get_version_script_path());
    8309             : 
    8310           1 :         c.compile(true);
    8311             : 
    8312           1 :         VERIFY_ERRORS("");
    8313             : 
    8314           1 :         std::stringstream out;
    8315           1 :         out << *n;
    8316           1 :         VERIFY_TREES(out.str(),
    8317             : 
    8318             : "LIST\n"
    8319             : "  AT_KEYWORD \"unknown\" I:0\n"
    8320             : "    STRING \"Question?\"\n"
    8321             : "    OPEN_CURLYBRACKET B:true\n"
    8322             : "      COMPONENT_VALUE\n"
    8323             : "        IDENTIFIER \"this\"\n"
    8324             : "        WHITESPACE\n"
    8325             : "        IDENTIFIER \"one\"\n"
    8326             : "        WHITESPACE\n"
    8327             : "        IDENTIFIER \"has\"\n"
    8328             : "        WHITESPACE\n"
    8329             : "        IDENTIFIER \"a\"\n"
    8330             : "        WHITESPACE\n"
    8331             : "        IDENTIFIER \"block\"\n"
    8332             : 
    8333             :             );
    8334             : 
    8335           1 :         CATCH_REQUIRE(c.get_root() == n);
    8336           1 :     }
    8337             : 
    8338             :     // no left over?
    8339           1 :     VERIFY_ERRORS("");
    8340           1 : }
    8341             : 
    8342           1 : CATCH_TEST_CASE("At-Keyword messages", "[compiler] [output]")
    8343             : {
    8344             :     // generate an error with @error
    8345             :     {
    8346           1 :         std::stringstream ss;
    8347           1 :         ss << "@error \"This is an error.\";";
    8348           3 :         csspp::position pos("test.css");
    8349           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8350             : 
    8351           2 :         csspp::parser p(l);
    8352             : 
    8353           1 :         csspp::node::pointer_t n(p.stylesheet());
    8354             : 
    8355             :         // no errors so far
    8356           1 :         VERIFY_ERRORS("");
    8357             : 
    8358           1 :         csspp::compiler c;
    8359           1 :         c.set_root(n);
    8360           1 :         c.clear_paths();
    8361           1 :         c.add_path(csspp_test::get_script_path());
    8362           1 :         c.add_path(csspp_test::get_version_script_path());
    8363             : 
    8364           1 :         c.compile(true);
    8365             : 
    8366           1 :         VERIFY_ERRORS("test.css(1): error: This is an error.\n");
    8367             : 
    8368           1 :         CATCH_REQUIRE(c.get_root() == n);
    8369           1 :     }
    8370             : 
    8371             :     // generate a warning with @warning
    8372             :     {
    8373           1 :         std::stringstream ss;
    8374           1 :         ss << "@warning \"This is a warning.\";";
    8375           3 :         csspp::position pos("test.css");
    8376           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8377             : 
    8378           2 :         csspp::parser p(l);
    8379             : 
    8380           1 :         csspp::node::pointer_t n(p.stylesheet());
    8381             : 
    8382             :         // no errors so far
    8383           1 :         VERIFY_ERRORS("");
    8384             : 
    8385           1 :         csspp::compiler c;
    8386           1 :         c.set_root(n);
    8387           1 :         c.clear_paths();
    8388           1 :         c.add_path(csspp_test::get_script_path());
    8389           1 :         c.add_path(csspp_test::get_version_script_path());
    8390             : 
    8391           1 :         c.compile(true);
    8392             : 
    8393           1 :         VERIFY_ERRORS("test.css(1): warning: This is a warning.\n");
    8394             : 
    8395           1 :         CATCH_REQUIRE(c.get_root() == n);
    8396           1 :     }
    8397             : 
    8398             :     // output a message with @info
    8399             :     {
    8400           1 :         std::stringstream ss;
    8401           1 :         ss << "@info \"This is an info message.\";";
    8402           3 :         csspp::position pos("test.css");
    8403           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8404             : 
    8405           2 :         csspp::parser p(l);
    8406             : 
    8407           1 :         csspp::node::pointer_t n(p.stylesheet());
    8408             : 
    8409             :         // no errors so far
    8410           1 :         VERIFY_ERRORS("");
    8411             : 
    8412           1 :         csspp::compiler c;
    8413           1 :         c.set_root(n);
    8414           1 :         c.clear_paths();
    8415           1 :         c.add_path(csspp_test::get_script_path());
    8416           1 :         c.add_path(csspp_test::get_version_script_path());
    8417             : 
    8418           1 :         c.compile(true);
    8419             : 
    8420           1 :         VERIFY_ERRORS("test.css(1): info: This is an info message.\n");
    8421             : 
    8422           1 :         CATCH_REQUIRE(c.get_root() == n);
    8423           1 :     }
    8424             : 
    8425             :     // make sure @message does the same as @info
    8426             :     {
    8427           1 :         std::stringstream ss;
    8428           1 :         ss << "@message \"This is an info message.\";";
    8429           3 :         csspp::position pos("test.css");
    8430           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8431             : 
    8432           2 :         csspp::parser p(l);
    8433             : 
    8434           1 :         csspp::node::pointer_t n(p.stylesheet());
    8435             : 
    8436             :         // no errors so far
    8437           1 :         VERIFY_ERRORS("");
    8438             : 
    8439           1 :         csspp::compiler c;
    8440           1 :         c.set_root(n);
    8441           1 :         c.clear_paths();
    8442           1 :         c.add_path(csspp_test::get_script_path());
    8443           1 :         c.add_path(csspp_test::get_version_script_path());
    8444             : 
    8445           1 :         c.compile(true);
    8446             : 
    8447           1 :         VERIFY_ERRORS("test.css(1): info: This is an info message.\n");
    8448             : 
    8449           1 :         CATCH_REQUIRE(c.get_root() == n);
    8450           1 :     }
    8451             : 
    8452             :     // test @debug does nothing by default
    8453             :     {
    8454           1 :         std::stringstream ss;
    8455           1 :         ss << "@debug \"This is a debug message.\";";
    8456           3 :         csspp::position pos("test.css");
    8457           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8458             : 
    8459           2 :         csspp::parser p(l);
    8460             : 
    8461           1 :         csspp::node::pointer_t n(p.stylesheet());
    8462             : 
    8463             :         // no errors so far
    8464           1 :         VERIFY_ERRORS("");
    8465             : 
    8466           1 :         csspp::compiler c;
    8467           1 :         c.set_root(n);
    8468           1 :         c.clear_paths();
    8469           1 :         c.add_path(csspp_test::get_script_path());
    8470           1 :         c.add_path(csspp_test::get_version_script_path());
    8471             : 
    8472           1 :         c.compile(true);
    8473             : 
    8474             :         // by default debug messages do not make it to the output
    8475           1 :         VERIFY_ERRORS("");
    8476             : 
    8477           1 :         CATCH_REQUIRE(c.get_root() == n);
    8478           1 :     }
    8479             : 
    8480             :     // make sure @debug does the same as @info
    8481             :     {
    8482           1 :         std::stringstream ss;
    8483           1 :         ss << "@debug \"This is a debug message.\";";
    8484           3 :         csspp::position pos("test.css");
    8485           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8486             : 
    8487           2 :         csspp::parser p(l);
    8488             : 
    8489           1 :         csspp::node::pointer_t n(p.stylesheet());
    8490             : 
    8491             :         // no errors so far
    8492           1 :         VERIFY_ERRORS("");
    8493             : 
    8494           1 :         csspp::compiler c;
    8495           1 :         c.set_root(n);
    8496           1 :         c.clear_paths();
    8497           1 :         c.add_path(csspp_test::get_script_path());
    8498           1 :         c.add_path(csspp_test::get_version_script_path());
    8499             : 
    8500           1 :         csspp::error::instance().set_show_debug(true);
    8501           1 :         c.compile(true);
    8502           1 :         csspp::error::instance().set_show_debug(false);
    8503             : 
    8504           1 :         VERIFY_ERRORS("test.css(1): debug: This is a debug message.\n");
    8505             : 
    8506           1 :         CATCH_REQUIRE(c.get_root() == n);
    8507           1 :     }
    8508             : 
    8509             :     // no left over?
    8510           1 :     VERIFY_ERRORS("");
    8511           1 : }
    8512             : 
    8513           1 : CATCH_TEST_CASE("At-Keyword with qualified rules", "[compiler] [at-keyword]")
    8514             : {
    8515             :     // a valid @document
    8516             :     {
    8517           1 :         std::stringstream ss;
    8518           1 :         ss << "@document { body { content: \"Utf-16\" } }\n";
    8519           3 :         csspp::position pos("test.css");
    8520           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8521             : 
    8522           2 :         csspp::parser p(l);
    8523             : 
    8524           1 :         csspp::node::pointer_t n(p.stylesheet());
    8525             : 
    8526             :         // no errors so far
    8527           1 :         VERIFY_ERRORS("");
    8528             : 
    8529           1 :         csspp::compiler c;
    8530           1 :         c.set_root(n);
    8531           1 :         c.clear_paths();
    8532           1 :         c.add_path(csspp_test::get_script_path());
    8533           1 :         c.add_path(csspp_test::get_version_script_path());
    8534             : 
    8535           1 :         c.compile(true);
    8536             : 
    8537             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8538             : 
    8539           1 :         VERIFY_ERRORS("");
    8540             : 
    8541           1 :         std::stringstream out;
    8542           1 :         out << *n;
    8543           1 :         VERIFY_TREES(out.str(),
    8544             : 
    8545             : "LIST\n"
    8546             : "  AT_KEYWORD \"document\" I:0\n"
    8547             : "    OPEN_CURLYBRACKET B:true\n"
    8548             : "      COMPONENT_VALUE\n"
    8549             : "        ARG\n"
    8550             : "          IDENTIFIER \"body\"\n"
    8551             : "        OPEN_CURLYBRACKET B:true\n"
    8552             : "          DECLARATION \"content\"\n"
    8553             : "            ARG\n"
    8554             : "              STRING \"Utf-16\"\n"
    8555             : 
    8556             :             );
    8557             : 
    8558           1 :         CATCH_REQUIRE(c.get_root() == n);
    8559           1 :     }
    8560             : 
    8561             :     // a valid @document with @if inside of there
    8562             :     {
    8563           1 :         std::stringstream ss;
    8564             :         ss << "$agent: 'Firefox';\n"
    8565             :            << "@document {\n"
    8566             :            << "body { content: \"Utf-16\" }\n"
    8567             :            << "@if $agent = 'Firefox' { body { margin: 0 } div { border: 1px solid white } }\n"
    8568           1 :            << " }\n";
    8569           3 :         csspp::position pos("test.css");
    8570           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8571             : 
    8572           2 :         csspp::parser p(l);
    8573             : 
    8574           1 :         csspp::node::pointer_t n(p.stylesheet());
    8575             : 
    8576             :         // no errors so far
    8577           1 :         VERIFY_ERRORS("");
    8578             : 
    8579           1 :         csspp::compiler c;
    8580           1 :         c.set_root(n);
    8581           1 :         c.clear_paths();
    8582           1 :         c.add_path(csspp_test::get_script_path());
    8583           1 :         c.add_path(csspp_test::get_version_script_path());
    8584             : 
    8585           1 :         c.compile(true);
    8586             : 
    8587             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8588             : 
    8589           1 :         VERIFY_ERRORS("");
    8590             : 
    8591           1 :         std::stringstream out;
    8592           1 :         out << *n;
    8593           1 :         VERIFY_TREES(out.str(),
    8594             : 
    8595             : "LIST\n"
    8596             : "    V:agent\n"
    8597             : "      LIST\n"
    8598             : "        VARIABLE \"agent\"\n"
    8599             : "        STRING \"Firefox\"\n"
    8600             : "  AT_KEYWORD \"document\" I:0\n"
    8601             : "    OPEN_CURLYBRACKET B:true\n"
    8602             : "      COMPONENT_VALUE\n"
    8603             : "        ARG\n"
    8604             : "          IDENTIFIER \"body\"\n"
    8605             : "        OPEN_CURLYBRACKET B:true\n"
    8606             : "          DECLARATION \"content\"\n"
    8607             : "            ARG\n"
    8608             : "              STRING \"Utf-16\"\n"
    8609             : "      COMPONENT_VALUE\n"
    8610             : "        ARG\n"
    8611             : "          IDENTIFIER \"body\"\n"
    8612             : "        OPEN_CURLYBRACKET B:true\n"
    8613             : "          DECLARATION \"margin\"\n"
    8614             : "            ARG\n"
    8615             : "              INTEGER \"\" I:0\n"
    8616             : "      COMPONENT_VALUE\n"
    8617             : "        ARG\n"
    8618             : "          IDENTIFIER \"div\"\n"
    8619             : "        OPEN_CURLYBRACKET B:true\n"
    8620             : "          DECLARATION \"border\"\n"
    8621             : "            ARG\n"
    8622             : "              INTEGER \"px\" I:1\n"
    8623             : "              WHITESPACE\n"
    8624             : "              IDENTIFIER \"solid\"\n"
    8625             : "              WHITESPACE\n"
    8626             : "              COLOR H:ffffffff\n"
    8627             : 
    8628             :             );
    8629             : 
    8630           1 :         CATCH_REQUIRE(c.get_root() == n);
    8631           1 :     }
    8632             : 
    8633             :     // a valid @media
    8634             :     {
    8635           1 :         std::stringstream ss;
    8636           1 :         ss << "@media screen { i { font-style: normal } }\n";
    8637           3 :         csspp::position pos("test.css");
    8638           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8639             : 
    8640           2 :         csspp::parser p(l);
    8641             : 
    8642           1 :         csspp::node::pointer_t n(p.stylesheet());
    8643             : 
    8644             :         // no errors so far
    8645           1 :         VERIFY_ERRORS("");
    8646             : 
    8647           1 :         csspp::compiler c;
    8648           1 :         c.set_root(n);
    8649           1 :         c.clear_paths();
    8650           1 :         c.add_path(csspp_test::get_script_path());
    8651           1 :         c.add_path(csspp_test::get_version_script_path());
    8652             : 
    8653           1 :         c.compile(true);
    8654             : 
    8655             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8656             : 
    8657           1 :         VERIFY_ERRORS("");
    8658             : 
    8659           1 :         std::stringstream out;
    8660           1 :         out << *n;
    8661           1 :         VERIFY_TREES(out.str(),
    8662             : 
    8663             : "LIST\n"
    8664             : "  AT_KEYWORD \"media\" I:0\n"
    8665             : "    ARG\n"
    8666             : "      IDENTIFIER \"screen\"\n"
    8667             : "    OPEN_CURLYBRACKET B:true\n"
    8668             : "      COMPONENT_VALUE\n"
    8669             : "        ARG\n"
    8670             : "          IDENTIFIER \"i\"\n"
    8671             : "        OPEN_CURLYBRACKET B:true\n"
    8672             : "          DECLARATION \"font-style\"\n"
    8673             : "            ARG\n"
    8674             : "              IDENTIFIER \"normal\"\n"
    8675             : 
    8676             :             );
    8677             : 
    8678           1 :         CATCH_REQUIRE(c.get_root() == n);
    8679           1 :     }
    8680             : 
    8681             :     // nested @media
    8682             :     {
    8683           1 :         std::stringstream ss;
    8684             :         ss << "@media screen {\n"
    8685             :            << "  i { font-style: normal }\n"
    8686             :            << "  @media max-width(12cm) {\n"
    8687             :            << "    b { font-weight: normal }\n"
    8688             :            << "  }\n"
    8689           1 :            << "}\n";
    8690           3 :         csspp::position pos("test.css");
    8691           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8692             : 
    8693           2 :         csspp::parser p(l);
    8694             : 
    8695           1 :         csspp::node::pointer_t n(p.stylesheet());
    8696             : 
    8697             :         // no errors so far
    8698           1 :         VERIFY_ERRORS("");
    8699             : 
    8700           1 :         csspp::compiler c;
    8701           1 :         c.set_root(n);
    8702           1 :         c.clear_paths();
    8703           1 :         c.add_path(csspp_test::get_script_path());
    8704           1 :         c.add_path(csspp_test::get_version_script_path());
    8705             : 
    8706           1 :         c.compile(true);
    8707             : 
    8708             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8709             : 
    8710           1 :         VERIFY_ERRORS("");
    8711             : 
    8712           1 :         std::stringstream out;
    8713           1 :         out << *n;
    8714           1 :         VERIFY_TREES(out.str(),
    8715             : 
    8716             : "LIST\n"
    8717             : "  AT_KEYWORD \"media\" I:0\n"
    8718             : "    ARG\n"
    8719             : "      IDENTIFIER \"screen\"\n"
    8720             : "    OPEN_CURLYBRACKET B:true\n"
    8721             : "      COMPONENT_VALUE\n"
    8722             : "        ARG\n"
    8723             : "          IDENTIFIER \"i\"\n"
    8724             : "        OPEN_CURLYBRACKET B:true\n"
    8725             : "          DECLARATION \"font-style\"\n"
    8726             : "            ARG\n"
    8727             : "              IDENTIFIER \"normal\"\n"
    8728             : "      COMPONENT_VALUE\n"
    8729             : "        AT_KEYWORD \"media\" I:0\n"
    8730             : "          ARG\n"
    8731             : "            FUNCTION \"max-width\"\n"
    8732             : "              INTEGER \"cm\" I:12\n"
    8733             : "          OPEN_CURLYBRACKET B:true\n"
    8734             : "            COMPONENT_VALUE\n"
    8735             : "              ARG\n"
    8736             : "                IDENTIFIER \"b\"\n"
    8737             : "              OPEN_CURLYBRACKET B:true\n"
    8738             : "                DECLARATION \"font-weight\"\n"
    8739             : "                  ARG\n"
    8740             : "                    IDENTIFIER \"normal\"\n"
    8741             : 
    8742             :             );
    8743             : 
    8744           1 :         CATCH_REQUIRE(c.get_root() == n);
    8745           1 :     }
    8746             : 
    8747             :     // a valid @supports
    8748             :     {
    8749           1 :         std::stringstream ss;
    8750           1 :         ss << "@supports not (screen and desktop) { b { font-weight: normal } }\n";
    8751           3 :         csspp::position pos("test.css");
    8752           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8753             : 
    8754           2 :         csspp::parser p(l);
    8755             : 
    8756           1 :         csspp::node::pointer_t n(p.stylesheet());
    8757             : 
    8758             :         // no errors so far
    8759           1 :         VERIFY_ERRORS("");
    8760             : 
    8761           1 :         csspp::compiler c;
    8762           1 :         c.set_root(n);
    8763           1 :         c.clear_paths();
    8764           1 :         c.add_path(csspp_test::get_script_path());
    8765           1 :         c.add_path(csspp_test::get_version_script_path());
    8766             : 
    8767           1 :         c.compile(true);
    8768             : 
    8769             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8770             : 
    8771           1 :         VERIFY_ERRORS("");
    8772             : 
    8773           1 :         std::stringstream out;
    8774           1 :         out << *n;
    8775           1 :         VERIFY_TREES(out.str(),
    8776             : 
    8777             : "LIST\n"
    8778             : "  AT_KEYWORD \"supports\" I:0\n"
    8779             : "    ARG\n"
    8780             : "      IDENTIFIER \"not\"\n"
    8781             : "      OPEN_PARENTHESIS\n"
    8782             : "        IDENTIFIER \"screen\"\n"
    8783             : "        WHITESPACE\n"
    8784             : "        IDENTIFIER \"and\"\n"
    8785             : "        WHITESPACE\n"
    8786             : "        IDENTIFIER \"desktop\"\n"
    8787             : "    OPEN_CURLYBRACKET B:true\n"
    8788             : "      COMPONENT_VALUE\n"
    8789             : "        ARG\n"
    8790             : "          IDENTIFIER \"b\"\n"
    8791             : "        OPEN_CURLYBRACKET B:true\n"
    8792             : "          DECLARATION \"font-weight\"\n"
    8793             : "            ARG\n"
    8794             : "              IDENTIFIER \"normal\"\n"
    8795             : 
    8796             :             );
    8797             : 
    8798           1 :         CATCH_REQUIRE(c.get_root() == n);
    8799           1 :     }
    8800             : 
    8801             :     // no left over?
    8802           1 :     VERIFY_ERRORS("");
    8803           1 : }
    8804             : 
    8805           1 : CATCH_TEST_CASE("Invalid at-keyword expecting qualified rules", "[compiler] [at-keyword]")
    8806             : {
    8807             :     // a @supports without a {}-block
    8808             :     {
    8809           1 :         std::stringstream ss;
    8810           1 :         ss << "@supports not (screen and desktop);\n";
    8811           3 :         csspp::position pos("test.css");
    8812           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8813             : 
    8814           2 :         csspp::parser p(l);
    8815             : 
    8816           1 :         csspp::node::pointer_t n(p.stylesheet());
    8817             : 
    8818             :         // no errors so far
    8819           1 :         VERIFY_ERRORS("");
    8820             : 
    8821           1 :         csspp::compiler c;
    8822           1 :         c.set_root(n);
    8823           1 :         c.clear_paths();
    8824           1 :         c.add_path(csspp_test::get_script_path());
    8825           1 :         c.add_path(csspp_test::get_version_script_path());
    8826             : 
    8827           1 :         c.compile(true);
    8828             : 
    8829             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8830             : 
    8831           1 :         VERIFY_ERRORS("");
    8832             : 
    8833           1 :         std::stringstream out;
    8834           1 :         out << *n;
    8835           1 :         VERIFY_TREES(out.str(),
    8836             : 
    8837             : "LIST\n"
    8838             : "  AT_KEYWORD \"supports\" I:0\n"
    8839             : "    IDENTIFIER \"not\"\n"
    8840             : "    OPEN_PARENTHESIS\n"
    8841             : "      IDENTIFIER \"screen\"\n"
    8842             : "      WHITESPACE\n"
    8843             : "      IDENTIFIER \"and\"\n"
    8844             : "      WHITESPACE\n"
    8845             : "      IDENTIFIER \"desktop\"\n"
    8846             : 
    8847             :             );
    8848             : 
    8849           1 :         CATCH_REQUIRE(c.get_root() == n);
    8850           1 :     }
    8851             : 
    8852             :     // no left over?
    8853           1 :     VERIFY_ERRORS("");
    8854           1 : }
    8855             : 
    8856           1 : CATCH_TEST_CASE("At-Keyword with declarations", "[compiler] [at-keyword]")
    8857             : {
    8858             :     // a valid @page
    8859             :     {
    8860           1 :         std::stringstream ss;
    8861           1 :         ss << "@page { left: 2in; right: 2.2in; }\n";
    8862           3 :         csspp::position pos("test.css");
    8863           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8864             : 
    8865           2 :         csspp::parser p(l);
    8866             : 
    8867           1 :         csspp::node::pointer_t n(p.stylesheet());
    8868             : 
    8869             :         // no errors so far
    8870           1 :         VERIFY_ERRORS("");
    8871             : 
    8872           1 :         csspp::compiler c;
    8873           1 :         c.set_root(n);
    8874           1 :         c.clear_paths();
    8875           1 :         c.add_path(csspp_test::get_script_path());
    8876           1 :         c.add_path(csspp_test::get_version_script_path());
    8877             : 
    8878           1 :         c.compile(true);
    8879             : 
    8880             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8881             : 
    8882           1 :         VERIFY_ERRORS("");
    8883             : 
    8884           1 :         std::stringstream out;
    8885           1 :         out << *n;
    8886           1 :         VERIFY_TREES(out.str(),
    8887             : 
    8888             : "LIST\n"
    8889             : "  AT_KEYWORD \"page\" I:0\n"
    8890             : "    OPEN_CURLYBRACKET B:true\n"
    8891             : "      LIST\n"
    8892             : "        DECLARATION \"left\"\n"
    8893             : "          ARG\n"
    8894             : "            INTEGER \"in\" I:2\n"
    8895             : "        DECLARATION \"right\"\n"
    8896             : "          ARG\n"
    8897             : "            DECIMAL_NUMBER \"in\" D:2.2\n"
    8898             : 
    8899             :             );
    8900             : 
    8901           1 :         CATCH_REQUIRE(c.get_root() == n);
    8902           1 :     }
    8903             : 
    8904             :     // @page with an @media inside
    8905             :     {
    8906           1 :         std::stringstream ss;
    8907             :         ss << "@page {\n"
    8908             :            << "  left: 2in;\n"
    8909             :            << "  right: 2.2in;\n"
    8910             :            << "  @media screen {\n"
    8911             :            << "    .arg { color: grey }\n"
    8912             :            << "  }\n"
    8913           1 :            << "}\n";
    8914           3 :         csspp::position pos("test.css");
    8915           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8916             : 
    8917           2 :         csspp::parser p(l);
    8918             : 
    8919           1 :         csspp::node::pointer_t n(p.stylesheet());
    8920             : 
    8921             :         // no errors so far
    8922           1 :         VERIFY_ERRORS("");
    8923             : 
    8924           1 :         csspp::compiler c;
    8925           1 :         c.set_root(n);
    8926           1 :         c.clear_paths();
    8927           1 :         c.add_path(csspp_test::get_script_path());
    8928           1 :         c.add_path(csspp_test::get_version_script_path());
    8929             : 
    8930           1 :         c.compile(true);
    8931             : 
    8932             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8933             : 
    8934           1 :         VERIFY_ERRORS("");
    8935             : 
    8936           1 :         std::stringstream out;
    8937           1 :         out << *n;
    8938           1 :         VERIFY_TREES(out.str(),
    8939             : 
    8940             : "LIST\n"
    8941             : "  AT_KEYWORD \"page\" I:0\n"
    8942             : "    OPEN_CURLYBRACKET B:true\n"
    8943             : "      LIST\n"
    8944             : "        DECLARATION \"left\"\n"
    8945             : "          ARG\n"
    8946             : "            INTEGER \"in\" I:2\n"
    8947             : "        DECLARATION \"right\"\n"
    8948             : "          ARG\n"
    8949             : "            DECIMAL_NUMBER \"in\" D:2.2\n"
    8950             : "        COMPONENT_VALUE\n"
    8951             : "          AT_KEYWORD \"media\" I:0\n"
    8952             : "            ARG\n"
    8953             : "              IDENTIFIER \"screen\"\n"
    8954             : "            OPEN_CURLYBRACKET B:true\n"
    8955             : "              COMPONENT_VALUE\n"
    8956             : "                ARG\n"
    8957             : "                  PERIOD\n"
    8958             : "                  IDENTIFIER \"arg\"\n"
    8959             : "                OPEN_CURLYBRACKET B:true\n"
    8960             : "                  DECLARATION \"color\"\n"
    8961             : "                    ARG\n"
    8962             : "                      COLOR H:ff808080\n"
    8963             : 
    8964             :             );
    8965             : 
    8966           1 :         CATCH_REQUIRE(c.get_root() == n);
    8967           1 :     }
    8968             : 
    8969             :     // a valid @supports
    8970             :     {
    8971           1 :         std::stringstream ss;
    8972           1 :         ss << "@font-face{unicode-range: U+4??;font-style:italic}\n";
    8973           3 :         csspp::position pos("test.css");
    8974           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    8975             : 
    8976           2 :         csspp::parser p(l);
    8977             : 
    8978           1 :         csspp::node::pointer_t n(p.stylesheet());
    8979             : 
    8980             :         // no errors so far
    8981           1 :         VERIFY_ERRORS("");
    8982             : 
    8983           1 :         csspp::compiler c;
    8984           1 :         c.set_root(n);
    8985           1 :         c.clear_paths();
    8986           1 :         c.add_path(csspp_test::get_script_path());
    8987           1 :         c.add_path(csspp_test::get_version_script_path());
    8988             : 
    8989           1 :         c.compile(true);
    8990             : 
    8991             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    8992             : 
    8993           1 :         VERIFY_ERRORS("");
    8994             : 
    8995           1 :         std::stringstream out;
    8996           1 :         out << *n;
    8997           1 :         VERIFY_TREES(out.str(),
    8998             : 
    8999             : "LIST\n"
    9000             : "  AT_KEYWORD \"font-face\" I:0\n"
    9001             : "    OPEN_CURLYBRACKET B:true\n"
    9002             : "      LIST\n"
    9003             : "        DECLARATION \"unicode-range\"\n"
    9004             : "          ARG\n"
    9005             : "            UNICODE_RANGE I:5493263172608\n"
    9006             : "        DECLARATION \"font-style\"\n"
    9007             : "          ARG\n"
    9008             : "            IDENTIFIER \"italic\"\n"
    9009             : 
    9010             :             );
    9011             : 
    9012           1 :         CATCH_REQUIRE(c.get_root() == n);
    9013           1 :     }
    9014             : 
    9015             :     // no left over?
    9016           1 :     VERIFY_ERRORS("");
    9017           1 : }
    9018             : 
    9019           1 : CATCH_TEST_CASE("Charset", "[compiler] [invalid]")
    9020             : {
    9021             :     // a valid @charset
    9022             :     {
    9023           1 :         std::stringstream ss;
    9024             :         ss << "@charset \"Utf-8\";\n"
    9025           1 :            << "html{margin:0}\n";
    9026           3 :         csspp::position pos("test.css");
    9027           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9028             : 
    9029           2 :         csspp::parser p(l);
    9030             : 
    9031           1 :         csspp::node::pointer_t n(p.stylesheet());
    9032             : 
    9033             :         // no errors so far
    9034           1 :         VERIFY_ERRORS("");
    9035             : 
    9036           1 :         csspp::compiler c;
    9037           1 :         c.set_root(n);
    9038           1 :         c.clear_paths();
    9039           1 :         c.add_path(csspp_test::get_script_path());
    9040           1 :         c.add_path(csspp_test::get_version_script_path());
    9041             : 
    9042           1 :         c.compile(true);
    9043             : 
    9044             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9045             : 
    9046           1 :         VERIFY_ERRORS("");
    9047             : 
    9048           1 :         std::stringstream out;
    9049           1 :         out << *n;
    9050           1 :         VERIFY_TREES(out.str(),
    9051             : 
    9052             : "LIST\n"
    9053             : "  COMPONENT_VALUE\n"
    9054             : "    ARG\n"
    9055             : "      IDENTIFIER \"html\"\n"
    9056             : "    OPEN_CURLYBRACKET B:true\n"
    9057             : "      DECLARATION \"margin\"\n"
    9058             : "        ARG\n"
    9059             : "          INTEGER \"\" I:0\n"
    9060             : 
    9061             :             );
    9062             : 
    9063           1 :         CATCH_REQUIRE(c.get_root() == n);
    9064           1 :     }
    9065             : 
    9066             :     // a valid @charset with many spaces
    9067             :     {
    9068           1 :         std::stringstream ss;
    9069             :         ss << "   @charset   \"   UTF-8   \"   ;\n"
    9070           1 :            << "html{margin:0}\n";
    9071           3 :         csspp::position pos("test.css");
    9072           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9073             : 
    9074           2 :         csspp::parser p(l);
    9075             : 
    9076           1 :         csspp::node::pointer_t n(p.stylesheet());
    9077             : 
    9078             :         // no errors so far
    9079           1 :         VERIFY_ERRORS("");
    9080             : 
    9081           1 :         csspp::compiler c;
    9082           1 :         c.set_root(n);
    9083           1 :         c.clear_paths();
    9084           1 :         c.add_path(csspp_test::get_script_path());
    9085           1 :         c.add_path(csspp_test::get_version_script_path());
    9086             : 
    9087           1 :         c.compile(true);
    9088             : 
    9089             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9090             : 
    9091           1 :         VERIFY_ERRORS("");
    9092             : 
    9093           1 :         std::stringstream out;
    9094           1 :         out << *n;
    9095           1 :         VERIFY_TREES(out.str(),
    9096             : 
    9097             : "LIST\n"
    9098             : "  COMPONENT_VALUE\n"
    9099             : "    ARG\n"
    9100             : "      IDENTIFIER \"html\"\n"
    9101             : "    OPEN_CURLYBRACKET B:true\n"
    9102             : "      DECLARATION \"margin\"\n"
    9103             : "        ARG\n"
    9104             : "          INTEGER \"\" I:0\n"
    9105             : 
    9106             :             );
    9107             : 
    9108           1 :         CATCH_REQUIRE(c.get_root() == n);
    9109           1 :     }
    9110             : 
    9111             :     // an @charset with a refused encoding
    9112             :     {
    9113           1 :         std::stringstream ss;
    9114             :         ss << "@charset \"iso-8859-6\";\n"
    9115           1 :            << "html{margin:0}\n";
    9116           3 :         csspp::position pos("test.css");
    9117           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9118             : 
    9119           2 :         csspp::parser p(l);
    9120             : 
    9121           1 :         csspp::node::pointer_t n(p.stylesheet());
    9122             : 
    9123             :         // no errors so far
    9124           1 :         VERIFY_ERRORS("");
    9125             : 
    9126           1 :         csspp::compiler c;
    9127           1 :         c.set_root(n);
    9128           1 :         c.clear_paths();
    9129           1 :         c.add_path(csspp_test::get_script_path());
    9130           1 :         c.add_path(csspp_test::get_version_script_path());
    9131             : 
    9132           1 :         c.compile(true);
    9133             : 
    9134             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9135             : 
    9136           1 :         VERIFY_ERRORS("test.css(1): error: we only support @charset \"utf-8\";, any other encoding is refused.\n");
    9137             : 
    9138           1 :         std::stringstream out;
    9139           1 :         out << *n;
    9140           1 :         VERIFY_TREES(out.str(),
    9141             : 
    9142             : "LIST\n"
    9143             : "  COMPONENT_VALUE\n"
    9144             : "    ARG\n"
    9145             : "      IDENTIFIER \"html\"\n"
    9146             : "    OPEN_CURLYBRACKET B:true\n"
    9147             : "      DECLARATION \"margin\"\n"
    9148             : "        ARG\n"
    9149             : "          INTEGER \"\" I:0\n"
    9150             : 
    9151             :             );
    9152             : 
    9153           1 :         CATCH_REQUIRE(c.get_root() == n);
    9154           1 :     }
    9155             : 
    9156             :     // an @charset with a decimal number
    9157             :     {
    9158           1 :         std::stringstream ss;
    9159             :         ss << "@charset 8859.6;\n"
    9160           1 :            << "html{margin:0}\n";
    9161           3 :         csspp::position pos("test.css");
    9162           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9163             : 
    9164           2 :         csspp::parser p(l);
    9165             : 
    9166           1 :         csspp::node::pointer_t n(p.stylesheet());
    9167             : 
    9168             :         // no errors so far
    9169           1 :         VERIFY_ERRORS("");
    9170             : 
    9171           1 :         csspp::compiler c;
    9172           1 :         c.set_root(n);
    9173           1 :         c.clear_paths();
    9174           1 :         c.add_path(csspp_test::get_script_path());
    9175           1 :         c.add_path(csspp_test::get_version_script_path());
    9176             : 
    9177           1 :         c.compile(true);
    9178             : 
    9179             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9180             : 
    9181           1 :         VERIFY_ERRORS("test.css(1): error: the @charset is expected to be followed by exactly one string.\n");
    9182             : 
    9183           1 :         std::stringstream out;
    9184           1 :         out << *n;
    9185           1 :         VERIFY_TREES(out.str(),
    9186             : 
    9187             : "LIST\n"
    9188             : "  COMPONENT_VALUE\n"
    9189             : "    ARG\n"
    9190             : "      IDENTIFIER \"html\"\n"
    9191             : "    OPEN_CURLYBRACKET B:true\n"
    9192             : "      DECLARATION \"margin\"\n"
    9193             : "        ARG\n"
    9194             : "          INTEGER \"\" I:0\n"
    9195             : 
    9196             :             );
    9197             : 
    9198           1 :         CATCH_REQUIRE(c.get_root() == n);
    9199           1 :     }
    9200             : 
    9201             :     // no left over?
    9202           1 :     VERIFY_ERRORS("");
    9203           1 : }
    9204             : 
    9205           1 : CATCH_TEST_CASE("Conditional compilation", "[compiler] [conditional]")
    9206             : {
    9207             :     // script with @if / @else if / @else keywords
    9208             :     {
    9209           1 :         std::stringstream ss;
    9210             :         ss << "$var: true;\n"
    9211             :            << "@if $var { @message \"Got here! (1)\" ; }\n"
    9212             :            << "@else if $var { @message \"Got here! (2)\";}\n"
    9213             :            << "@else{@message\"Got here! (3)\";}\n"
    9214           1 :            << "ul { list: cross; }";
    9215           3 :         csspp::position pos("test.css");
    9216           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9217             : 
    9218           2 :         csspp::parser p(l);
    9219             : 
    9220           1 :         csspp::node::pointer_t n(p.stylesheet());
    9221             : 
    9222             : //std::cerr << "Parser result is: [" << *n << "]\n";
    9223             : 
    9224             :         // no errors so far
    9225           1 :         VERIFY_ERRORS("");
    9226             : 
    9227           1 :         csspp::compiler c;
    9228           1 :         c.set_root(n);
    9229           1 :         c.clear_paths();
    9230           1 :         c.add_path(csspp_test::get_script_path());
    9231           1 :         c.add_path(csspp_test::get_version_script_path());
    9232             : 
    9233           1 :         c.compile(true);
    9234             : 
    9235             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9236             : 
    9237           1 :         VERIFY_ERRORS("test.css(2): info: Got here! (1)\n");
    9238             : 
    9239           1 :         std::stringstream out;
    9240           1 :         out << *n;
    9241           1 :         VERIFY_TREES(out.str(),
    9242             : 
    9243             : "LIST\n"
    9244             : "    V:var\n"
    9245             : "      LIST\n"
    9246             : "        VARIABLE \"var\"\n"
    9247             : "        IDENTIFIER \"true\"\n"
    9248             : "  COMPONENT_VALUE\n"
    9249             : "    ARG\n"
    9250             : "      IDENTIFIER \"ul\"\n"
    9251             : "    OPEN_CURLYBRACKET B:true\n"
    9252             : "      DECLARATION \"list\"\n"
    9253             : "        ARG\n"
    9254             : "          IDENTIFIER \"cross\"\n"
    9255             : 
    9256             :             );
    9257             : 
    9258           1 :         CATCH_REQUIRE(c.get_root() == n);
    9259           1 :     }
    9260             : 
    9261             :     // script with @if / @else if / @else keywords
    9262             :     {
    9263           1 :         std::stringstream ss;
    9264             :         ss << "$var: 2;\n"
    9265             :            << "@if $var = 1 { @message \"Got here! (1)\" ; }\n"
    9266             :            << "@else if $var = 2 { @message \"Got here! (2)\";}\n"
    9267             :            << "@else{@message\"Got here! (3)\";}\n"
    9268           1 :            << "ul { list: cross; }";
    9269           3 :         csspp::position pos("test.css");
    9270           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9271             : 
    9272           2 :         csspp::parser p(l);
    9273             : 
    9274           1 :         csspp::node::pointer_t n(p.stylesheet());
    9275             : 
    9276             :         // no errors so far
    9277           1 :         VERIFY_ERRORS("");
    9278             : 
    9279           1 :         csspp::compiler c;
    9280           1 :         c.set_root(n);
    9281           1 :         c.clear_paths();
    9282           1 :         c.add_path(csspp_test::get_script_path());
    9283           1 :         c.add_path(csspp_test::get_version_script_path());
    9284             : 
    9285           1 :         c.compile(true);
    9286             : 
    9287             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9288             : 
    9289           1 :         VERIFY_ERRORS("test.css(3): info: Got here! (2)\n");
    9290             : 
    9291           1 :         std::stringstream out;
    9292           1 :         out << *n;
    9293           1 :         VERIFY_TREES(out.str(),
    9294             : 
    9295             : "LIST\n"
    9296             : "    V:var\n"
    9297             : "      LIST\n"
    9298             : "        VARIABLE \"var\"\n"
    9299             : "        INTEGER \"\" I:2\n"
    9300             : "  COMPONENT_VALUE\n"
    9301             : "    ARG\n"
    9302             : "      IDENTIFIER \"ul\"\n"
    9303             : "    OPEN_CURLYBRACKET B:true\n"
    9304             : "      DECLARATION \"list\"\n"
    9305             : "        ARG\n"
    9306             : "          IDENTIFIER \"cross\"\n"
    9307             : 
    9308             :             );
    9309             : 
    9310           1 :         CATCH_REQUIRE(c.get_root() == n);
    9311           1 :     }
    9312             : 
    9313             :     // script with @if / @else if / @else keywords
    9314             :     {
    9315           1 :         std::stringstream ss;
    9316             :         ss << "$var: -192;\n"
    9317             :            << "@if $var = 1 { @message \"Got here! (1)\" ; }\n"
    9318             :            << "@else if $var = 2 { @message \"Got here! (2)\";}\n"
    9319             :            << "@else{@message\"Got here! (3)\";}\n"
    9320           1 :            << "ul { list: cross; }";
    9321           3 :         csspp::position pos("test.css");
    9322           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9323             : 
    9324           2 :         csspp::parser p(l);
    9325             : 
    9326           1 :         csspp::node::pointer_t n(p.stylesheet());
    9327             : 
    9328             :         // no errors so far
    9329           1 :         VERIFY_ERRORS("");
    9330             : 
    9331           1 :         csspp::compiler c;
    9332           1 :         c.set_root(n);
    9333           1 :         c.clear_paths();
    9334           1 :         c.add_path(csspp_test::get_script_path());
    9335           1 :         c.add_path(csspp_test::get_version_script_path());
    9336             : 
    9337           1 :         c.compile(true);
    9338             : 
    9339             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9340             : 
    9341           1 :         VERIFY_ERRORS("test.css(4): info: Got here! (3)\n");
    9342             : 
    9343           1 :         std::stringstream out;
    9344           1 :         out << *n;
    9345           1 :         VERIFY_TREES(out.str(),
    9346             : 
    9347             : "LIST\n"
    9348             : "    V:var\n"
    9349             : "      LIST\n"
    9350             : "        VARIABLE \"var\"\n"
    9351             : "        INTEGER \"\" I:-192\n"
    9352             : "  COMPONENT_VALUE\n"
    9353             : "    ARG\n"
    9354             : "      IDENTIFIER \"ul\"\n"
    9355             : "    OPEN_CURLYBRACKET B:true\n"
    9356             : "      DECLARATION \"list\"\n"
    9357             : "        ARG\n"
    9358             : "          IDENTIFIER \"cross\"\n"
    9359             : 
    9360             :             );
    9361             : 
    9362           1 :         CATCH_REQUIRE(c.get_root() == n);
    9363           1 :     }
    9364             : 
    9365             :     // no left over?
    9366           1 :     VERIFY_ERRORS("");
    9367           1 : }
    9368             : 
    9369           1 : CATCH_TEST_CASE("Invalid conditional", "[compiler] [conditional] [invalid]")
    9370             : {
    9371             :     // script with @if / @else if / @else keywords
    9372             :     // invalid "@else if" which includes an expression
    9373             :     {
    9374           1 :         std::stringstream ss;
    9375             :         ss << "$zzvar: false;\n"
    9376             :            << "@if { @message \"Got here! (1)\" ; }\n"
    9377             :            << "@else if { @message \"Got here! (2)\";}\n"
    9378             :            << "@else{@message\"Got here! (3)\";}\n"
    9379           1 :            << "ul { list: cross; }";
    9380           3 :         csspp::position pos("test.css");
    9381           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9382             : 
    9383           2 :         csspp::parser p(l);
    9384             : 
    9385           1 :         csspp::node::pointer_t n(p.stylesheet());
    9386             : 
    9387             : //std::cerr << "Parser result is: [" << *n << "]\n";
    9388             : 
    9389             :         // no errors so far
    9390           1 :         VERIFY_ERRORS("");
    9391             : 
    9392           1 :         csspp::compiler c;
    9393           1 :         c.set_root(n);
    9394           1 :         c.set_date_time_variables(csspp_test::get_now());
    9395           1 :         c.clear_paths();
    9396           1 :         c.add_path(csspp_test::get_script_path());
    9397           1 :         c.add_path(csspp_test::get_version_script_path());
    9398             : 
    9399           1 :         c.compile(false);
    9400             : 
    9401             : //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
    9402             : 
    9403           1 :         VERIFY_ERRORS(
    9404             :                 "test.css(2): error: @if is expected to have exactly 2 parameters: an expression and a block. This @if has 1 parameters.\n"
    9405             :                 "test.css(3): error: '@else if ...' is missing an expression or a block.\n"
    9406             :                 //"test.css(3): error: a standalone @else is not legal, it has to be preceeded by an @if ... or @else if ...\n"
    9407             :                 //"test.css(4): error: a standalone @else is not legal, it has to be preceeded by an @if ... or @else if ...\n"
    9408             :             );
    9409             : 
    9410           1 :         std::stringstream out;
    9411           1 :         out << *n;
    9412           1 :         VERIFY_TREES(out.str(),
    9413             : 
    9414             : "LIST\n"
    9415             : + csspp_test::get_default_variables() +
    9416             : "    V:zzvar\n"
    9417             : "      LIST\n"
    9418             : "        VARIABLE \"zzvar\"\n"
    9419             : "        IDENTIFIER \"false\"\n"
    9420             : "  COMPONENT_VALUE\n"
    9421             : "    ARG\n"
    9422             : "      IDENTIFIER \"ul\"\n"
    9423             : "    OPEN_CURLYBRACKET B:true\n"
    9424             : "      DECLARATION \"list\"\n"
    9425             : "        ARG\n"
    9426             : "          IDENTIFIER \"cross\"\n"
    9427             : + csspp_test::get_close_comment(true)
    9428             : 
    9429             :             );
    9430             : 
    9431           1 :         CATCH_REQUIRE(c.get_root() == n);
    9432           1 :     }
    9433             : 
    9434             :     // script with @if / @else if / @else keywords
    9435             :     // invalid "@else if" which includes an expression
    9436             :     {
    9437           1 :         std::stringstream ss;
    9438             :         ss << "$var: false;\n"
    9439             :            << "@if $var { @message \"Got here! (1)\" ; }\n"
    9440             :            << "@else if + { @message \"Got here! (2)\";}\n"
    9441             :            << "@else{@message\"Got here! (3)\";}\n"
    9442           1 :            << "ul { list: cross; }";
    9443           3 :         csspp::position pos("test.css");
    9444           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9445             : 
    9446           2 :         csspp::parser p(l);
    9447             : 
    9448           1 :         csspp::node::pointer_t n(p.stylesheet());
    9449             : 
    9450             :         // no errors so far
    9451           1 :         VERIFY_ERRORS("");
    9452             : 
    9453           1 :         csspp::compiler c;
    9454           1 :         c.set_root(n);
    9455           1 :         c.clear_paths();
    9456           1 :         c.add_path(csspp_test::get_script_path());
    9457           1 :         c.add_path(csspp_test::get_version_script_path());
    9458             : 
    9459           1 :         c.compile(true);
    9460             : 
    9461             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9462             : 
    9463           1 :         VERIFY_ERRORS(
    9464             :                 "test.css(3): error: unsupported type OPEN_CURLYBRACKET as a unary expression token.\n"
    9465             :                 "test.css(3): error: '@else { ... }' is expected to have 1 parameter, '@else if ... { ... }' is expected to have 2 parameters. This @else has 2 parameters.\n"
    9466             :                 //"test.css(4): error: a standalone @else is not legal, it has to be preceeded by an @if ... or @else if ...\n"
    9467             :             );
    9468             : 
    9469           1 :         std::stringstream out;
    9470           1 :         out << *n;
    9471           1 :         VERIFY_TREES(out.str(),
    9472             : 
    9473             : "LIST\n"
    9474             : "    V:var\n"
    9475             : "      LIST\n"
    9476             : "        VARIABLE \"var\"\n"
    9477             : "        IDENTIFIER \"false\"\n"
    9478             : "  COMPONENT_VALUE\n"
    9479             : "    ARG\n"
    9480             : "      IDENTIFIER \"ul\"\n"
    9481             : "    OPEN_CURLYBRACKET B:true\n"
    9482             : "      DECLARATION \"list\"\n"
    9483             : "        ARG\n"
    9484             : "          IDENTIFIER \"cross\"\n"
    9485             : 
    9486             :             );
    9487             : 
    9488           1 :         CATCH_REQUIRE(c.get_root() == n);
    9489           1 :     }
    9490             : 
    9491             :     // script with @if / @else if / @else keywords
    9492             :     // invalid "@else" which includes an expression
    9493             :     {
    9494           1 :         std::stringstream ss;
    9495             :         ss << "$var: false;\n"
    9496             :            << "@if $var { @message \"Got here! (1)\" ; }\n"
    9497             :            << "@else if $var { @message \"Got here! (2)\";}\n"
    9498             :            << "@else $var {@message\"Got here! (3)\";}\n"   // TODO: this doesn't get caught?!
    9499           1 :            << "ul { list: cross; }";
    9500           3 :         csspp::position pos("test.css");
    9501           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9502             : 
    9503           2 :         csspp::parser p(l);
    9504             : 
    9505           1 :         csspp::node::pointer_t n(p.stylesheet());
    9506             : 
    9507             :         // no errors so far
    9508           1 :         VERIFY_ERRORS("");
    9509             : 
    9510           1 :         csspp::compiler c;
    9511           1 :         c.set_root(n);
    9512           1 :         c.clear_paths();
    9513           1 :         c.add_path(csspp_test::get_script_path());
    9514           1 :         c.add_path(csspp_test::get_version_script_path());
    9515             : 
    9516           1 :         c.compile(true);
    9517             : 
    9518             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9519             : 
    9520           1 :         VERIFY_ERRORS(""
    9521             :                 "test.css(4): error: '@else { ... }' is expected to have 1 parameter, '@else if ... { ... }' is expected to have 2 parameters. This @else has 2 parameters.\n"
    9522             :                 //"test.css(3): error: '@else if ...' is missing an expression or a block.\n"
    9523             :                 //"test.css(3): error: '@else { ... }' cannot follow another '@else { ... }'. Maybe you are missing an 'if expr'?\n"
    9524             :                 //"test.css(4): error: a standalone @else is not legal, it has to be preceeded by an @if ... or @else if ...\n"
    9525             :                 //"test.css(3): info: Got here! (2)\n"
    9526             :             );
    9527             : 
    9528           1 :         std::stringstream out;
    9529           1 :         out << *n;
    9530           1 :         VERIFY_TREES(out.str(),
    9531             : 
    9532             : "LIST\n"
    9533             : "    V:var\n"
    9534             : "      LIST\n"
    9535             : "        VARIABLE \"var\"\n"
    9536             : "        IDENTIFIER \"false\"\n"
    9537             : "  COMPONENT_VALUE\n"
    9538             : "    ARG\n"
    9539             : "      IDENTIFIER \"ul\"\n"
    9540             : "    OPEN_CURLYBRACKET B:true\n"
    9541             : "      DECLARATION \"list\"\n"
    9542             : "        ARG\n"
    9543             : "          IDENTIFIER \"cross\"\n"
    9544             : 
    9545             :             );
    9546             : 
    9547           1 :         CATCH_REQUIRE(c.get_root() == n);
    9548           1 :     }
    9549             : 
    9550             :     // script with @if / @else if / @else keywords
    9551             :     // spurious "@else"
    9552             :     {
    9553           1 :         std::stringstream ss;
    9554             :         ss << "$var: false;\n"
    9555             :            << "@if $var { @message \"Got here! (1)\" ; }\n"
    9556             :            << "@else if $var { @message \"Got here! (2)\";}\n"
    9557             :            << "@else {@message\"Got here! (3)\";}\n"
    9558             :            << "@else { @message\"Spurious! (4)\";}\n"
    9559           1 :            << "ul { list: cross; }";
    9560           3 :         csspp::position pos("test.css");
    9561           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9562             : 
    9563           2 :         csspp::parser p(l);
    9564             : 
    9565           1 :         csspp::node::pointer_t n(p.stylesheet());
    9566             : 
    9567             :         // no errors so far
    9568           1 :         VERIFY_ERRORS("");
    9569             : 
    9570           1 :         csspp::compiler c;
    9571           1 :         c.set_root(n);
    9572           1 :         c.clear_paths();
    9573           1 :         c.add_path(csspp_test::get_script_path());
    9574           1 :         c.add_path(csspp_test::get_version_script_path());
    9575             : 
    9576           1 :         c.compile(true);
    9577             : 
    9578             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9579             : 
    9580           1 :         VERIFY_ERRORS(""
    9581             :                 "test.css(4): error: '@else { ... }' cannot follow another '@else { ... }'. Maybe you are missing an 'if expr'?\n"
    9582             :                 "test.css(5): error: a standalone @else is not legal, it has to be preceeded by an @if ... or @else if ...\n"
    9583             :                 //"test.css(4): info: Got here! (3)\n"
    9584             :             );
    9585             : 
    9586           1 :         std::stringstream out;
    9587           1 :         out << *n;
    9588           1 :         VERIFY_TREES(out.str(),
    9589             : 
    9590             : "LIST\n"
    9591             : "    V:var\n"
    9592             : "      LIST\n"
    9593             : "        VARIABLE \"var\"\n"
    9594             : "        IDENTIFIER \"false\"\n"
    9595             : "  COMPONENT_VALUE\n"
    9596             : "    ARG\n"
    9597             : "      IDENTIFIER \"ul\"\n"
    9598             : "    OPEN_CURLYBRACKET B:true\n"
    9599             : "      DECLARATION \"list\"\n"
    9600             : "        ARG\n"
    9601             : "          IDENTIFIER \"cross\"\n"
    9602             : 
    9603             :             );
    9604             : 
    9605           1 :         CATCH_REQUIRE(c.get_root() == n);
    9606           1 :     }
    9607             : 
    9608             :     // no left over?
    9609           1 :     VERIFY_ERRORS("");
    9610           1 : }
    9611             : 
    9612           1 : CATCH_TEST_CASE("User @import", "[compiler] [at-keyword]")
    9613             : {
    9614             :     // @import with a valid URL
    9615             :     {
    9616             :         // write a file (in a block so it gets flushed and closed)
    9617             :         {
    9618           1 :             std::ofstream importing;
    9619           1 :             importing.open("importing.scss");
    9620           1 :             CATCH_REQUIRE(!!importing);
    9621           1 :             importing << "/* @preserve this worked! {$_csspp_version} */";
    9622           1 :         }
    9623           1 :         std::stringstream ss;
    9624             :         {
    9625           1 :             std::unique_ptr<char, void (*)(char *)> cwd(get_current_dir_name(), free_char);
    9626             :             ss << "@import url(file://"
    9627           1 :                << cwd.get()
    9628           1 :                << "/importing.scss);";
    9629           1 :         }
    9630           3 :         csspp::position pos("test.css");
    9631           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9632             : 
    9633           2 :         csspp::parser p(l);
    9634             : 
    9635           1 :         csspp::node::pointer_t n(p.stylesheet());
    9636             : 
    9637             :         // no errors so far
    9638           1 :         VERIFY_ERRORS("");
    9639             : 
    9640           1 :         csspp::compiler c;
    9641           1 :         c.set_root(n);
    9642           1 :         c.set_date_time_variables(csspp_test::get_now());
    9643           1 :         c.clear_paths();
    9644           1 :         c.add_path(csspp_test::get_script_path());
    9645           1 :         c.add_path(csspp_test::get_version_script_path());
    9646             : 
    9647           1 :         c.compile(false);
    9648             : 
    9649           1 :         VERIFY_ERRORS("");
    9650             : 
    9651           1 :         std::stringstream out;
    9652           1 :         out << *n;
    9653           1 :         VERIFY_TREES(out.str(),
    9654             : 
    9655             : "LIST\n"
    9656             : + csspp_test::get_default_variables() +
    9657             : "  COMMENT \"@preserve this worked! " CSSPP_VERSION "\" I:1\n"
    9658             : + csspp_test::get_close_comment(true)
    9659             : 
    9660             :             );
    9661             : 
    9662           1 :         unlink("importing.scss");
    9663             : 
    9664           1 :         CATCH_REQUIRE(c.get_root() == n);
    9665           1 :     }
    9666             : 
    9667             :     // @import with a valid path as a URL (thus not recognized as a file://)
    9668             :     {
    9669           1 :         std::stringstream ss;
    9670           1 :         ss << "@import url(system/version);";
    9671           3 :         csspp::position pos("test.css");
    9672           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9673             : 
    9674           2 :         csspp::parser p(l);
    9675             : 
    9676           1 :         csspp::node::pointer_t n(p.stylesheet());
    9677             : 
    9678             :         // no errors so far
    9679           1 :         VERIFY_ERRORS("");
    9680             : 
    9681           1 :         csspp::compiler c;
    9682           1 :         c.set_root(n);
    9683           1 :         c.clear_paths();
    9684           1 :         c.add_path(csspp_test::get_script_path());
    9685           1 :         c.add_path(csspp_test::get_version_script_path());
    9686             : 
    9687           1 :         c.compile(true);
    9688             : 
    9689           1 :         VERIFY_ERRORS("");
    9690             : 
    9691           1 :         std::stringstream out;
    9692           1 :         out << *n;
    9693           1 :         VERIFY_TREES(out.str(),
    9694             : 
    9695             : "LIST\n"
    9696             : "  AT_KEYWORD \"import\" I:0\n"
    9697             : "    URL \"system/version\"\n"
    9698             : 
    9699             :             );
    9700             : 
    9701           1 :         CATCH_REQUIRE(c.get_root() == n);
    9702           1 :     }
    9703             : 
    9704             :     // @import with a valid path as a URL (thus not recognized as a file://)
    9705             :     {
    9706           1 :         std::stringstream ss;
    9707           1 :         ss << "@import 'http://csspp.org/css/special.css';";
    9708           3 :         csspp::position pos("test.css");
    9709           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9710             : 
    9711           2 :         csspp::parser p(l);
    9712             : 
    9713           1 :         csspp::node::pointer_t n(p.stylesheet());
    9714             : 
    9715             :         // no errors so far
    9716           1 :         VERIFY_ERRORS("");
    9717             : 
    9718           1 :         csspp::compiler c;
    9719           1 :         c.set_root(n);
    9720           1 :         c.clear_paths();
    9721           1 :         c.add_path(csspp_test::get_script_path());
    9722           1 :         c.add_path(csspp_test::get_version_script_path());
    9723             : 
    9724           1 :         c.compile(true);
    9725             : 
    9726           1 :         VERIFY_ERRORS("");
    9727             : 
    9728           1 :         std::stringstream out;
    9729           1 :         out << *n;
    9730           1 :         VERIFY_TREES(out.str(),
    9731             : 
    9732             : "LIST\n"
    9733             : "  AT_KEYWORD \"import\" I:0\n"
    9734             : "    STRING \"http://csspp.org/css/special.css\"\n"
    9735             : 
    9736             :             );
    9737             : 
    9738           1 :         CATCH_REQUIRE(c.get_root() == n);
    9739           1 :     }
    9740             : 
    9741             :     // no left over?
    9742           1 :     VERIFY_ERRORS("");
    9743           1 : }
    9744             : 
    9745           1 : CATCH_TEST_CASE("Invalid @import", "[compiler] [at-keyword] [invalid]")
    9746             : {
    9747             :     // @import with URL representing a an inexistant file
    9748             :     {
    9749           1 :         std::stringstream ss;
    9750           1 :         ss << "@import url(file:///this/shall/not/exist/anywhere/on/your/drive);";
    9751           3 :         csspp::position pos("test.css");
    9752           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9753             : 
    9754           2 :         csspp::parser p(l);
    9755             : 
    9756           1 :         csspp::node::pointer_t n(p.stylesheet());
    9757             : 
    9758             :         // no errors so far
    9759           1 :         VERIFY_ERRORS("");
    9760             : 
    9761           1 :         csspp::compiler c;
    9762           1 :         c.set_root(n);
    9763           1 :         c.clear_paths();
    9764           1 :         c.add_path(csspp_test::get_script_path());
    9765           1 :         c.add_path(csspp_test::get_version_script_path());
    9766             : 
    9767           1 :         c.compile(true);
    9768             : 
    9769           1 :         VERIFY_ERRORS("test.css(1): info: @import uri(/this/shall/not/exist/anywhere/on/your/drive); left alone by the CSS Preprocessor, no matching file found.\n");
    9770             : 
    9771           1 :         std::stringstream out;
    9772           1 :         out << *n;
    9773           1 :         VERIFY_TREES(out.str(),
    9774             : 
    9775             : "LIST\n"
    9776             : "  AT_KEYWORD \"import\" I:0\n"
    9777             : "    URL \"file:///this/shall/not/exist/anywhere/on/your/drive\"\n"
    9778             : 
    9779             :             );
    9780             : 
    9781           1 :         CATCH_REQUIRE(c.get_root() == n);
    9782           1 :     }
    9783             : 
    9784             :     // @import with URL representing a an inexistant file
    9785             :     {
    9786           1 :         std::stringstream ss;
    9787           1 :         ss << "@import url(file://this/shall/not/exist/either/on/your/drive);";
    9788           3 :         csspp::position pos("test.css");
    9789           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9790             : 
    9791           2 :         csspp::parser p(l);
    9792             : 
    9793           1 :         csspp::node::pointer_t n(p.stylesheet());
    9794             : 
    9795             :         // no errors so far
    9796           1 :         VERIFY_ERRORS("");
    9797             : 
    9798           1 :         csspp::compiler c;
    9799           1 :         c.set_root(n);
    9800           1 :         c.clear_paths();
    9801           1 :         c.add_path(csspp_test::get_script_path());
    9802           1 :         c.add_path(csspp_test::get_version_script_path());
    9803             : 
    9804           1 :         c.compile(true);
    9805             : 
    9806           1 :         VERIFY_ERRORS("test.css(1): info: @import uri(/this/shall/not/exist/either/on/your/drive); left alone by the CSS Preprocessor, no matching file found.\n");
    9807             : 
    9808           1 :         std::stringstream out;
    9809           1 :         out << *n;
    9810           1 :         VERIFY_TREES(out.str(),
    9811             : 
    9812             : "LIST\n"
    9813             : "  AT_KEYWORD \"import\" I:0\n"
    9814             : "    URL \"file://this/shall/not/exist/either/on/your/drive\"\n"
    9815             : 
    9816             :             );
    9817             : 
    9818           1 :         CATCH_REQUIRE(c.get_root() == n);
    9819           1 :     }
    9820             : 
    9821             :     // @import with a string that includes a URL
    9822             :     {
    9823           1 :         std::stringstream ss;
    9824           1 :         ss << "@import \"file://this/shall/not/ever/exist/on/your/drive\";";
    9825           3 :         csspp::position pos("test.css");
    9826           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9827             : 
    9828           2 :         csspp::parser p(l);
    9829             : 
    9830           1 :         csspp::node::pointer_t n(p.stylesheet());
    9831             : 
    9832             :         // no errors so far
    9833           1 :         VERIFY_ERRORS("");
    9834             : 
    9835           1 :         csspp::compiler c;
    9836           1 :         c.set_root(n);
    9837           1 :         c.clear_paths();
    9838           1 :         c.add_path(csspp_test::get_script_path());
    9839           1 :         c.add_path(csspp_test::get_version_script_path());
    9840             : 
    9841           1 :         c.compile(true);
    9842             : 
    9843           1 :         VERIFY_ERRORS("test.css(1): info: @import \"/this/shall/not/ever/exist/on/your/drive\"; left alone by the CSS Preprocessor, no matching file found.\n");
    9844             : 
    9845           1 :         std::stringstream out;
    9846           1 :         out << *n;
    9847           1 :         VERIFY_TREES(out.str(),
    9848             : 
    9849             : "LIST\n"
    9850             : "  AT_KEYWORD \"import\" I:0\n"
    9851             : "    STRING \"file://this/shall/not/ever/exist/on/your/drive\"\n"
    9852             : 
    9853             :             );
    9854             : 
    9855           1 :         CATCH_REQUIRE(c.get_root() == n);
    9856           1 :     }
    9857             : 
    9858             :     // @import with a string that includes a URL
    9859             :     {
    9860           1 :         std::stringstream ss;
    9861           1 :         ss << "@import \"include/a/file:///in/the/filename/but/still/a/regular/filename\";";
    9862           3 :         csspp::position pos("test.css");
    9863           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9864             : 
    9865           2 :         csspp::parser p(l);
    9866             : 
    9867           1 :         csspp::node::pointer_t n(p.stylesheet());
    9868             : 
    9869             :         // no errors so far
    9870           1 :         VERIFY_ERRORS("");
    9871             : 
    9872           1 :         csspp::compiler c;
    9873           1 :         c.set_root(n);
    9874           1 :         c.clear_paths();
    9875           1 :         c.add_path(csspp_test::get_script_path());
    9876           1 :         c.add_path(csspp_test::get_version_script_path());
    9877             : 
    9878           1 :         c.compile(true);
    9879             : 
    9880           1 :         VERIFY_ERRORS("test.css(1): info: @import \"include/a/file:///in/the/filename/but/still/a/regular/filename\"; left alone by the CSS Preprocessor, no matching file found.\n");
    9881             : 
    9882           1 :         std::stringstream out;
    9883           1 :         out << *n;
    9884           1 :         VERIFY_TREES(out.str(),
    9885             : 
    9886             : "LIST\n"
    9887             : "  AT_KEYWORD \"import\" I:0\n"
    9888             : "    STRING \"include/a/file:///in/the/filename/but/still/a/regular/filename\"\n"
    9889             : 
    9890             :             );
    9891             : 
    9892           1 :         CATCH_REQUIRE(c.get_root() == n);
    9893           1 :     }
    9894             : 
    9895             :     // @import a script named "" (empty string!)
    9896             :     {
    9897           1 :         std::stringstream ss;
    9898           1 :         ss << "@import \"\";";
    9899           3 :         csspp::position pos("test.css");
    9900           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9901             : 
    9902           2 :         csspp::parser p(l);
    9903             : 
    9904           1 :         csspp::node::pointer_t n(p.stylesheet());
    9905             : 
    9906             :         // no errors so far
    9907           1 :         VERIFY_ERRORS("");
    9908             : 
    9909           1 :         csspp::compiler c;
    9910           1 :         c.set_root(n);
    9911           1 :         c.clear_paths();
    9912           1 :         c.add_path(csspp_test::get_script_path());
    9913           1 :         c.add_path(csspp_test::get_version_script_path());
    9914             : 
    9915           1 :         c.compile(true);
    9916             : 
    9917           1 :         VERIFY_ERRORS("test.css(1): error: @import \"\"; and @import url(); are not valid.\n");
    9918             : 
    9919           1 :         std::stringstream out;
    9920           1 :         out << *n;
    9921           1 :         VERIFY_TREES(out.str(),
    9922             : 
    9923             : "LIST\n"
    9924             : "  AT_KEYWORD \"import\" I:0\n"
    9925             : "    STRING \"\"\n"
    9926             : 
    9927             :             );
    9928             : 
    9929           1 :         CATCH_REQUIRE(c.get_root() == n);
    9930           1 :     }
    9931             : 
    9932             :     // no left over?
    9933           1 :     VERIFY_ERRORS("");
    9934           1 : }
    9935             : 
    9936           1 : CATCH_TEST_CASE("Invalid variable in comment", "[compiler] [conditional] [invalid]")
    9937             : {
    9938             :     // variable is not defined
    9939             :     {
    9940           1 :         std::stringstream ss;
    9941           1 :         ss << "/* @preserve this variable is #{$unknown} */\n";
    9942           3 :         csspp::position pos("test.css");
    9943           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9944             : 
    9945           2 :         csspp::parser p(l);
    9946             : 
    9947           1 :         csspp::node::pointer_t n(p.stylesheet());
    9948             : 
    9949             :         // no errors so far
    9950           1 :         VERIFY_ERRORS("");
    9951             : 
    9952           1 :         csspp::compiler c;
    9953           1 :         c.set_root(n);
    9954           1 :         c.set_date_time_variables(csspp_test::get_now());
    9955           1 :         c.clear_paths();
    9956           1 :         c.add_path(csspp_test::get_script_path());
    9957           1 :         c.add_path(csspp_test::get_version_script_path());
    9958             : 
    9959           1 :         c.compile(false);
    9960             : 
    9961             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9962             : 
    9963           1 :         VERIFY_ERRORS(
    9964             :                 "test.css(1): warning: variable named \"unknown\", used in a comment, is not set.\n"
    9965             :             );
    9966             : 
    9967           1 :         CATCH_REQUIRE(c.get_root() == n);
    9968           1 :     }
    9969             : 
    9970             :     // variable is not defined
    9971             :     {
    9972           1 :         std::stringstream ss;
    9973             :         ss << "$func($arg): { color: $arg + #010101; };\n"
    9974           1 :            << "/* @preserve this variable is #{$func(#030303)} */\n";
    9975           3 :         csspp::position pos("test.css");
    9976           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
    9977             : 
    9978           2 :         csspp::parser p(l);
    9979             : 
    9980           1 :         csspp::node::pointer_t n(p.stylesheet());
    9981             : 
    9982             :         // no errors so far
    9983           1 :         VERIFY_ERRORS("");
    9984             : 
    9985           1 :         csspp::compiler c;
    9986           1 :         c.set_root(n);
    9987           1 :         c.set_date_time_variables(csspp_test::get_now());
    9988           1 :         c.clear_paths();
    9989           1 :         c.add_path(csspp_test::get_script_path());
    9990           1 :         c.add_path(csspp_test::get_version_script_path());
    9991             : 
    9992           1 :         c.compile(false);
    9993             : 
    9994             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
    9995             : 
    9996           1 :         VERIFY_ERRORS(
    9997             :                 "test.css(2): warning: variable named \"func\", is a function which is not supported in a comment.\n"
    9998             :             );
    9999             : 
   10000           1 :         CATCH_REQUIRE(c.get_root() == n);
   10001           1 :     }
   10002             : 
   10003             :     // variable is not defined
   10004             :     {
   10005           1 :         std::stringstream ss;
   10006             :         ss << "$simple_var: { color: #0568FF + #010101; };\n"
   10007           1 :            << "/* @preserve this variable is #{$simple_var(#030303)} */\n";
   10008           3 :         csspp::position pos("test.css");
   10009           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
   10010             : 
   10011           2 :         csspp::parser p(l);
   10012             : 
   10013           1 :         csspp::node::pointer_t n(p.stylesheet());
   10014             : 
   10015             :         // no errors so far
   10016           1 :         VERIFY_ERRORS("");
   10017             : 
   10018           1 :         csspp::compiler c;
   10019           1 :         c.set_root(n);
   10020           1 :         c.set_date_time_variables(csspp_test::get_now());
   10021           1 :         c.clear_paths();
   10022           1 :         c.add_path(csspp_test::get_script_path());
   10023           1 :         c.add_path(csspp_test::get_version_script_path());
   10024             : 
   10025           1 :         c.compile(false);
   10026             : 
   10027             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
   10028             : 
   10029           1 :         VERIFY_ERRORS(
   10030             :                 "test.css(2): warning: variable named \"simple_var\", is not a function, yet you referenced it as such (and functions are not yet supported in comments).\n"
   10031             :             );
   10032             : 
   10033           1 :         CATCH_REQUIRE(c.get_root() == n);
   10034           1 :     }
   10035             : 
   10036             :     // no left over?
   10037           1 :     VERIFY_ERRORS("");
   10038           1 : }
   10039             : 
   10040           1 : CATCH_TEST_CASE("Compile keyframes", "[compiler] [stylesheet] [attribute]")
   10041             : {
   10042             :     {
   10043           1 :         std::stringstream ss;
   10044             :         ss << "/* testing keyframes */"
   10045             :            << "normal { right: 45px; }\n"
   10046             :            << "@keyframes progress-bar-stripes\n"
   10047             :               "{\n"
   10048             :               "  from {\n"
   10049             :               "    background-position: 40px 0;\n"
   10050             :               "    left: 0;\n"
   10051             :               "  }\n"
   10052             :               "  30% {\n"
   10053             :               "    background-position: 30px 0;\n"
   10054             :               "    left: 20px;\n"
   10055             :               "  }\n"
   10056             :               "  60% {\n"
   10057             :               "    background-position: 5px 0;\n"
   10058             :               "    left: 27px;\n"
   10059             :               "  }\n"
   10060             :               "  to {\n"
   10061             :               "    background-position: 0 0;\n"
   10062             :               "    left: 35px;\n"
   10063             :               "  }\n"
   10064             :               "}\n"
   10065           1 :            << "/* @preserver test \"Compile keyframes\" */";
   10066           3 :         csspp::position pos("test.css");
   10067           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
   10068             : 
   10069           2 :         csspp::parser p(l);
   10070             : 
   10071           1 :         csspp::node::pointer_t n(p.stylesheet());
   10072             : 
   10073             :         // no errors so far
   10074           1 :         VERIFY_ERRORS("");
   10075             : 
   10076           1 :         csspp::compiler c;
   10077           1 :         c.set_root(n);
   10078           1 :         c.set_date_time_variables(csspp_test::get_now());
   10079           1 :         c.clear_paths();
   10080           1 :         c.add_path(csspp_test::get_script_path());
   10081           1 :         c.add_path(csspp_test::get_version_script_path());
   10082             : 
   10083           1 :         c.compile(false);
   10084             : 
   10085             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
   10086             : 
   10087           1 :         std::stringstream out;
   10088           1 :         out << *n;
   10089           1 :         VERIFY_TREES(out.str(),
   10090             : 
   10091             : "LIST\n"
   10092             : + csspp_test::get_default_variables() +
   10093             : "  COMPONENT_VALUE\n"
   10094             : "    ARG\n"
   10095             : "      IDENTIFIER \"normal\"\n"
   10096             : "    OPEN_CURLYBRACKET B:true\n"
   10097             : "      DECLARATION \"right\"\n"
   10098             : "        ARG\n"
   10099             : "          INTEGER \"px\" I:45\n"
   10100             : "  AT_KEYWORD \"keyframes\" I:0\n"
   10101             : "    IDENTIFIER \"progress-bar-stripes\"\n"
   10102             : "    FRAME D:0\n"
   10103             : "      DECLARATION \"background-position\"\n"
   10104             : "        ARG\n"
   10105             : "          INTEGER \"px\" I:40\n"
   10106             : "          WHITESPACE\n"
   10107             : "          INTEGER \"\" I:0\n"
   10108             : "      DECLARATION \"left\"\n"
   10109             : "        ARG\n"
   10110             : "          INTEGER \"\" I:0\n"
   10111             : "    FRAME D:0.3\n"
   10112             : "      DECLARATION \"background-position\"\n"
   10113             : "        ARG\n"
   10114             : "          INTEGER \"px\" I:30\n"
   10115             : "          WHITESPACE\n"
   10116             : "          INTEGER \"\" I:0\n"
   10117             : "      DECLARATION \"left\"\n"
   10118             : "        ARG\n"
   10119             : "          INTEGER \"px\" I:20\n"
   10120             : "    FRAME D:0.6\n"
   10121             : "      DECLARATION \"background-position\"\n"
   10122             : "        ARG\n"
   10123             : "          INTEGER \"px\" I:5\n"
   10124             : "          WHITESPACE\n"
   10125             : "          INTEGER \"\" I:0\n"
   10126             : "      DECLARATION \"left\"\n"
   10127             : "        ARG\n"
   10128             : "          INTEGER \"px\" I:27\n"
   10129             : "    FRAME D:1\n"
   10130             : "      DECLARATION \"background-position\"\n"
   10131             : "        ARG\n"
   10132             : "          INTEGER \"\" I:0\n"
   10133             : "          WHITESPACE\n"
   10134             : "          INTEGER \"\" I:0\n"
   10135             : "      DECLARATION \"left\"\n"
   10136             : "        ARG\n"
   10137             : "          INTEGER \"px\" I:35\n"
   10138             : "  COMMENT \"@preserver test \"Compile keyframes\"\" I:1\n"
   10139             : + csspp_test::get_close_comment(true)
   10140             : 
   10141             :             );
   10142             : 
   10143             :         // no error left over
   10144           1 :         VERIFY_ERRORS("");
   10145             : 
   10146           1 :         CATCH_REQUIRE(c.get_root() == n);
   10147           1 :     }
   10148             : 
   10149             :     // without spaces
   10150             :     {
   10151           1 :         std::stringstream ss;
   10152             :         ss << "/* testing compile */"
   10153             :            << "body,a[q]>b[p=\"344.5\"]+c[z=33]~d[e],html *[ff=fire] *.blue { background:white url(/images/background.png) }"
   10154           1 :            << "/* @preserver test \"Compile Simple Stylesheet\" with version #{$_csspp_major}.#{$_csspp_minor} */";
   10155           3 :         csspp::position pos("test.css");
   10156           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
   10157             : 
   10158           2 :         csspp::parser p(l);
   10159             : 
   10160           1 :         csspp::node::pointer_t n(p.stylesheet());
   10161             : 
   10162             :         // no errors so far
   10163           1 :         VERIFY_ERRORS("");
   10164             : 
   10165           1 :         csspp::compiler c;
   10166           1 :         c.set_root(n);
   10167           1 :         c.set_date_time_variables(csspp_test::get_now());
   10168           1 :         c.clear_paths();
   10169           1 :         c.add_path(csspp_test::get_script_path());
   10170           1 :         c.add_path(csspp_test::get_version_script_path());
   10171             : 
   10172           1 :         c.compile(false);
   10173             : 
   10174             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
   10175             : 
   10176           1 :         std::stringstream out;
   10177           1 :         out << *n;
   10178           1 :         VERIFY_TREES(out.str(),
   10179             : 
   10180             : "LIST\n"
   10181             : + csspp_test::get_default_variables() +
   10182             : "  COMPONENT_VALUE\n"
   10183             : "    ARG\n"
   10184             : "      IDENTIFIER \"body\"\n"
   10185             : "    ARG\n"
   10186             : "      IDENTIFIER \"a\"\n"
   10187             : "      OPEN_SQUAREBRACKET\n"
   10188             : "        IDENTIFIER \"q\"\n"
   10189             : "      GREATER_THAN\n"
   10190             : "      IDENTIFIER \"b\"\n"
   10191             : "      OPEN_SQUAREBRACKET\n"
   10192             : "        IDENTIFIER \"p\"\n"
   10193             : "        EQUAL\n"
   10194             : "        STRING \"344.5\"\n"
   10195             : "      ADD\n"
   10196             : "      IDENTIFIER \"c\"\n"
   10197             : "      OPEN_SQUAREBRACKET\n"
   10198             : "        IDENTIFIER \"z\"\n"
   10199             : "        EQUAL\n"
   10200             : "        INTEGER \"\" I:33\n"
   10201             : "      PRECEDED\n"
   10202             : "      IDENTIFIER \"d\"\n"
   10203             : "      OPEN_SQUAREBRACKET\n"
   10204             : "        IDENTIFIER \"e\"\n"
   10205             : "    ARG\n"
   10206             : "      IDENTIFIER \"html\"\n"
   10207             : "      WHITESPACE\n"
   10208             : "      OPEN_SQUAREBRACKET\n"
   10209             : "        IDENTIFIER \"ff\"\n"
   10210             : "        EQUAL\n"
   10211             : "        IDENTIFIER \"fire\"\n"
   10212             : "      WHITESPACE\n"
   10213             : "      PERIOD\n"
   10214             : "      IDENTIFIER \"blue\"\n"
   10215             : "    OPEN_CURLYBRACKET B:true\n"
   10216             : "      DECLARATION \"background\"\n"
   10217             : "        ARG\n"
   10218             : "          COLOR H:ffffffff\n"
   10219             : "          WHITESPACE\n"
   10220             : "          URL \"/images/background.png\"\n"
   10221             : "  COMMENT \"@preserver test \"Compile Simple Stylesheet\" with version 1.0\" I:1\n"
   10222             : + csspp_test::get_close_comment(true)
   10223             : 
   10224             :             );
   10225             : 
   10226             :         // no error left over
   10227           1 :         VERIFY_ERRORS("");
   10228             : 
   10229           1 :         CATCH_REQUIRE(c.get_root() == n);
   10230           1 :     }
   10231             : 
   10232             :     // rules with !important
   10233             :     {
   10234           1 :         std::stringstream ss;
   10235           1 :         ss << "div.blackness { color: red !important }";
   10236           3 :         csspp::position pos("test.css");
   10237           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
   10238             : 
   10239           2 :         csspp::parser p(l);
   10240             : 
   10241           1 :         csspp::node::pointer_t n(p.stylesheet());
   10242             : 
   10243             :         // no errors so far
   10244           1 :         VERIFY_ERRORS("");
   10245             : 
   10246           1 :         csspp::compiler c;
   10247           1 :         c.set_root(n);
   10248           1 :         c.set_date_time_variables(csspp_test::get_now());
   10249           1 :         c.clear_paths();
   10250           1 :         c.add_path(csspp_test::get_script_path());
   10251           1 :         c.add_path(csspp_test::get_version_script_path());
   10252             : 
   10253           1 :         c.compile(false);
   10254             : 
   10255             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
   10256             : 
   10257           1 :         std::stringstream out;
   10258           1 :         out << *n;
   10259           1 :         VERIFY_TREES(out.str(),
   10260             : 
   10261             : "LIST\n"
   10262             : + csspp_test::get_default_variables() +
   10263             : "  COMPONENT_VALUE\n"
   10264             : "    ARG\n"
   10265             : "      IDENTIFIER \"div\"\n"
   10266             : "      PERIOD\n"
   10267             : "      IDENTIFIER \"blackness\"\n"
   10268             : "    OPEN_CURLYBRACKET B:true\n"
   10269             : "      DECLARATION \"color\" F:important\n"
   10270             : "        ARG\n"
   10271             : "          COLOR H:ff0000ff\n"
   10272             : + csspp_test::get_close_comment(true)
   10273             : 
   10274             :             );
   10275             : 
   10276             :         // no error left over
   10277           1 :         VERIFY_ERRORS("");
   10278             : 
   10279           1 :         CATCH_REQUIRE(c.get_root() == n);
   10280           1 :     }
   10281             : 
   10282             :     // rules with ! important
   10283             :     {
   10284           1 :         std::stringstream ss;
   10285           1 :         ss << "div.blackness { color: red ! important }";
   10286           3 :         csspp::position pos("test.css");
   10287           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
   10288             : 
   10289           2 :         csspp::parser p(l);
   10290             : 
   10291           1 :         csspp::node::pointer_t n(p.stylesheet());
   10292             : 
   10293             :         // no errors so far
   10294           1 :         VERIFY_ERRORS("");
   10295             : 
   10296           1 :         csspp::compiler c;
   10297           1 :         c.set_root(n);
   10298           1 :         c.set_date_time_variables(csspp_test::get_now());
   10299           1 :         c.clear_paths();
   10300           1 :         c.add_path(csspp_test::get_script_path());
   10301           1 :         c.add_path(csspp_test::get_version_script_path());
   10302             : 
   10303           1 :         c.compile(false);
   10304             : 
   10305             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
   10306             : 
   10307           1 :         std::stringstream out;
   10308           1 :         out << *n;
   10309           1 :         VERIFY_TREES(out.str(),
   10310             : 
   10311             : "LIST\n"
   10312             : + csspp_test::get_default_variables() +
   10313             : "  COMPONENT_VALUE\n"
   10314             : "    ARG\n"
   10315             : "      IDENTIFIER \"div\"\n"
   10316             : "      PERIOD\n"
   10317             : "      IDENTIFIER \"blackness\"\n"
   10318             : "    OPEN_CURLYBRACKET B:true\n"
   10319             : "      DECLARATION \"color\" F:important\n"
   10320             : "        ARG\n"
   10321             : "          COLOR H:ff0000ff\n"
   10322             : + csspp_test::get_close_comment(true)
   10323             : 
   10324             :             );
   10325             : 
   10326             :         // no error left over
   10327           1 :         VERIFY_ERRORS("");
   10328             : 
   10329           1 :         CATCH_REQUIRE(c.get_root() == n);
   10330           1 :     }
   10331             : 
   10332             :     // rules with !important and no spaces
   10333             :     {
   10334           1 :         std::stringstream ss;
   10335           1 :         ss << "div.blackness { color: red!important }";
   10336           3 :         csspp::position pos("test.css");
   10337           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
   10338             : 
   10339           2 :         csspp::parser p(l);
   10340             : 
   10341           1 :         csspp::node::pointer_t n(p.stylesheet());
   10342             : 
   10343             :         // no errors so far
   10344           1 :         VERIFY_ERRORS("");
   10345             : 
   10346           1 :         csspp::compiler c;
   10347           1 :         c.set_root(n);
   10348           1 :         c.set_date_time_variables(csspp_test::get_now());
   10349           1 :         c.clear_paths();
   10350           1 :         c.add_path(csspp_test::get_script_path());
   10351           1 :         c.add_path(csspp_test::get_version_script_path());
   10352             : 
   10353           1 :         c.compile(false);
   10354             : 
   10355             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
   10356             : 
   10357           1 :         std::stringstream out;
   10358           1 :         out << *n;
   10359           1 :         VERIFY_TREES(out.str(),
   10360             : 
   10361             : "LIST\n"
   10362             : + csspp_test::get_default_variables() +
   10363             : "  COMPONENT_VALUE\n"
   10364             : "    ARG\n"
   10365             : "      IDENTIFIER \"div\"\n"
   10366             : "      PERIOD\n"
   10367             : "      IDENTIFIER \"blackness\"\n"
   10368             : "    OPEN_CURLYBRACKET B:true\n"
   10369             : "      DECLARATION \"color\" F:important\n"
   10370             : "        ARG\n"
   10371             : "          COLOR H:ff0000ff\n"
   10372             : + csspp_test::get_close_comment(true)
   10373             : 
   10374             :             );
   10375             : 
   10376             :         // no error left over
   10377           1 :         VERIFY_ERRORS("");
   10378             : 
   10379           1 :         CATCH_REQUIRE(c.get_root() == n);
   10380           1 :     }
   10381             : 
   10382             :     // empty rules have to compile too
   10383             :     {
   10384           1 :         std::stringstream ss;
   10385             :         ss << "div.blackness section.light span.clear\n"
   10386             :            << "{\n"
   10387           1 :            << "}\n";
   10388           3 :         csspp::position pos("test.css");
   10389           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
   10390             : 
   10391           2 :         csspp::parser p(l);
   10392             : 
   10393           1 :         csspp::node::pointer_t n(p.stylesheet());
   10394             : 
   10395             :         // no errors so far
   10396           1 :         VERIFY_ERRORS("");
   10397             : 
   10398           1 :         csspp::compiler c;
   10399           1 :         c.set_root(n);
   10400           1 :         c.set_date_time_variables(csspp_test::get_now());
   10401           1 :         c.clear_paths();
   10402           1 :         c.add_path(csspp_test::get_script_path());
   10403           1 :         c.add_path(csspp_test::get_version_script_path());
   10404             : 
   10405           1 :         c.compile(false);
   10406             : 
   10407             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
   10408             : 
   10409           1 :         std::stringstream out;
   10410           1 :         out << *n;
   10411           1 :         VERIFY_TREES(out.str(),
   10412             : 
   10413             : "LIST\n"
   10414             : + csspp_test::get_default_variables()
   10415             : + csspp_test::get_close_comment(true)
   10416             : 
   10417             :             );
   10418             : 
   10419             :         // no error left over
   10420           1 :         VERIFY_ERRORS("");
   10421             : 
   10422           1 :         CATCH_REQUIRE(c.get_root() == n);
   10423           1 :     }
   10424             : 
   10425             :     // special IE8 value which has to be skipped
   10426             :     {
   10427           1 :         std::stringstream ss;
   10428             :         ss << ".transparent img\n"
   10429             :            << "{\n"
   10430             :            << "  $alpha: 5% * 4;\n"
   10431             :            << "  filter: opacity($alpha);\n"
   10432             :            << "  filter: alpha( opacity=20 );\n"
   10433           1 :            << "}\n";
   10434           3 :         csspp::position pos("test.css");
   10435           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
   10436             : 
   10437           2 :         csspp::parser p(l);
   10438             : 
   10439           1 :         csspp::node::pointer_t n(p.stylesheet());
   10440             : 
   10441             :         // no errors so far
   10442           1 :         VERIFY_ERRORS("");
   10443             : 
   10444           1 :         csspp::compiler c;
   10445           1 :         c.set_root(n);
   10446           1 :         c.set_date_time_variables(csspp_test::get_now());
   10447           1 :         c.clear_paths();
   10448           1 :         c.add_path(csspp_test::get_script_path());
   10449           1 :         c.add_path(csspp_test::get_version_script_path());
   10450             : 
   10451           1 :         c.compile(false);
   10452             : 
   10453             :         // no error left over
   10454           1 :         VERIFY_ERRORS(
   10455             :                 "test.css(4): warning: the alpha(), chroma() and similar functions of the filter field are Internet Explorer specific extensions which are not supported across browsers.\n"
   10456             :                 "test.css(5): warning: the alpha(), chroma() and similar functions of the filter field are Internet Explorer specific extensions which are not supported across browsers.\n"
   10457             :             );
   10458             : 
   10459             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
   10460             : 
   10461           1 :         std::stringstream out;
   10462           1 :         out << *n;
   10463           1 :         VERIFY_TREES(out.str(),
   10464             : 
   10465             : "LIST\n"
   10466             : + csspp_test::get_default_variables() +
   10467             : "  COMPONENT_VALUE\n"
   10468             : "    ARG\n"
   10469             : "      PERIOD\n"
   10470             : "      IDENTIFIER \"transparent\"\n"
   10471             : "      WHITESPACE\n"
   10472             : "      IDENTIFIER \"img\"\n"
   10473             : "    OPEN_CURLYBRACKET B:true\n"
   10474             : "        V:alpha\n"
   10475             : "          LIST\n"
   10476             : "            VARIABLE \"alpha\"\n"
   10477             : "            LIST\n"
   10478             : "              PERCENT D:0.05\n"
   10479             : "              WHITESPACE\n"
   10480             : "              MULTIPLY\n"
   10481             : "              WHITESPACE\n"
   10482             : "              INTEGER \"\" I:4\n"
   10483             : "      LIST\n"
   10484             : "        DECLARATION \"filter\"\n"
   10485             : "          FUNCTION \"opacity\"\n"
   10486             : "            PERCENT D:0.05\n"
   10487             : "            WHITESPACE\n"
   10488             : "            MULTIPLY\n"
   10489             : "            WHITESPACE\n"
   10490             : "            INTEGER \"\" I:4\n"
   10491             : "        DECLARATION \"filter\"\n"
   10492             : "          FUNCTION \"alpha\"\n"
   10493             : "            IDENTIFIER \"opacity\"\n"
   10494             : "            EQUAL\n"
   10495             : "            INTEGER \"\" I:20\n"
   10496             : + csspp_test::get_close_comment(true)
   10497             : 
   10498             :             );
   10499             : 
   10500             :         // no error left over
   10501           1 :         VERIFY_ERRORS("");
   10502             : 
   10503           1 :         CATCH_REQUIRE(c.get_root() == n);
   10504           1 :     }
   10505             : 
   10506             :     // a simple test with '--no-logo' specified
   10507             :     {
   10508           1 :         std::stringstream ss;
   10509             :         ss << ".box\n"
   10510             :            << "{\n"
   10511             :            << "  color: $_csspp_no_logo ? red : blue;\n"
   10512           1 :            << "}\n";
   10513           3 :         csspp::position pos("test.css");
   10514           1 :         csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
   10515             : 
   10516           2 :         csspp::parser p(l);
   10517             : 
   10518           1 :         csspp::node::pointer_t n(p.stylesheet());
   10519             : 
   10520             :         // no errors so far
   10521           1 :         VERIFY_ERRORS("");
   10522             : 
   10523           1 :         csspp::compiler c;
   10524           1 :         c.set_root(n);
   10525           1 :         c.set_date_time_variables(csspp_test::get_now());
   10526           1 :         c.set_no_logo();
   10527           1 :         c.clear_paths();
   10528           1 :         c.add_path(csspp_test::get_script_path());
   10529           1 :         c.add_path(csspp_test::get_version_script_path());
   10530             : 
   10531           1 :         c.compile(false);
   10532             : 
   10533             : //std::cerr << "Result is: [" << *c.get_root() << "]\n";
   10534             : 
   10535             :         // no error left over
   10536           1 :         VERIFY_ERRORS("");
   10537             : 
   10538           1 :         std::stringstream out;
   10539           1 :         out << *n;
   10540           1 :         VERIFY_TREES(out.str(),
   10541             : 
   10542             : "LIST\n"
   10543             : + csspp_test::get_default_variables(csspp_test::flag_no_logo_true) +
   10544             : "  COMPONENT_VALUE\n"
   10545             : "    ARG\n"
   10546             : "      PERIOD\n"
   10547             : "      IDENTIFIER \"box\"\n"
   10548             : "    OPEN_CURLYBRACKET B:true\n"
   10549             : "      DECLARATION \"color\"\n"
   10550             : "        ARG\n"
   10551             : "          COLOR H:ff0000ff\n"
   10552             : //+ csspp_test::get_close_comment(true) -- with --no-logo this is gone
   10553             : 
   10554             :             );
   10555             : 
   10556             :         // no error left over
   10557           1 :         VERIFY_ERRORS("");
   10558             : 
   10559           1 :         CATCH_REQUIRE(c.get_root() == n);
   10560           1 :     }
   10561           1 : }
   10562             : 
   10563             : // This does not work under Linux, the ifstream.open() accepts a
   10564             : // directory name as input without generating an error
   10565             : //
   10566             : //CATCH_TEST_CASE("Cannot open file", "[compiler] [invalid] [input]")
   10567             : //{
   10568             : //    // generate an error with @error
   10569             : //    {
   10570             : //        // create a directory in place of the script, so it exists
   10571             : //        // and is readable but cannot be opened
   10572             : //        rmdir("pseudo-nth-functions.scss"); // in case you run more than once
   10573             : //        CATCH_REQUIRE(mkdir("pseudo-nth-functions.scss", 0700) == 0);
   10574             : //
   10575             : //        std::stringstream ss;
   10576             : //        ss << "div:nth-child(3n+2){font-style:normal}";
   10577             : //        csspp::position pos("test.css");
   10578             : //        csspp::lexer::pointer_t l(new csspp::lexer(ss, pos));
   10579             : //
   10580             : //        csspp::parser p(l);
   10581             : //
   10582             : //        csspp::node::pointer_t n(p.stylesheet());
   10583             : //
   10584             : //        // no errors so far
   10585             : //        VERIFY_ERRORS("");
   10586             : //
   10587             : //        csspp::compiler c;
   10588             : //        c.set_root(n);
   10589             : //        c.clear_paths();
   10590             : //        c.add_path(".");
   10591             : //
   10592             : //        CATCH_REQUIRE_THROWS_AS(c.compile(true), csspp::csspp_exception_exit);
   10593             : //
   10594             : //        // TODO: use an RAII class instead
   10595             : //        rmdir("pseudo-nth-functions.scss"); // in case you run more than once
   10596             : //
   10597             : //        VERIFY_ERRORS("pseudo-nth-functions(1): fatal: validation script \"pseudo-nth-functions\" was not found.\n");
   10598             : //
   10599             : //        CATCH_REQUIRE(c.get_root() == n);
   10600             : //    }
   10601             : //
   10602             : //    // no left over?
   10603             : //    VERIFY_ERRORS("");
   10604             : //}
   10605             : 
   10606             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14