Element.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * This source file is part of RmlUi, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://github.com/mikke89/RmlUi
  5. *
  6. * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  7. * Copyright (c) 2019 The RmlUi Team, and contributors
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28. #include "../Common/Mocks.h"
  29. #include "../Common/TestsShell.h"
  30. #include <RmlUi/Core/Context.h>
  31. #include <RmlUi/Core/Element.h>
  32. #include <RmlUi/Core/ElementDocument.h>
  33. #include <RmlUi/Core/Factory.h>
  34. #include <doctest.h>
  35. using namespace Rml;
  36. static const String document_clone_rml = R"(
  37. <rml>
  38. <head>
  39. <title>Test</title>
  40. <link type="text/rcss" href="/assets/rml.rcss"/>
  41. <link type="text/rcss" href="/assets/invader.rcss"/>
  42. <style>
  43. body
  44. {
  45. left: 0;
  46. top: 0;
  47. right: 0;
  48. bottom: 0;
  49. }
  50. div {
  51. drag: clone;
  52. background-color: #fff;
  53. height: 100px;
  54. }
  55. div.blue {
  56. background-color: #00f;
  57. }
  58. span {
  59. color: red;
  60. }
  61. </style>
  62. </head>
  63. <body>
  64. <div style="background-color: #f00">This is a <span>sample</span>.</div>
  65. </body>
  66. </rml>
  67. )";
  68. TEST_CASE("Element")
  69. {
  70. Context* context = TestsShell::GetContext();
  71. REQUIRE(context);
  72. ElementDocument* document = context->LoadDocumentFromMemory(document_clone_rml);
  73. REQUIRE(document);
  74. document->Show();
  75. context->Update();
  76. context->Render();
  77. TestsShell::RenderLoop();
  78. SUBCASE("Attribute")
  79. {
  80. auto* button = document->AppendChild(document->CreateElement("button"));
  81. SUBCASE("Event listener")
  82. {
  83. namespace tl = trompeloeil;
  84. static constexpr auto ON_CLICK_ATTRIBUTE = "onclick";
  85. static constexpr auto ON_CLICK_VALUE = "moo";
  86. std::vector<UniquePtr<tl::expectation>> expectations;
  87. UniquePtr<MockEventListener> mockEventListener;
  88. const auto configureMockEventListener = [&]()
  89. {
  90. mockEventListener.reset(new MockEventListener());
  91. expectations.emplace_back(NAMED_ALLOW_CALL(*mockEventListener, OnAttach(button)));
  92. expectations.emplace_back(NAMED_ALLOW_CALL(*mockEventListener, OnDetach(button))
  93. .LR_SIDE_EFFECT(mockEventListener.reset()));
  94. };
  95. MockEventListenerInstancer mockEventListenerInstancer;
  96. const auto configureMockEventListenerInstancer = [&](const auto value)
  97. {
  98. expectations.emplace_back(NAMED_REQUIRE_CALL(mockEventListenerInstancer, InstanceEventListener(value, button))
  99. .LR_SIDE_EFFECT(configureMockEventListener())
  100. .LR_RETURN(mockEventListener.get()));
  101. };
  102. Factory::RegisterEventListenerInstancer(&mockEventListenerInstancer);
  103. configureMockEventListenerInstancer(ON_CLICK_VALUE);
  104. button->SetAttribute(ON_CLICK_ATTRIBUTE, ON_CLICK_VALUE);
  105. SUBCASE("Replacement")
  106. {
  107. static constexpr auto REPLACEMENT_ON_CLICK_VALUE = "boo";
  108. configureMockEventListenerInstancer(REPLACEMENT_ON_CLICK_VALUE);
  109. button->SetAttribute(ON_CLICK_ATTRIBUTE, REPLACEMENT_ON_CLICK_VALUE);
  110. }
  111. button->RemoveAttribute(ON_CLICK_ATTRIBUTE);
  112. }
  113. SUBCASE("Simple")
  114. {
  115. static constexpr auto DISABLED_ATTRIBUTE = "disabled";
  116. REQUIRE_FALSE(button->HasAttribute(DISABLED_ATTRIBUTE));
  117. button->SetAttribute(DISABLED_ATTRIBUTE, "");
  118. REQUIRE(button->HasAttribute(DISABLED_ATTRIBUTE));
  119. SUBCASE("Replacement")
  120. {
  121. static constexpr auto VALUE = "something";
  122. button->SetAttribute(DISABLED_ATTRIBUTE, VALUE);
  123. const auto* attributeValue = button->GetAttribute(DISABLED_ATTRIBUTE);
  124. REQUIRE(attributeValue);
  125. REQUIRE(attributeValue->GetType() == Variant::Type::STRING);
  126. CHECK(attributeValue->Get<String>() == VALUE);
  127. }
  128. button->RemoveAttribute(DISABLED_ATTRIBUTE);
  129. CHECK_FALSE(button->HasAttribute(DISABLED_ATTRIBUTE));
  130. }
  131. }
  132. SUBCASE("CloneDrag")
  133. {
  134. // Simulate input for mouse click and drag
  135. context->ProcessMouseMove(10, 10, 0);
  136. context->Update();
  137. context->Render();
  138. context->ProcessMouseButtonDown(0, 0);
  139. context->Update();
  140. context->Render();
  141. // This should initiate a drag clone.
  142. context->ProcessMouseMove(10, 11, 0);
  143. context->Update();
  144. context->Render();
  145. context->ProcessMouseButtonUp(0, 0);
  146. }
  147. SUBCASE("CloneManual")
  148. {
  149. Element* element = document->GetFirstChild();
  150. REQUIRE(element->GetProperty<String>("background-color") == "255, 0, 0, 255");
  151. CHECK(element->Clone()->GetProperty<String>("background-color") == "255, 0, 0, 255");
  152. element->SetProperty("background-color", "#0f0");
  153. CHECK(element->Clone()->GetProperty<String>("background-color") == "0, 255, 0, 255");
  154. element->RemoveProperty("background-color");
  155. Element* clone = document->AppendChild(element->Clone());
  156. context->Update();
  157. CHECK(clone->GetProperty<String>("background-color") == "255, 255, 255, 255");
  158. element->SetClass("blue", true);
  159. clone = document->AppendChild(element->Clone());
  160. context->Update();
  161. CHECK(clone->GetProperty<String>("background-color") == "0, 0, 255, 255");
  162. }
  163. SUBCASE("SetInnerRML")
  164. {
  165. Element* element = document->GetFirstChild();
  166. CHECK(element->GetInnerRML() == "This is a <span>sample</span>.");
  167. element->SetInnerRML("text");
  168. CHECK(element->GetInnerRML() == "text");
  169. const char* inner_rml = R"(before<div class="blue">child</div>after)";
  170. element->SetInnerRML(inner_rml);
  171. CHECK(element->GetInnerRML() == inner_rml);
  172. ElementPtr element_ptr = document->CreateElement("div");
  173. CHECK(element_ptr->GetInnerRML() == "");
  174. element_ptr->SetInnerRML("text");
  175. CHECK(element_ptr->GetInnerRML() == "text");
  176. }
  177. document->Close();
  178. TestsShell::ShutdownShell();
  179. }