Browse Source

CMake option for enabling benchmarks in Tests. Add benchmark for creation and destruction of elements. Refactor geometry database tests.

Michael Ragazzon 5 years ago
parent
commit
64c8574130

+ 1 - 0
CMakeLists.txt

@@ -75,6 +75,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
 	
 	
 	if(BUILD_TESTING)
 	if(BUILD_TESTING)
 		set(RMLUI_TESTS_ENABLED ON)
 		set(RMLUI_TESTS_ENABLED ON)
+		option(ENABLE_BENCHMARKS "Will enable benchmarks while running Tests." ON)
 	endif()
 	endif()
 endif()
 endif()
 
 

+ 33 - 0
Source/Core/GeometryDatabase.cpp

@@ -70,6 +70,15 @@ public:
 		return handle;
 		return handle;
 	}
 	}
 
 
+	int size() const
+	{
+		return (int)geometry_list.size() - (int)free_list.size();
+	}
+
+	void clear() {
+		geometry_list.clear();
+		free_list.clear();
+	}
 	void erase(GeometryDatabaseHandle handle)
 	void erase(GeometryDatabaseHandle handle)
 	{
 	{
 		free_list.push_back(handle);
 		free_list.push_back(handle);
@@ -125,5 +134,29 @@ void ReleaseAll()
 }
 }
 
 
 
 
+#ifdef RMLUI_TESTS_ENABLED
+
+bool PrepareForTests()
+{
+	if (!geometry_database.size() == 0)
+		return false;
+
+	geometry_database.clear();
+
+	return true;
+}
+
+bool ListMatchesDatabase(const Vector<Geometry>& geometry_list)
+{
+	int i = 0;
+	bool result = true;
+	geometry_database.for_each([&geometry_list, &i, &result](Geometry* geometry) {
+		result &= (geometry == &geometry_list[i++]);
+		});
+	return result;
+}
+
+#endif // RMLUI_TESTS_ENABLED
+
 } // namespace GeometryDatabase
 } // namespace GeometryDatabase
 } // namespace Rml
 } // namespace Rml

+ 5 - 0
Source/Core/GeometryDatabase.h

@@ -30,6 +30,7 @@
 #define RMLUI_CORE_GEOMETRYDATABASE_H
 #define RMLUI_CORE_GEOMETRYDATABASE_H
 
 
 #include <stdint.h>
 #include <stdint.h>
+#include "../../Include/RmlUi/Core/Types.h"
 
 
 namespace Rml {
 namespace Rml {
 
 
@@ -52,6 +53,10 @@ namespace GeometryDatabase {
 
 
     void ReleaseAll();
     void ReleaseAll();
 
 
+#ifdef RMLUI_TESTS_ENABLED
+    bool PrepareForTests();
+    bool ListMatchesDatabase(const Vector<Geometry>& geometry_list);
+#endif
 }
 }
 
 
 } // namespace Rml
 } // namespace Rml

+ 7 - 1
Tests/CMakeLists.txt

