Browse Source

Implement unit tests for the newly introduced functionality

ZombieRaccoon 4 years ago
parent
commit
97044c3e84

+ 74 - 15
Tests/Source/UnitTests/Element.cpp

@@ -27,9 +27,11 @@
  */
  */
 
 
 #include "../Common/TestsShell.h"
 #include "../Common/TestsShell.h"
+#include "FakeEventListenerInstancer.h"
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Element.h>
 #include <RmlUi/Core/Element.h>
 #include <RmlUi/Core/ElementDocument.h>
 #include <RmlUi/Core/ElementDocument.h>
+#include <RmlUi/Core/Factory.h>
 #include <doctest.h>
 #include <doctest.h>
 
 
 using namespace Rml;
 using namespace Rml;
@@ -65,8 +67,7 @@ static const String document_clone_rml = R"(
 </rml>
 </rml>
 )";
 )";
 
 
-
-TEST_CASE("element.clone")
+TEST_CASE("element")
 {
 {
 	Context* context = TestsShell::GetContext();
 	Context* context = TestsShell::GetContext();
 	REQUIRE(context);
 	REQUIRE(context);
@@ -79,27 +80,85 @@ TEST_CASE("element.clone")
 	context->Render();
 	context->Render();
 
 
 	TestsShell::RenderLoop();
 	TestsShell::RenderLoop();
+	SUBCASE("attribute")
+	{
+		auto* button = document->AppendChild(document->CreateElement("button"));
+		SUBCASE("event listener")
+		{
+			static constexpr auto CLICK_EVENT = "click";
+			static constexpr auto ON_CLICK_ATTRIBUTE = "onclick";
+			static constexpr auto ON_CLICK_VALUE = "moo";
+
+			FakeEventListenerInstancer eventListenerInstancer;
+			Factory::RegisterEventListenerInstancer(&eventListenerInstancer);
+
+			REQUIRE(button->DispatchEvent(CLICK_EVENT, {}));
+			button->SetAttribute(ON_CLICK_ATTRIBUTE, ON_CLICK_VALUE);
+			REQUIRE_EQ(eventListenerInstancer.GetLastInstancedValue(), ON_CLICK_VALUE);
+			CHECK_FALSE(button->DispatchEvent(CLICK_EVENT, {}));
+
+			SUBCASE("removal")
+			{
+				button->RemoveAttribute(ON_CLICK_ATTRIBUTE);
+				CHECK(button->DispatchEvent(CLICK_EVENT, {}));
+			}
+
+			SUBCASE("replacement")
+			{
+				static constexpr auto REPLACEMENT_ON_CLICK_VALUE = "boo";
+				button->SetAttribute(ON_CLICK_ATTRIBUTE, REPLACEMENT_ON_CLICK_VALUE);
+				REQUIRE_EQ(eventListenerInstancer.GetLastInstancedValue(), REPLACEMENT_ON_CLICK_VALUE);
+				CHECK_FALSE(button->DispatchEvent(CLICK_EVENT, {}));
+			}
+		}
 
 
-	// Simulate input for mouse click and drag
-	context->ProcessMouseMove(10, 10, 0);
+		SUBCASE("simple")
+		{
+			static constexpr auto DISABLED_ATTRIBUTE = "disabled";
+			REQUIRE_FALSE(button->HasAttribute(DISABLED_ATTRIBUTE));
+			button->SetAttribute(DISABLED_ATTRIBUTE, "");
+			REQUIRE(button->HasAttribute(DISABLED_ATTRIBUTE));
+
+			SUBCASE("removal")
+			{
+				button->RemoveAttribute(DISABLED_ATTRIBUTE);
+				CHECK_FALSE(button->HasAttribute(DISABLED_ATTRIBUTE));
+			}
+
+			SUBCASE("replacement")
+			{
+				static constexpr auto VALUE = "something";
+				button->SetAttribute(DISABLED_ATTRIBUTE, VALUE);
+				const auto* attributeValue = button->GetAttribute(DISABLED_ATTRIBUTE);
+				REQUIRE(attributeValue);
+				REQUIRE(attributeValue->GetType() == Variant::Type::STRING);
+				CHECK(attributeValue->Get<String>() == VALUE);
+			}
+		}
+	}
 
 
-	context->Update();
-	context->Render();
+	SUBCASE("clone")
+	{
+		// Simulate input for mouse click and drag
+		context->ProcessMouseMove(10, 10, 0);
 
 
-	context->ProcessMouseButtonDown(0, 0);
+		context->Update();
+		context->Render();
 
 
-	context->Update();
-	context->Render();
+		context->ProcessMouseButtonDown(0, 0);
 
 
-	// This should initiate a drag clone.
-	context->ProcessMouseMove(10, 11, 0);
+		context->Update();
+		context->Render();
 
 
-	context->Update();
-	context->Render();
+		// This should initiate a drag clone.
+		context->ProcessMouseMove(10, 11, 0);
 
 
-	context->ProcessMouseButtonUp(0, 0);
+		context->Update();
+		context->Render();
 
 
-	document->Close();
+		context->ProcessMouseButtonUp(0, 0);
+	}
 
 
+	document->Close();
 	TestsShell::ShutdownShell();
 	TestsShell::ShutdownShell();
 }
 }

