Browse Source

Refactor existing unit tests using Trompeloeil

ZombieRaccoon 4 years ago
parent
commit
53e2f0c5a6

+ 21 - 0
Tests/Source/Common/Mocks.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include <RmlUi/Core/EventListener.h>
+#include <RmlUi/Core/EventListenerInstancer.h>
+
+#include <doctest.h>
+#include <doctest/trompeloeil.hpp>
+
+class MockEventListener : public trompeloeil::mock_interface<Rml::EventListener>
+{
+public:
+	IMPLEMENT_MOCK1(OnAttach);
+	IMPLEMENT_MOCK1(OnDetach);
+	IMPLEMENT_MOCK1(ProcessEvent);
+};
+
+class MockEventListenerInstancer : public trompeloeil::mock_interface<Rml::EventListenerInstancer>
+{
+public:
+	IMPLEMENT_MOCK2(InstanceEventListener);
+};

+ 39 - 28
Tests/Source/UnitTests/Element.cpp

@@ -26,8 +26,8 @@
  *
  *
  */
  */
 
 
+#include "../Common/Mocks.h"
 #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>
@@ -67,7 +67,7 @@ static const String document_clone_rml = R"(
 </rml>
 </rml>
 )";
 )";
 
 
-TEST_CASE("element")
+TEST_CASE("Element")
 {
 {
 	Context* context = TestsShell::GetContext();
 	Context* context = TestsShell::GetContext();
 	REQUIRE(context);
 	REQUIRE(context);
@@ -80,64 +80,75 @@ TEST_CASE("element")
 	context->Render();
 	context->Render();
 
 
 	TestsShell::RenderLoop();
 	TestsShell::RenderLoop();
-	SUBCASE("attribute")
+	SUBCASE("Attribute")
 	{
 	{
 		auto* button = document->AppendChild(document->CreateElement("button"));
 		auto* button = document->AppendChild(document->CreateElement("button"));
-		SUBCASE("event listener")
+		SUBCASE("Event listener")
 		{
 		{
-			static constexpr auto CLICK_EVENT = "click";
+			namespace tl = trompeloeil;
 			static constexpr auto ON_CLICK_ATTRIBUTE = "onclick";
 			static constexpr auto ON_CLICK_ATTRIBUTE = "onclick";
 			static constexpr auto ON_CLICK_VALUE = "moo";
 			static constexpr auto ON_CLICK_VALUE = "moo";
 
 
-			FakeEventListenerInstancer eventListenerInstancer;
-			Factory::RegisterEventListenerInstancer(&eventListenerInstancer);
+			std::vector<UniquePtr<tl::expectation>> expectations;
 
 
-			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")
+			UniquePtr<MockEventListener> mockEventListener;
+			const auto configureMockEventListener = [&]()
 			{
 			{
-				button->RemoveAttribute(ON_CLICK_ATTRIBUTE);
-				CHECK(button->DispatchEvent(CLICK_EVENT, {}));
-			}
+				mockEventListener.reset(new MockEventListener());
+				expectations.emplace_back(NAMED_ALLOW_CALL(*mockEventListener, OnAttach(button)));
+				expectations.emplace_back(NAMED_ALLOW_CALL(*mockEventListener, OnDetach(button))
+					.LR_SIDE_EFFECT(mockEventListener.reset()));
+			};
+
+			MockEventListenerInstancer mockEventListenerInstancer;
+			const auto configureMockEventListenerInstancer = [&](const auto value)
+			{
+				expectations.emplace_back(NAMED_REQUIRE_CALL(mockEventListenerInstancer, InstanceEventListener(value, button))
+					.LR_SIDE_EFFECT(configureMockEventListener())
+					.LR_RETURN(mockEventListener.get()));
+			};
 
 
-			SUBCASE("replacement")
+			Factory::RegisterEventListenerInstancer(&mockEventListenerInstancer);
+
+			configureMockEventListenerInstancer(ON_CLICK_VALUE);
+			button->SetAttribute(ON_CLICK_ATTRIBUTE, ON_CLICK_VALUE);
+
+			SUBCASE("Replacement")
 			{
 			{
 				static constexpr auto REPLACEMENT_ON_CLICK_VALUE = "boo";
 				static constexpr auto REPLACEMENT_ON_CLICK_VALUE = "boo";
+
+				configureMockEventListenerInstancer(REPLACEMENT_ON_CLICK_VALUE);
 				button->SetAttribute(ON_CLICK_ATTRIBUTE, REPLACEMENT_ON_CLICK_VALUE);
 				button->SetAttribute(ON_CLICK_ATTRIBUTE, REPLACEMENT_ON_CLICK_VALUE);
-				REQUIRE_EQ(eventListenerInstancer.GetLastInstancedValue(), REPLACEMENT_ON_CLICK_VALUE);
-				CHECK_FALSE(button->DispatchEvent(CLICK_EVENT, {}));
 			}
 			}
+
+			button->RemoveAttribute(ON_CLICK_ATTRIBUTE);
 		}
 		}
 
 
-		SUBCASE("simple")
+		SUBCASE("Simple")
 		{
 		{
 			static constexpr auto DISABLED_ATTRIBUTE = "disabled";
 			static constexpr auto DISABLED_ATTRIBUTE = "disabled";
+
 			REQUIRE_FALSE(button->HasAttribute(DISABLED_ATTRIBUTE));
 			REQUIRE_FALSE(button->HasAttribute(DISABLED_ATTRIBUTE));
 			button->SetAttribute(DISABLED_ATTRIBUTE, "");
 			button->SetAttribute(DISABLED_ATTRIBUTE, "");
 			REQUIRE(button->HasAttribute(DISABLED_ATTRIBUTE));
 			REQUIRE(button->HasAttribute(DISABLED_ATTRIBUTE));
 
 
-			SUBCASE("removal")
-			{
-				button->RemoveAttribute(DISABLED_ATTRIBUTE);
-				CHECK_FALSE(button->HasAttribute(DISABLED_ATTRIBUTE));
-			}
-
-			SUBCASE("replacement")
+			SUBCASE("Replacement")
 			{
 			{
 				static constexpr auto VALUE = "something";
 				static constexpr auto VALUE = "something";
+
 				button->SetAttribute(DISABLED_ATTRIBUTE, VALUE);
 				button->SetAttribute(DISABLED_ATTRIBUTE, VALUE);
 				const auto* attributeValue = button->GetAttribute(DISABLED_ATTRIBUTE);
 				const auto* attributeValue = button->GetAttribute(DISABLED_ATTRIBUTE);
 				REQUIRE(attributeValue);
 				REQUIRE(attributeValue);
 				REQUIRE(attributeValue->GetType() == Variant::Type::STRING);
 				REQUIRE(attributeValue->GetType() == Variant::Type::STRING);
 				CHECK(attributeValue->Get<String>() == VALUE);
 				CHECK(attributeValue->Get<String>() == VALUE);
 			}
 			}
+
+			button->RemoveAttribute(DISABLED_ATTRIBUTE);
+			CHECK_FALSE(button->HasAttribute(DISABLED_ATTRIBUTE));
 		}
 		}
 	}
 	}
 
 
-	SUBCASE("clone")
+	SUBCASE("Clone")
 	{
 	{
 		// Simulate input for mouse click and drag
 		// Simulate input for mouse click and drag
 		context->ProcessMouseMove(10, 10, 0);
 		context->ProcessMouseMove(10, 10, 0);

+ 27 - 10
Tests/Source/UnitTests/ElementDocument.cpp

@@ -26,8 +26,8 @@
  *
  *
  */
  */
 
 
+#include "../Common/Mocks.h"
 #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>
@@ -96,9 +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_SUITE_BEGIN("ElementDocument");
 
 
-TEST_CASE("focus")
+TEST_CASE("Focus")
 {
 {
 	Context* context = TestsShell::GetContext();
 	Context* context = TestsShell::GetContext();
 	REQUIRE(context);
 	REQUIRE(context);
@@ -111,14 +111,14 @@ TEST_CASE("focus")
 	context->Render();
 	context->Render();
 
 
 	TestsShell::RenderLoop();
 	TestsShell::RenderLoop();
-	SUBCASE("tab order")
+	SUBCASE("Tab order")
 	{
 	{
 		StringList ids;
 		StringList ids;
 		StringUtilities::ExpandString(ids, focus_forward, ' ');
 		StringUtilities::ExpandString(ids, focus_forward, ' ');
 		REQUIRE(!ids.empty());
 		REQUIRE(!ids.empty());
 
 
 		document->Focus();
 		document->Focus();
-		SUBCASE("forward")
+		SUBCASE("Forward")
 		{
 		{
 			for(const String& id : ids)
 			for(const String& id : ids)
 			{
 			{
@@ -131,7 +131,7 @@ TEST_CASE("focus")
 			CHECK(context->GetFocusElement()->GetId() == ids[0]);
 			CHECK(context->GetFocusElement()->GetId() == ids[0]);
 		}
 		}
 
 
-		SUBCASE("reverse")
+		SUBCASE("Reverse")
 		{
 		{
 			std::reverse(ids.begin(), ids.end());
 			std::reverse(ids.begin(), ids.end());
 			for (const String& id : ids)
 			for (const String& id : ids)
@@ -241,17 +241,34 @@ TEST_CASE("focus")
 	TestsShell::ShutdownShell();
 	TestsShell::ShutdownShell();
 }
 }
 
 
-TEST_CASE("load")
+TEST_CASE("Load")
 {
 {
+	namespace tl = trompeloeil;
+	constexpr auto BODY_TAG = "body";
+
 	Context* context = TestsShell::GetContext();
 	Context* context = TestsShell::GetContext();
 	REQUIRE(context);
 	REQUIRE(context);
 
 
-	FakeEventListenerInstancer eventListenerInstancer;
-	Factory::RegisterEventListenerInstancer(&eventListenerInstancer);
+	MockEventListener mockEventListener;
+	MockEventListenerInstancer mockEventListenerInstancer;
+
+	tl::sequence sequence;
+	REQUIRE_CALL(mockEventListenerInstancer, InstanceEventListener("something", tl::_))
+		.WITH(_2->GetTagName() == BODY_TAG)
+		.IN_SEQUENCE(sequence)
+		.LR_RETURN(&mockEventListener);
+
+	ALLOW_CALL(mockEventListener, OnAttach(tl::_));
+	ALLOW_CALL(mockEventListener, OnDetach(tl::_));
+
+	REQUIRE_CALL(mockEventListener, ProcessEvent(tl::_))
+		.WITH(_1.GetId() == EventId::Load && _1.GetTargetElement()->GetTagName() == BODY_TAG)
+		.IN_SEQUENCE(sequence);
+
+	Factory::RegisterEventListenerInstancer(&mockEventListenerInstancer);
 
 
 	ElementDocument* document = context->LoadDocumentFromMemory(document_focus_rml);
 	ElementDocument* document = context->LoadDocumentFromMemory(document_focus_rml);
 	REQUIRE(document);
 	REQUIRE(document);
-	CHECK_EQ(eventListenerInstancer.GetLastInstancedValue(), "something");
 
 
 	document->Close();
 	document->Close();
 	TestsShell::ShutdownShell();
 	TestsShell::ShutdownShell();

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

@@ -1,34 +0,0 @@
-#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;
-};