@@ -16,13 +16,19 @@ set_property(TARGET nanobench::nanobench PROPERTY INTERFACE_INCLUDE_DIRECTORIES
 #===================================
 #===================================
 file(GLOB RmlTest_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Source/*.cpp)
 file(GLOB RmlTest_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Source/*.cpp)
 add_executable(Tests ${RmlTest_SRC_FILES})
 add_executable(Tests ${RmlTest_SRC_FILES})
-target_link_libraries(Tests RmlCore RmlDebugger doctest::doctest nanobench::nanobench)
+target_link_libraries(Tests RmlCore RmlDebugger doctest::doctest nanobench::nanobench ${sample_LIBRARIES})
 
 
 set_target_properties(Tests PROPERTIES CXX_STANDARD 14)
 set_target_properties(Tests PROPERTIES CXX_STANDARD 14)
 
 
 # Enable compiler warnings
 # Enable compiler warnings
 add_common_target_options(Tests)
 add_common_target_options(Tests)
 
 
+target_compile_definitions(RmlCore PUBLIC RMLUI_TESTS_ENABLED)
+
+if(TESTING_BENCHMARKS)
+	target_compile_definitions(Tests PRIVATE RMLUI_ENABLE_BENCHMARKS)
+endif()
+
 if(MSVC)
 if(MSVC)
 	target_compile_definitions(Tests PUBLIC DOCTEST_CONFIG_USE_STD_HEADERS)
 	target_compile_definitions(Tests PUBLIC DOCTEST_CONFIG_USE_STD_HEADERS)
 endif()
 endif()

+ 183 - 0
Tests/Data/acid1.rml

@@ -0,0 +1,183 @@
+<rml>
+<head>
+<title>display/box/float/clear test</title>
+<style type="text/css">
+/* Add default values for elements (RmlUi does not provide a default style sheet) */
+dl,dt,dd,ul,li,blockquote,address,h1,p {
+display: block;
+}
+input.radio {
+width: 10px;
+height: 10px;
+border: 1px #666;
+background: #fff;
+}
+
+/* RmlUi does not accept styling of the html/rml element, they have been moved into body. */
+body {
+font-family: rmlui-debugger-font;
+font-weight: normal;
+font-style: normal;
+font-size: 10px;
+background-color: blue;
+color: white;
+margin: 1.5em;
+border: .5em black;
+padding: 0;
+width: 48em;
+background-color: white;
+}
+
+dl {
+margin: 0;
+border: 0;
+padding: .5em;
+}
+
+dt { 
+background-color: rgb(204,0,0);
+margin: 0; 
+padding: 1em;
+width: 10.638%; /* refers to parent element's width of 47em. = 5em or 50px */
+height: 28em;
+border: .5em black;
+float: left;
+}
+
+dd {
+float: right;
+margin: 0 0 0 1em;
+border: 1em black;
+padding: 1em;
+width: 34em;
+height: 27em;
+}
+
+ul {
+margin: 0;
+border: 0;
+padding: 0;
+}
+
+li {
+display: block; /* i.e., suppress marker */
+color: black;
+height: 9em;
+width: 5em;
+margin: 0;
+border: .5em black;
+padding: 1em;
+float: left;
+background-color: #FC0;
+}
+
+#bar {
+background-color: black;
+color: white;
+width: 41.17%; /* = 14em */
+border: 0;
+margin: 0 1em;
+}
+
+#baz {
+margin: 1em 0;
+border: 0;
+padding: 1em;
+width: 10em;
+height: 10em;
+background-color: black;
+color: white;
+}
+
+form { 
+margin: 0;
+display: inline;
+}
+
+p { 
+margin: 0;
+}
+
+form p {
+line-height: 1.9;
+}
+
+blockquote {
+margin: 1em 1em 1em 2em;
+border-width: 1em 1.5em 2em .5em;
+border-color: black;
+padding: 1em 0;
+width: 5em;
+height: 9em;
+float: left;
+background-color: #FC0;
+color: black;
+}
+
+address {
+font-style: normal;
+}
+
+h1 {
+background-color: black;
+color: white;
+float: left;
+margin: 1em 0;
+border: 0;
+padding: 1em;
+width: 10em;
+height: 10em;
+font-weight: normal;
+font-size: 1em;
+}
+</style>
+</head>
+<body>
+	<dl>
+		<dt>
+		 toggle 
+		</dt>
+		<dd>
+		<ul>
+			<li>
+			 the way 
+			</li>
+			<li id="bar">
+			<p>
+			 the world ends 
+			</p>
+			<form action="./" method="get">
+				<p>
+				 bang 
+				<input type="radio" name="foo" value="off"/>
+				</p>
+				<p>
+				 whimper 
+				<input type="radio" name="foo2" value="on"/>
+				</p>
+			</form>
+			</li>
+			<li>
+			 i grow old 
+			</li>
+			<li id="baz">
+			 pluot? 
+			</li>
+		</ul>
+		<blockquote>
+			<address>
+				 bar maids, 
+			</address>
+		</blockquote>
+		<h1>
+			 sing to me, erbarme dich 
+		</h1>
+		</dd>
+	</dl>
+	<p style="color: black; font-size: 1em; line-height: 1.3em; clear: both">
+	 This is a nonsensical document, but syntactically valid HTML 4.0. All 100%-conformant CSS1 agents should be able to render the document elements above this paragraph indistinguishably (to the pixel) from this 
+		<a href="sec5526c.gif">reference rendering,</a>
+	 (except font rasterization and form widgets). All discrepancies should be traceable to CSS1 implementation shortcomings. Once you have finished evaluating this test, you can return to the <A HREF="sec5526c.htm">parent page</A>. 
+	</p>
+</body>
+</rml>