+ 60 - 35
Tests/Source/UnitTests/ElementDocument.cpp

@@ -27,9 +27,11 @@
  */
  */
 
 
 #include "../Common/TestsShell.h"
 #include "../Common/TestsShell.h"
+#include "FakeEventListenerInstancer.h"
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Element.h>
 #include <RmlUi/Core/Element.h>
 #include <RmlUi/Core/ElementDocument.h>
 #include <RmlUi/Core/ElementDocument.h>
+#include <RmlUi/Core/Factory.h>
 #include <doctest.h>
 #include <doctest.h>
 #include <algorithm>
 #include <algorithm>
 
 
@@ -60,7 +62,7 @@ static const String document_focus_rml = R"(
 	</style>
 	</style>
 </head>
 </head>
 
 
-<body id="body">
+<body id="body" onload="something">
 <input type="checkbox" id="p1"/> P1
 <input type="checkbox" id="p1"/> P1
 <label><input type="checkbox" id="p2"/> P2</label>
 <label><input type="checkbox" id="p2"/> P2</label>
 <p>
 <p>
@@ -94,8 +96,9 @@ static const String document_focus_rml = R"(
 
 
 static const String focus_forward = "p1 p2 p3 p5 p7 p9 p10 p11 p12 p13";
 static const String focus_forward = "p1 p2 p3 p5 p7 p9 p10 p11 p12 p13";
 
 
