CssSelectorTest.C 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #include <boost/test/unit_test.hpp>
  2. #include <boost/assign/list_of.hpp>
  3. #include <Wt/Render/Block.h>
  4. #include <Wt/Render/CssParser.h>
  5. #include <iostream>
  6. #include "3rdparty/rapidxml/rapidxml.hpp"
  7. using namespace boost::assign;
  8. using namespace Wt::Render;
  9. #include <boost/version.hpp>
  10. #if !defined(WT_NO_SPIRIT) && BOOST_VERSION >= 104700
  11. # define CSS_PARSER
  12. #endif
  13. #ifdef CSS_PARSER
  14. const Wt::Render::Block* childBlock(const Wt::Render::Block* parent,
  15. const std::vector<int>& indexes)
  16. {
  17. const Wt::Render::Block* block = parent;
  18. for(std::vector<int>::const_iterator iter = indexes.begin();
  19. iter != indexes.end(); ++iter)
  20. {
  21. block = block->children().at(*iter);
  22. }
  23. return block;
  24. }
  25. Wt::rapidxml::xml_document<>* createXHtml(const char *xhtml)
  26. {
  27. Wt::rapidxml::xml_document<>* doc = new Wt::rapidxml::xml_document<>();
  28. char *cxhtml = doc->allocate_string(xhtml);
  29. doc->parse<Wt::rapidxml::parse_xhtml_entity_translation>(cxhtml);
  30. return doc;
  31. }
  32. BOOST_AUTO_TEST_CASE( CssSelector_test1 )
  33. {
  34. Wt::rapidxml::xml_document<>* doc = createXHtml(
  35. "<ul><li></li></ul><li><h1><h2><h1></h1></h2></h1></li>");
  36. Wt::Render::StyleSheet* style = Wt::Render::CssParser().parse(
  37. "ul{} ul li{} li{} ul h1{} h1 h1{} li h1 h1{}");
  38. BOOST_REQUIRE( style );
  39. Wt::Render::Block b(doc, 0);
  40. // PASS ul to "ul"
  41. BOOST_REQUIRE(Match::isMatch(childBlock(&b, list_of(0)),
  42. style->rulesetAt(0).selector() ).isValid() );
  43. // PASS ul/li to "ul li"
  44. BOOST_REQUIRE(Match::isMatch(childBlock(&b, list_of(0)(0)),
  45. style->rulesetAt(1).selector() ).isValid() );
  46. // PASS ul/li to "li"
  47. BOOST_REQUIRE(Match::isMatch(childBlock(&b, list_of(0)(0)),
  48. style->rulesetAt(2).selector() ).isValid() );
  49. // FAIL li to "ul li"
  50. BOOST_REQUIRE(!Match::isMatch(childBlock(&b, list_of(1)),
  51. style->rulesetAt(1).selector() ).isValid() );
  52. // FAIL li/h1/h2/h1 to "ul h1"
  53. BOOST_REQUIRE(!Match::isMatch(childBlock(&b, list_of(1)(0)(0)(0)),
  54. style->rulesetAt(3).selector() ).isValid() );
  55. // PASS li/h1/h2/h1 to "li h1 h1"
  56. BOOST_REQUIRE(Match::isMatch(childBlock(&b, list_of(1)(0)(0)(0)),
  57. style->rulesetAt(5).selector() ).isValid() );
  58. // PASS li/h1/h2/h1 to "h1 h1"
  59. BOOST_REQUIRE(Match::isMatch(childBlock(&b, list_of(1)(0)(0)(0)),
  60. style->rulesetAt(4).selector() ).isValid() );
  61. delete style;
  62. delete doc;
  63. }
  64. BOOST_AUTO_TEST_CASE( CssSelector_test2 )
  65. {
  66. Wt::rapidxml::xml_document<>* doc = createXHtml(
  67. "<h1><h2 id=\"two\"><h3><h4 id=\"four\"></h4></h3></h2></h1>");
  68. Wt::Render::StyleSheet* style = Wt::Render::CssParser().parse(
  69. "#two #four{} #two h4#four{} #two h3#four{}");
  70. BOOST_REQUIRE( style );
  71. Wt::Render::Block b(doc, 0);
  72. // PASS h1/h2/h3/h4 to "#two #four"
  73. BOOST_REQUIRE(Match::isMatch(childBlock(&b, list_of(0)(0)(0)(0)),
  74. style->rulesetAt(0).selector() ).isValid() );
  75. // PASS h1/h2/h3/h4 to "#two h4#four"
  76. BOOST_REQUIRE(Match::isMatch(childBlock(&b, list_of(0)(0)(0)(0)),
  77. style->rulesetAt(1).selector() ).isValid() );
  78. // FAIL h1/h2/h3/h4 to "#two h3#four"
  79. BOOST_REQUIRE(!Match::isMatch(childBlock(&b, list_of(0)(0)(0)(0)),
  80. style->rulesetAt(2).selector() ).isValid() );
  81. // FAIL h1/h2/h3 to "#two h3#four"
  82. BOOST_REQUIRE(!Match::isMatch(childBlock(&b, list_of(0)(0)(0)),
  83. style->rulesetAt(2).selector() ).isValid() );
  84. delete style;
  85. delete doc;
  86. }
  87. BOOST_AUTO_TEST_CASE( CssSelector_test3 )
  88. {
  89. Wt::rapidxml::xml_document<>* doc = createXHtml(
  90. "<h1><h2 class=\"b\"><h3 class=\"c e\"><h4 class=\"d\"></h4></h3></h2></h1>");
  91. Wt::Render::StyleSheet* style = Wt::Render::CssParser().parse(
  92. ".b .d{} .b h4.d{} .b h3.d{} .b .c.e .d{}");
  93. BOOST_REQUIRE( style );
  94. Wt::Render::Block b(doc, 0);
  95. // PASS h1/h2/h3/h4 to ".b .d"
  96. BOOST_REQUIRE(Match::isMatch(childBlock(&b, list_of(0)(0)(0)(0)),
  97. style->rulesetAt(0).selector() ).isValid() );
  98. // PASS h1/h2/h3/h4 to ".b h4.d"
  99. BOOST_REQUIRE(Match::isMatch(childBlock(&b, list_of(0)(0)(0)(0)),
  100. style->rulesetAt(1).selector() ).isValid() );
  101. // FAIL h1/h2/h3/h4 to ".b h3.d"
  102. BOOST_REQUIRE(!Match::isMatch(childBlock(&b, list_of(0)(0)(0)(0)),
  103. style->rulesetAt(2).selector() ).isValid() );
  104. // FAIL h1/h2/h3 to ".b h3.d"
  105. BOOST_REQUIRE(!Match::isMatch(childBlock(&b, list_of(0)(0)(0)),
  106. style->rulesetAt(2).selector() ).isValid() );
  107. // PASS h1/h2/h3/h4 to ".b .c.e .d"
  108. BOOST_REQUIRE(Match::isMatch(childBlock(&b, list_of(0)(0)(0)(0)),
  109. style->rulesetAt(3).selector() ).isValid() );
  110. delete style;
  111. delete doc;
  112. }
  113. BOOST_AUTO_TEST_CASE( CssSelector_test4 )
  114. {
  115. Wt::rapidxml::xml_document<>* doc = createXHtml(
  116. "<h1 class=\"a1 a2\" id=\"one\"><h2><h3 class=\"c\" id=\"two\"></h3></h2></h1>"
  117. );
  118. Wt::Render::StyleSheet* style = Wt::Render::CssParser().parse(
  119. "h1.a1#one.a2 * h3#two.c{}");
  120. BOOST_REQUIRE( style );
  121. Wt::Render::Block b(doc, 0);
  122. // PASS h1/h2/h3 to "h1.a1#one.a2 * h3#two.c{}"
  123. BOOST_REQUIRE( Match::isMatch(childBlock(&b, list_of(0)(0)(0)),
  124. style->rulesetAt(0).selector() ).isValid() );
  125. delete style;
  126. delete doc;
  127. }
  128. BOOST_AUTO_TEST_CASE( CssSelector_testSpecificity )
  129. {
  130. Wt::Render::StyleSheet* style = Wt::Render::CssParser().parse(
  131. "h1, *, h1.a1#one.a2 * h3#two.c h4 h5{}");
  132. BOOST_REQUIRE( style );
  133. BOOST_REQUIRE( style->rulesetAt(0).selector().specificity()
  134. == Wt::Render::Specificity(0,0,0,1) );
  135. BOOST_REQUIRE( style->rulesetAt(1).selector().specificity()
  136. == Wt::Render::Specificity(0,0,0,0) );
  137. BOOST_REQUIRE( style->rulesetAt(2).selector().specificity()
  138. == Wt::Render::Specificity(0,2,3,4) );
  139. delete style;
  140. }
  141. BOOST_AUTO_TEST_CASE( CssSelector_test5 )
  142. {
  143. Wt::rapidxml::xml_document<>* doc = createXHtml(
  144. "<h1><h1><h1></h1></h1></h1>");
  145. Wt::Render::StyleSheet* style = Wt::Render::CssParser().parse(
  146. "h1 h1 h1{}");
  147. BOOST_REQUIRE( style );
  148. Wt::Render::Block b(doc, 0);
  149. // Sanity check, match h1/h1/h1 to "h1 h1 h1"
  150. BOOST_REQUIRE( Match::isMatch(childBlock(&b, list_of(0)(0)(0)),
  151. style->rulesetAt(0).selector() ).isValid() );
  152. // FAIL h1/h1 to "h1 h1 h1"
  153. BOOST_REQUIRE( !Match::isMatch(childBlock(&b, list_of(0)(0)),
  154. style->rulesetAt(0).selector() ).isValid() );
  155. delete style;
  156. delete doc;
  157. }
  158. #endif // CSS_PARSER