+ 2 - 0
Tests/Source/DataExpression.cpp

@@ -168,8 +168,10 @@ TEST_CASE("Data expressions")
 	CHECK(TestExpression("(3.42345 | format(0)) + 0.2") == "30.2"); // Here, format(0) returns a string, so the + means string concatenation.
 	CHECK(TestExpression("(3.42345 | format(0)) + 0.2") == "30.2"); // Here, format(0) returns a string, so the + means string concatenation.
 
 
 	// Benchmark
 	// Benchmark
+#ifdef RMLUI_ENABLE_BENCHMARKS
 	TestExpression("2 * 2", "Data expression simple");
 	TestExpression("2 * 2", "Data expression simple");
 	TestExpression("true || false ? true && 3==1+2 ? 'Absolutely!' : 'well..' : 'no'", "Data expression complex");
 	TestExpression("true || false ? true && 3==1+2 ? 'Absolutely!' : 'well..' : 'no'", "Data expression complex");
+#endif
 }
 }
 
 
 
 

+ 136 - 0
Tests/Source/Element.cpp

@@ -0,0 +1,136 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifdef RMLUI_ENABLE_BENCHMARKS
+
+#include "TestsInterface.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/Element.h>
+#include <RmlUi/Core/ElementDocument.h>
+#include <RmlUi/Core/Types.h>
+#include <RmlUi/Debugger.h>
+
+#include <Shell.h>
+#include <Input.h>
+#include <ShellRenderInterfaceOpenGL.h>
+
+#include <doctest.h>
+#include <nanobench.h>
+
+using namespace ankerl;
+using namespace Rml;
+
+static Rml::Context* context = nullptr;
+static ShellRenderInterfaceExtensions* shell_renderer;
+
+
+TEST_CASE("Element benchmark")
+{
+	const Vector2i window_size(1024, 768);
+
+	ShellRenderInterfaceOpenGL opengl_renderer;
+	shell_renderer = &opengl_renderer;
+
+	// Generic OS initialisation, creates a window and attaches OpenGL.
+	REQUIRE(Shell::Initialise());
+	REQUIRE(Shell::OpenWindow("Element benchmark", shell_renderer, window_size.x, window_size.y, true));
+
+	// RmlUi initialisation.
+	Rml::SetRenderInterface(&opengl_renderer);
+	shell_renderer->SetViewport(window_size.x, window_size.y);
+
+	ShellSystemInterface system_interface;
+	Rml::SetSystemInterface(&system_interface);
+
+	//TestsSystemInterface system_interface;
+	//TestsRenderInterface render_interface;
+
+	//SetRenderInterface(&render_interface);
+	//SetSystemInterface(&system_interface);
+
+	REQUIRE(Initialise());
+
+	context = Rml::CreateContext("main", window_size);
+	REQUIRE(context);
+
+	Rml::Debugger::Initialise(context);
+	::Input::SetContext(context);
+	shell_renderer->SetContext(context);
+
+	Shell::LoadFonts("assets/");
+
+	ElementDocument* document = context->LoadDocument("basic/benchmark/data/benchmark.rml");
+	REQUIRE(document);
+	document->Show();
+
+	Rml::String rml;
+	Element* el = document->GetElementById("performance");
+	REQUIRE(el);
+
+	nanobench::Bench bench;
+	bench.title("Elements")
+		.run("SetInnerRML", [&] {
+		for (int i = 0; i < 50; i++)
+		{
+			int index = rand() % 1000;
+			int route = rand() % 50;
+			int max = (rand() % 40) + 10;
+			int value = rand() % max;
+			Rml::String rml_row = Rml::CreateString(1000, R"(
+				<div class="row">
+					<div class="col col1"><button class="expand" index="%d">+</button>&nbsp;<a>Route %d</a></div>
+					<div class="col col23"><input type="range" class="assign_range" min="0" max="%d" value="%d"/></div>
+					<div class="col col4">Assigned</div>
+					<select>
+						<option>Red</option><option>Blue</option><option selected>Green</option><option style="background-color: yellow;">Yellow</option>
+					</select>
+					<div class="inrow unmark_collapse">
+						<div class="col col123 assign_text">Assign to route</div>
+						<div class="col col4">
+							<input type="submit" class="vehicle_depot_assign_confirm" quantity="0">Confirm</input>
+						</div>
+					</div>
+				</div>)",
+				index,
+				route,
+				max,
+				value
+			);
+			rml += rml_row;
+		}
+
+		el->SetInnerRML(rml);
+	});
+
+	Rml::Shutdown();
+
+	Shell::CloseWindow();
+}
+
+#endif