+TEST_SUITE_BEGIN("elementdocument");
 
 
-TEST_CASE("elementdocument.focus")
+TEST_CASE("focus")
 {
 {
 	Context* context = TestsShell::GetContext();
 	Context* context = TestsShell::GetContext();
 	REQUIRE(context);
 	REQUIRE(context);
@@ -108,42 +111,47 @@ TEST_CASE("elementdocument.focus")
 	context->Render();
 	context->Render();
 
 
 	TestsShell::RenderLoop();
 	TestsShell::RenderLoop();
-
-	document->Focus();
-
-	StringList ids;
-	StringUtilities::ExpandString(ids, focus_forward, ' ');
-
-	REQUIRE(!ids.empty());
-
-	// Forward direction
-	for(const String& id : ids)
+	SUBCASE("tab order")
 	{
 	{
-		context->ProcessKeyDown(Input::KI_TAB, 0);
-		CHECK(context->GetFocusElement()->GetId() == id);
-	}
-
-	// Wrap around
-	context->ProcessKeyDown(Input::KI_TAB, 0);
-	CHECK(context->GetFocusElement()->GetId() == ids[0]);
+		StringList ids;
+		StringUtilities::ExpandString(ids, focus_forward, ' ');
+		REQUIRE(!ids.empty());
 
 
-	document->Focus();
-
-	std::reverse(ids.begin(), ids.end());
+		document->Focus();
+		SUBCASE("forward")
+		{
+			for(const String& id : ids)
+			{
+				context->ProcessKeyDown(Input::KI_TAB, 0);
+				CHECK(context->GetFocusElement()->GetId() == id);
+			}
+
+			// Wrap around
+			context->ProcessKeyDown(Input::KI_TAB, 0);
+			CHECK(context->GetFocusElement()->GetId() == ids[0]);
+		}
 
 
-	// Reverse direction
-	for (const String& id : ids)
-	{
-		context->ProcessKeyDown(Input::KI_TAB, Input::KM_SHIFT);
-		CHECK(context->GetFocusElement()->GetId() == id);
+		SUBCASE("reverse")
+		{
+			std::reverse(ids.begin(), ids.end());
+			for (const String& id : ids)
+			{
+				context->ProcessKeyDown(Input::KI_TAB, Input::KM_SHIFT);
+				CHECK(context->GetFocusElement()->GetId() == id);
+			}
+
+			// Wrap around (reverse)
+			context->ProcessKeyDown(Input::KI_TAB, Input::KM_SHIFT);
+			CHECK(context->GetFocusElement()->GetId() == ids[0]);
+		}
 	}
 	}
 
 
-	// Wrap around (reverse)
-	context->ProcessKeyDown(Input::KI_TAB, Input::KM_SHIFT);
-	CHECK(context->GetFocusElement()->GetId() == ids[0]);
-
-	// Tab to document
+	SUBCASE("Tab to document")
 	{
 	{
+		Element* element = document->GetElementById("p13");
+		REQUIRE(element);
+		element->Focus();
+
 		document->SetProperty("tab-index", "auto");
 		document->SetProperty("tab-index", "auto");
 		document->UpdateDocument();
 		document->UpdateDocument();
 
 
@@ -151,7 +159,7 @@ TEST_CASE("elementdocument.focus")
 		CHECK(context->GetFocusElement()->GetId() == "body");
 		CHECK(context->GetFocusElement()->GetId() == "body");
 	}
 	}
 
 
-	// Tab from container element
+	SUBCASE("Tab from container element")
 	{
 	{
 		Element* container = document->GetElementById("container");
 		Element* container = document->GetElementById("container");
 		REQUIRE(container);
 		REQUIRE(container);
@@ -165,7 +173,7 @@ TEST_CASE("elementdocument.focus")
 		CHECK(context->GetFocusElement()->GetId() == "p10");
 		CHECK(context->GetFocusElement()->GetId() == "p10");
 	}
 	}
 
 
-	// Single element
+	SUBCASE("Single element")
 	{
 	{
 		document->SetProperty("tab-index", "none");
 		document->SetProperty("tab-index", "none");
 		document->SetInnerRML(R"(<input type="checkbox" id="p1"/> P1)");
 		document->SetInnerRML(R"(<input type="checkbox" id="p1"/> P1)");
@@ -193,7 +201,7 @@ TEST_CASE("elementdocument.focus")
 		CHECK(context->GetFocusElement()->GetId() == "body");
 		CHECK(context->GetFocusElement()->GetId() == "body");
 	}
 	}
 
 
-	// Single, non-tabable element
+	SUBCASE("Single, non-tabable element")
 	{
 	{
 		document->SetProperty("tab-index", "none");
 		document->SetProperty("tab-index", "none");
 		document->SetInnerRML(R"(<div id="child"/>)");
 		document->SetInnerRML(R"(<div id="child"/>)");
@@ -230,6 +238,23 @@ TEST_CASE("elementdocument.focus")
 	}
 	}
 
 
 	document->Close();
 	document->Close();
+	TestsShell::ShutdownShell();
+}
+
+TEST_CASE("load")
+{
+	Context* context = TestsShell::GetContext();
+	REQUIRE(context);
 
 
+	FakeEventListenerInstancer eventListenerInstancer;
+	Factory::RegisterEventListenerInstancer(&eventListenerInstancer);
+
+	ElementDocument* document = context->LoadDocumentFromMemory(document_focus_rml);
+	REQUIRE(document);
+	CHECK_EQ(eventListenerInstancer.GetLastInstancedValue(), "something");
+
+	document->Close();
 	TestsShell::ShutdownShell();
 	TestsShell::ShutdownShell();
 }
 }
+
+TEST_SUITE_END();

+ 34 - 0
Tests/Source/UnitTests/FakeEventListenerInstancer.h

@@ -0,0 +1,34 @@
+#pragma once
+
+#include <RmlUi/Core/EventListener.h>
+#include <RmlUi/Core/EventListenerInstancer.h>
+
+#include <doctest.h>
+
+class FakeEventListener : public Rml::EventListener
+{
+public:
+	virtual void OnDetach(Rml::Element*) override { delete this; }
+	virtual void ProcessEvent(Rml::Event& event) override { event.StopPropagation(); }
+};
+
+class FakeEventListenerInstancer : public Rml::EventListenerInstancer
+{
+public:
+	const Rml::String& GetLastInstancedValue()
+	{
+		if (!last_instanced_value)
+			DOCTEST_FAIL("No event listeners have been instanced so far!");
+		
+		return *last_instanced_value;
+	}
+
+	virtual Rml::EventListener* InstanceEventListener(const Rml::String& value, Rml::Element*) override
+	{
+		last_instanced_value = std::make_unique<Rml::String>(value);
+		return new FakeEventListener();
+	}
+
+private:
+	Rml::UniquePtr<Rml::String> last_instanced_value;
+};