Simple html/css test tool
parent
3b91146d23
commit
52e0e71c4a
@ -0,0 +1,15 @@
|
|||||||
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.1)
|
||||||
|
CMAKE_POLICY(SET CMP0015 NEW)
|
||||||
|
|
||||||
|
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${CMAKE_LIBRARY_DIR})
|
||||||
|
ADD_DEFINITIONS(${LIBXML2_DEFINITIONS})
|
||||||
|
|
||||||
|
FILE(GLOB SRC htmlcss_test.cpp)
|
||||||
|
ADD_EXECUTABLE(htmlcss_test ${SRC})
|
||||||
|
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${LUA_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR} )
|
||||||
|
TARGET_LINK_LIBRARIES(htmlcss_test nelmisc nelgui ${LUA_LIBRARIES} ${LIBXML2_LIBRARIES})
|
||||||
|
NL_DEFAULT_PROPS(htmlcss_test "Ryzom, Tests: html/css parser tests")
|
||||||
|
NL_ADD_RUNTIME_FLAGS(htmlcss_test)
|
||||||
|
|
||||||
|
INSTALL(TARGETS htmlcss_test RUNTIME DESTINATION bin COMPONENT tools)
|
||||||
|
# TODO: test fixtures
|
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* File: main.cpp
|
||||||
|
* Author: Karu <nimetu@gmail.com>
|
||||||
|
*
|
||||||
|
* Created on 2015-04-11
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _xmlNode xmlNode;
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "nel/misc/types_nl.h"
|
||||||
|
#include "nel/misc/file.h"
|
||||||
|
#include "nel/misc/path.h"
|
||||||
|
|
||||||
|
#include "nel/gui/html_parser.h"
|
||||||
|
#include "nel/gui/css_parser.h"
|
||||||
|
#include "nel/gui/html_element.h"
|
||||||
|
#include "nel/gui/css_style.h"
|
||||||
|
|
||||||
|
#include "nel/gui/libwww.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace NLMISC;
|
||||||
|
using namespace NLGUI;
|
||||||
|
|
||||||
|
sint indent { 0 };
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
void checkRuleset(CHtmlElement &elm, CCssStyle &style, TStyleVec testset, bool exists)
|
||||||
|
{
|
||||||
|
bool verbose = false;
|
||||||
|
std::string existsMessage = exists ? "exist" : "unset";
|
||||||
|
for (auto it : testset)
|
||||||
|
{
|
||||||
|
bool failed = (exists != style.hasStyle(it.first));
|
||||||
|
if (failed)
|
||||||
|
{
|
||||||
|
bool failed2 = true;
|
||||||
|
if (it.first == "font-size")
|
||||||
|
{
|
||||||
|
printf("[%s]: font-size: %d; expected '%s'\n", existsMessage.c_str(), style.Current.FontSize, it.second.c_str());
|
||||||
|
printf(" (%s)\n", elm.toString().c_str());
|
||||||
|
failed2 = false;
|
||||||
|
}
|
||||||
|
else if (it.first == "background-color")
|
||||||
|
{
|
||||||
|
printf("[%s]: background-color: '%s'; expected '%s'\n", existsMessage.c_str(), style.Current.BackgroundColor.toString().c_str(), it.second.c_str());
|
||||||
|
printf(" (%s)\n", elm.toString().c_str());
|
||||||
|
failed2 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failed2)
|
||||||
|
{
|
||||||
|
printf("[%s] FAIL: '%s': '%s'\n", existsMessage.c_str(), it.first.c_str(), it.second.c_str());
|
||||||
|
printf(" (%s)\n", elm.toString().c_str());
|
||||||
|
for (auto it2 : style.Current.StyleRules)
|
||||||
|
printf("'%s': '%s'\n", it2.first.c_str(), it2.second.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (exists && !style.checkStyle(it.first, it.second))
|
||||||
|
{
|
||||||
|
printf("[%s] FAIL: expecting '%s': '%s', got '%s'\n", existsMessage.c_str(), it.first.c_str(), it.second.c_str(), style.getStyle(it.first).c_str());
|
||||||
|
printf(" (%s)\n", elm.toString().c_str());
|
||||||
|
}
|
||||||
|
else if (!failed)
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
printf("[%s] PASS: '%s': '%s'\n", existsMessage.c_str(), it.first.c_str(), it.second.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
void recursiveHtmlRender(CHtmlElement &elm, CCssStyle &style)
|
||||||
|
{
|
||||||
|
bool verbose = false;
|
||||||
|
if (elm.Type == CHtmlElement::TEXT_NODE)
|
||||||
|
{
|
||||||
|
std::string val = trim(elm.Value);
|
||||||
|
if (verbose)
|
||||||
|
if (!val.empty())
|
||||||
|
printf("[%d] '%s'\n", indent, val.c_str());
|
||||||
|
}
|
||||||
|
else if (elm.Type == CHtmlElement::ELEMENT_NODE)
|
||||||
|
{
|
||||||
|
style.pushStyle();
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
printf("========= '%s'\n", elm.toString().c_str());
|
||||||
|
|
||||||
|
style.getStyleFor(elm);
|
||||||
|
style.applyStyle(elm.Style);
|
||||||
|
if (elm.hasAttribute("data-ruleset"))
|
||||||
|
{
|
||||||
|
TStyleVec testset = CCssParser::parseDecls(elm.getAttribute("data-ruleset"));
|
||||||
|
checkRuleset(elm, style, testset, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elm.hasAttribute("data-ruleunset"))
|
||||||
|
{
|
||||||
|
TStyleVec testset = CCssParser::parseDecls(elm.getAttribute("data-ruleunset"));
|
||||||
|
checkRuleset(elm, style, testset, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elm.hasAttribute("data-ruleset-before"))
|
||||||
|
{
|
||||||
|
TStyleVec testset = CCssParser::parseDecls(elm.getAttribute("data-ruleset-before"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = elm.Children.begin(); it != elm.Children.end(); ++it)
|
||||||
|
{
|
||||||
|
recursiveHtmlRender(*it, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
style.popStyle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
void runTestOnFile(const std::string &filename)
|
||||||
|
{
|
||||||
|
CHtmlElement dom;
|
||||||
|
|
||||||
|
CHtmlParser htmlParser;
|
||||||
|
|
||||||
|
std::vector<CHtmlParser::StyleLink> links;
|
||||||
|
std::vector<std::string> styles;
|
||||||
|
//, elm, styles, links
|
||||||
|
|
||||||
|
ifstream f(filename);
|
||||||
|
if (!f.is_open())
|
||||||
|
{
|
||||||
|
printf("!! failed to open file '%s'\n", filename.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(": %s\n", filename.c_str());
|
||||||
|
std::string htmlString;
|
||||||
|
std::string line;
|
||||||
|
while (getline(f, line))
|
||||||
|
htmlString += line;
|
||||||
|
|
||||||
|
htmlParser.getDOM(htmlString, dom, styles, links);
|
||||||
|
|
||||||
|
CCssStyle style;
|
||||||
|
for (std::string s : styles)
|
||||||
|
{
|
||||||
|
if (!s.empty())
|
||||||
|
style.parseStylesheet(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = dom.Children.begin(); it != dom.Children.end(); ++it)
|
||||||
|
recursiveHtmlRender(*it, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
int main(int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
CApplicationContext *appContext = new CApplicationContext;
|
||||||
|
|
||||||
|
// htmlcss_test file.html
|
||||||
|
if (argc == 2)
|
||||||
|
{
|
||||||
|
runTestOnFile(argv[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
CPath::getPathContent("tests/", true /*recursive*/, false /*wantDir*/, true /*wantFile*/, result, NULL /*callback*/, true /*showEverything*/);
|
||||||
|
printf(":: got %ld files\n", result.size());
|
||||||
|
for (const auto &fname : result)
|
||||||
|
{
|
||||||
|
if (endsWith(fname, ".html") && fname != "tests/XX-template.html")
|
||||||
|
runTestOnFile(fname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(">>> all done\n");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
:lang(en) { --text: '(en)'; }
|
||||||
|
:lang(de-DE) { --text: '(de-DE)'; }
|
||||||
|
a { test: " (" var(--lang) ")"}
|
||||||
|
|
||||||
|
div {
|
||||||
|
/* '--a' and '--b' are both 'initial' */
|
||||||
|
--should-not-exist: var(--a, var(--b, ( "p() " ) ), { "b" [ "r" ] });
|
||||||
|
/* 'before -var- after' */
|
||||||
|
--concate-test: 'before' var(--exists) 'after';
|
||||||
|
--exists: '-var-';
|
||||||
|
/* fallback should be at least one char */
|
||||||
|
--invalid-fallback: var(--exists,);
|
||||||
|
/* using fallback */
|
||||||
|
--fallback: var(--a, 'ok');
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div data-ruleset="--concate-test: 'before' '-var-' 'after'; --exists: '-var-'; --fallback: 'ok';"
|
||||||
|
data-ruleunset="--should-not-exists: 1; --invalid-fallback: 1;" />
|
||||||
|
|
||||||
|
<a lang="en" data-ruleset="--text: '(en)';">link</a>
|
||||||
|
<a lang="de" data-ruleunset="--text: 1;">link</a>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,24 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
p {
|
||||||
|
--mq-sm: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small {
|
||||||
|
--mq-sm: ;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
--padding-when-small: var(--mq-sm) 2rem;
|
||||||
|
--padding-when-large: 4rem;
|
||||||
|
padding: var(--padding-when-small, var(--padding-when-large));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<p data-ruleset="padding-left: 4rem;" comment="--mq-sm==initial, should use fallback value" />
|
||||||
|
<div>
|
||||||
|
<p class="small" data-ruleset="padding-left: 2rem;" comment="--mq-sm==;, should use defined value"/>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--main-color: #06c;
|
||||||
|
--accent-color: #006;
|
||||||
|
}
|
||||||
|
/* The rest of the CSS file */
|
||||||
|
#foo h1 {
|
||||||
|
color: var(--main-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="foo">
|
||||||
|
<h1 data-ruleset="color: #06c;">Header</h1>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--main-color: #06c;
|
||||||
|
--accent-color: #006;
|
||||||
|
--MAIN-COLOR: #f00;
|
||||||
|
}
|
||||||
|
/* The rest of the CSS file */
|
||||||
|
#foo h1 {
|
||||||
|
color: var(--main-color);
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
color: var(--MAIN-COLOR);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="foo">
|
||||||
|
<h1 data-ruleset="color: #06c;">Header1</h1>
|
||||||
|
<h2 data-ruleset="color: #f00;">Header2</h1>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--foo: if(x > 5) this.width = 10;
|
||||||
|
}
|
||||||
|
/* The rest of the CSS file */
|
||||||
|
#foo h1 {
|
||||||
|
test: var(--foo)
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="foo">
|
||||||
|
<h1 data-ruleset="test: if(x > 5) this.width = 10;">Header</h1>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
a:lang(en) {--lang: 'en';}
|
||||||
|
a:lang(de) {--lang: 'de';}
|
||||||
|
a { test: var(--lang); }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<a lang="en" data-ruleset="test: 'en';">link</a>
|
||||||
|
|
||||||
|
<a lang="de" data-ruleset="test: 'de';">link</a>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--main-color: #c06;
|
||||||
|
--accent-background: var(--main-color);
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
test: var(--accent-background);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div data-ruleset="test: #c06;"/>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
--one: calc(var(--two) + 20px);
|
||||||
|
--two: calc(var(--one) - 20px);
|
||||||
|
--ok: 'ok';
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div data-ruleset="--ok: 'ok';"
|
||||||
|
data-ruleunset="--one: 1; --two: 1;" />
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
one { --foo: 10px; }
|
||||||
|
two { --bar: calc(var(--foo) + 10px); }
|
||||||
|
three { --foo: calc(var(--bar) + 10px); }
|
||||||
|
</style>
|
||||||
|
<one data-ruleset="--foo: 10px;">
|
||||||
|
<two data-ruleset="--bar: calc( 10px + 10px);">
|
||||||
|
<three data-ruleset="--foo: calc( calc( 10px + 10px) + 10px);"/>
|
||||||
|
</two>
|
||||||
|
</one>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
--side: margin-top;
|
||||||
|
var(--side): 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div data-ruleset="--side: margin-top;" data-ruleunset="var(--side): 1;" />
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
--gap: 20;
|
||||||
|
margin-top: var(--gap)px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!-- should have whitespace, ie '20 px' -->
|
||||||
|
<div data-ruleset="margin-top: 20 px;" />
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
:root { --not-a-color: 20px; }
|
||||||
|
p { background-color: red; }
|
||||||
|
p { background-color: var(--not-a-color); }
|
||||||
|
</style>
|
||||||
|
<!-- this should have 'red' because var() has invalid value for color -->
|
||||||
|
<!-- TODO: not really supported by NEL currently -->
|
||||||
|
<div data-ruleset="background-color: red;" />
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue