/* Ousía Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include namespace ousia { namespace parser { namespace css { TEST(CSSParser, testParseSelectors) { // create a string describing a SelectorTree std::string data{"A>B,A B:r, C#a A[bla=\"blub\"], A::g(4,2,3)"}; /* This should describe the tree: * root_____ * | \ \ * A C#a A::g(4,2,3) * |\ \ * B B::r A[bla="blub"] */ // initialize an empty parser context. StandaloneParserContext ctx; // parse the data. CSSParser instance; Rooted root = instance.parse(data, ctx).cast(); // we expect three children of the root node overall. ASSERT_EQ(3, root->getEdges().size()); // get all "A" children, which should be two. std::vector> children = root->getChildren("A"); ASSERT_EQ(2, children.size()); // assert A Rooted A = children[0]; ASSERT_EQ("A", A->getName()); { PseudoSelector select{"true", false}; ASSERT_EQ(select, A->getPseudoSelector()); } ASSERT_EQ(2, A->getEdges().size()); ASSERT_FALSE(A->isAccepting()); ASSERT_EQ(0, A->getRuleSet()->getRules().size()); { // assert A > B std::vector> Achildren = A->getChildren(SelectionOperator::DIRECT_DESCENDANT, "B"); ASSERT_EQ(1, Achildren.size()); Rooted B = Achildren[0]; ASSERT_EQ("B", B->getName()); { PseudoSelector select{"true", false}; ASSERT_EQ(select, B->getPseudoSelector()); } ASSERT_EQ(0, B->getEdges().size()); ASSERT_TRUE(B->isAccepting()); ASSERT_EQ(0, B->getRuleSet()->getRules().size()); // assert A B:r Achildren = A->getChildren(SelectionOperator::DESCENDANT, "B"); ASSERT_EQ(1, Achildren.size()); Rooted Br = Achildren[0]; ASSERT_EQ("B", Br->getName()); { PseudoSelector select{"r", false}; ASSERT_EQ(select, Br->getPseudoSelector()); } ASSERT_EQ(0, Br->getEdges().size()); ASSERT_TRUE(Br->isAccepting()); ASSERT_EQ(0, Br->getRuleSet()->getRules().size()); } // assert C#a children = root->getChildren("C"); ASSERT_EQ(1, children.size()); Rooted C = children[0]; ASSERT_EQ("C", C->getName()); { PseudoSelector select{"has_id", {"a"}, false}; ASSERT_EQ(select, C->getPseudoSelector()); } ASSERT_EQ(1, C->getEdges().size()); ASSERT_FALSE(C->isAccepting()); ASSERT_EQ(0, C->getRuleSet()->getRules().size()); { // assert C#a A[bla=\"blub\"] std::vector> Cchildren = C->getChildren(SelectionOperator::DESCENDANT, "A"); ASSERT_EQ(1, Cchildren.size()); Rooted A = Cchildren[0]; ASSERT_EQ("A", A->getName()); { PseudoSelector select{"has_value", {"bla", "blub"}, false}; ASSERT_EQ(select, A->getPseudoSelector()); } ASSERT_EQ(0, A->getEdges().size()); ASSERT_TRUE(A->isAccepting()); ASSERT_EQ(0, A->getRuleSet()->getRules().size()); } // assert A::g(4,2,3) children = root->getChildren("A"); ASSERT_EQ(2, children.size()); Rooted Ag = children[1]; ASSERT_EQ("A", Ag->getName()); { PseudoSelector select{"g", {Variant(4), Variant(2), Variant(3)}, true}; ASSERT_EQ(select, Ag->getPseudoSelector()); } ASSERT_EQ(0, Ag->getEdges().size()); ASSERT_TRUE(Ag->isAccepting()); ASSERT_EQ(0, Ag->getRuleSet()->getRules().size()); } TEST(CSSParser, testParseCSS) { // create the CSS input std::stringstream input; input << "A, B A {\n"; input << "/*\n"; input << " * Some multiline\n"; input << " * comment\n"; input << " */\n"; input << "\t ident1 : \"val1\";\n"; input << "\t ident2 : \"val2\";\n"; input << "}\n"; input << "A:select(a,b) {\n"; input << "\t ident3 : \"val3\";\n"; input << "}\n"; input << "A {\n"; input << "\t ident1 : \"val4\";\n"; input << "}\n"; // initialize an empty parser context. StandaloneParserContext ctx; // parse the input. CSSParser instance; CharReader reader{input}; Rooted root = instance.parse(reader, ctx).cast(); // we expect three children of the root node overall. ASSERT_EQ(3, root->getEdges().size()); // get all "A" children, which should be two. std::vector> children = root->getChildren("A"); ASSERT_EQ(2, children.size()); // assert A /* * A { * ident1 : "val1"; * ident2 : "val2"; * } * * and * * A { * ident1 : "val4"; * } * * should be merged. */ Rooted A = children[0]; ASSERT_EQ("A", A->getName()); { PseudoSelector select{"true", false}; ASSERT_EQ(select, A->getPseudoSelector()); } ASSERT_EQ(0, A->getEdges().size()); ASSERT_TRUE(A->isAccepting()); { Rooted ruleSet = A->getRuleSet(); ASSERT_EQ(2, ruleSet->getRules().size()); Variant v = ruleSet->getRules()["ident1"]; ASSERT_EQ(Variant::Type::STRING, v.getType()); ASSERT_EQ("val4", v.asString()); v = ruleSet->getRules()["ident2"]; ASSERT_EQ(Variant::Type::STRING, v.getType()); ASSERT_EQ("val2", v.asString()); } /* * For this part of the SelectorTree we only have * * A:select(a,b) { * ident3 : val3; * } */ Rooted Aselect = children[1]; ASSERT_EQ("A", Aselect->getName()); { PseudoSelector select{"select", {"a", "b"}, false}; ASSERT_EQ(select, Aselect->getPseudoSelector()); } ASSERT_EQ(0, Aselect->getEdges().size()); ASSERT_TRUE(Aselect->isAccepting()); { Rooted ruleSet = Aselect->getRuleSet(); ASSERT_EQ(1, ruleSet->getRules().size()); Variant v = ruleSet->getRules()["ident3"]; ASSERT_EQ(Variant::Type::STRING, v.getType()); ASSERT_EQ("val3", v.asString()); } /* * The remaining part of the SelectorTree is * * B A { * ident1 : val1; * ident2 : val2; * } */ children = root->getChildren("B"); ASSERT_EQ(1, children.size()); Rooted B = children[0]; ASSERT_EQ("B", B->getName()); { PseudoSelector select{"true", false}; ASSERT_EQ(select, B->getPseudoSelector()); } ASSERT_EQ(1, B->getEdges().size()); ASSERT_FALSE(B->isAccepting()); ASSERT_EQ(0, B->getRuleSet()->getRules().size()); children = B->getChildren("A"); ASSERT_EQ(1, children.size()); Rooted BA = children[0]; ASSERT_EQ("A", BA->getName()); { PseudoSelector select{"true", false}; ASSERT_EQ(select, BA->getPseudoSelector()); } ASSERT_EQ(0, BA->getEdges().size()); ASSERT_TRUE(BA->isAccepting()); { Rooted ruleSet = BA->getRuleSet(); ASSERT_EQ(2, ruleSet->getRules().size()); Variant v = ruleSet->getRules()["ident1"]; ASSERT_EQ(Variant::Type::STRING, v.getType()); ASSERT_EQ("val1", v.asString()); v = ruleSet->getRules()["ident2"]; ASSERT_EQ(Variant::Type::STRING, v.getType()); ASSERT_EQ("val2", v.asString()); } } void assertException(std::string css) { CharReader reader(css); TerminalLogger logger(std::cerr, true); { ScopedLogger sl(logger, "test.css", SourceLocation{}, CharReader::contextCallback, &reader); Scope scope(nullptr); Registry registry(logger); Manager manager; ParserContext ctx{scope, registry, logger, manager}; CSSParser instance; try { instance.parse(reader, ctx).cast(); } catch (LoggableException ex) { logger.log(ex); } ASSERT_TRUE(logger.hasError()); } } TEST(CSSParser, testParseExceptions) { assertException(", "); assertException("A::myGenerative , "); assertException("A::(a)"); assertException("A::f()"); assertException("A#"); assertException("A[]"); assertException("A[a"); assertException("A[a=]"); assertException("A > "); } } } }