+ 15 - 18
Tests/Source/GeometryDatabase.cpp

@@ -26,47 +26,44 @@
  *
  *
  */
  */
 
 
-#include "../../../Source/Core/GeometryDatabase.cpp"
+
+#include <RmlUi/Core/Types.h>
+#include <RmlUi/Core/Geometry.h>
+#include "../../../Source/Core/GeometryDatabase.h"
 #include <doctest.h>
 #include <doctest.h>
 
 
 using namespace Rml;
 using namespace Rml;
 
 
-
 TEST_CASE("Geometry database")
 TEST_CASE("Geometry database")
 {
 {
-	Vector<Geometry> geometry_list(10);
+	REQUIRE(GeometryDatabase::PrepareForTests());
 
 
-	auto list_database_equivalent = [&geometry_list]() -> bool {
-		int i = 0;
-		bool result = true;
-		GeometryDatabase::geometry_database.for_each([&geometry_list, &i, &result](Geometry* geometry) {
-			result &= (geometry == &geometry_list[i++]);
-			});
-		return result;
-	};
+	using GeometryDatabase::ListMatchesDatabase;
+
+	Vector<Geometry> geometry_list(10);
 
 
 	int i = 0;
 	int i = 0;
 	for (auto& geometry : geometry_list)
 	for (auto& geometry : geometry_list)
 		geometry.GetIndices().push_back(i++);
 		geometry.GetIndices().push_back(i++);
 
 
-	CHECK(list_database_equivalent());
+	CHECK(ListMatchesDatabase(geometry_list));
 
 
 	geometry_list.reserve(2000);
 	geometry_list.reserve(2000);
-	CHECK(list_database_equivalent());
+	CHECK(ListMatchesDatabase(geometry_list));
 
 
 	geometry_list.erase(geometry_list.begin() + 5);
 	geometry_list.erase(geometry_list.begin() + 5);
-	CHECK(list_database_equivalent());
+	CHECK(ListMatchesDatabase(geometry_list));
 
 
 	std::swap(geometry_list.front(), geometry_list.back());
 	std::swap(geometry_list.front(), geometry_list.back());
 	geometry_list.pop_back();
 	geometry_list.pop_back();
-	CHECK(list_database_equivalent());
+	CHECK(ListMatchesDatabase(geometry_list));
 
 
 	std::swap(geometry_list.front(), geometry_list.back());
 	std::swap(geometry_list.front(), geometry_list.back());
-	CHECK(list_database_equivalent());
+	CHECK(ListMatchesDatabase(geometry_list));
 
 
 	geometry_list.emplace_back();
 	geometry_list.emplace_back();
-	CHECK(list_database_equivalent());
+	CHECK(ListMatchesDatabase(geometry_list));
 
 
 	geometry_list.clear();
 	geometry_list.clear();
-	CHECK(list_database_equivalent());
+	CHECK(ListMatchesDatabase(geometry_list));
 }
 }