summaryrefslogtreecommitdiffstats
path: root/tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp')
-rw-r--r--tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp b/tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp
new file mode 100644
index 000000000..c2d8717e5
--- /dev/null
+++ b/tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp
@@ -0,0 +1,228 @@
+
+#include "Globals.h"
+#include <thread>
+#include "BlockTypeRegistry.h"
+#include "../TestHelpers.h"
+
+
+
+
+/** Dummy BlockState implementation */
+class BlockState
+{
+public:
+ BlockState() = default;
+};
+
+
+
+
+/** Dummy cBlockHandler implementation that allows simple checking for equality through mIdent. */
+class cBlockHandler
+{
+public:
+ cBlockHandler(UInt32 aIdent):
+ mIdent(aIdent)
+ {
+ }
+
+ UInt32 mIdent;
+};
+
+
+
+
+
+/** Tests simple block type name registration.
+Registers a block type, checks that the type is then registered. */
+static void testSimpleReg()
+{
+ LOGD("Testing simple registration...");
+
+ // Register the block type:
+ BlockTypeRegistry reg;
+ AString blockTypeName("test:block1");
+ AString pluginName("testPlugin");
+ AString hint1("testHint1");
+ AString hint1Value("value1");
+ std::shared_ptr<cBlockHandler> handler(new cBlockHandler(0x12345678));
+ std::map<AString, AString> hints = {{hint1, hint1Value}, {"testHint2", "value2"}};
+ std::map<AString, BlockInfo::HintCallback> hintCallbacks;
+ reg.registerBlockType(pluginName, blockTypeName, handler, hints, hintCallbacks);
+
+ // Query the registration:
+ auto blockInfo = reg.blockInfo(blockTypeName);
+ TEST_NOTEQUAL(blockInfo, nullptr);
+ TEST_EQUAL(blockInfo->blockTypeName(), blockTypeName);
+ TEST_EQUAL(blockInfo->pluginName(), pluginName);
+ TEST_EQUAL(blockInfo->handler(), handler);
+ TEST_EQUAL(blockInfo->hintValue(hint1, BlockState()), hint1Value);
+ TEST_EQUAL(blockInfo->hintValue("nonexistent", BlockState()), "");
+}
+
+
+
+
+
+/** Tests that the plugin-based information is used correctly for registration.
+Registers two different block types with two different plugins, then tries to re-register them from a different plugin.
+Finally removes the registration through removeAllByPlugin() and checks its success. */
+static void testPlugins()
+{
+ LOGD("Testing plugin-based checks / removal...");
+
+ // Register the block types:
+ BlockTypeRegistry reg;
+ AString blockTypeName1("test:block1");
+ AString pluginName1("testPlugin1");
+ AString hint1("testHint1");
+ AString hint1Value("value1");
+ std::shared_ptr<cBlockHandler> handler1(new cBlockHandler(1));
+ std::map<AString, AString> hints = {{hint1, hint1Value}, {"testHint2", "value2"}};
+ std::map<AString, BlockInfo::HintCallback> hintCallbacks;
+ reg.registerBlockType(pluginName1, blockTypeName1, handler1, hints, hintCallbacks);
+ AString blockTypeName2("test:block2");
+ AString pluginName2("testPlugin2");
+ std::shared_ptr<cBlockHandler> handler2(new cBlockHandler(2));
+ reg.registerBlockType(pluginName2, blockTypeName2, handler2, hints, hintCallbacks);
+
+ // Test the refusal to register under a different plugin:
+ TEST_THROWS(reg.registerBlockType(pluginName2, blockTypeName1, handler2, hints, hintCallbacks), BlockTypeRegistry::AlreadyRegisteredException);
+ TEST_EQUAL(reg.blockInfo(blockTypeName1)->handler()->mIdent, 1); // Did we overwrite the old registration?
+ reg.registerBlockType(pluginName1, blockTypeName1, handler1, hints, hintCallbacks); // Re-registering must succeed
+
+ // Unregister by plugin, then re-register from a different plugin:
+ reg.removeAllByPlugin(pluginName1);
+ TEST_EQUAL(reg.blockInfo(blockTypeName1), nullptr); // Unregistered successfully
+ TEST_NOTEQUAL(reg.blockInfo(blockTypeName2), nullptr); // Didn't unregister from the other plugin
+ std::shared_ptr<cBlockHandler> handler3(new cBlockHandler(3));
+ reg.registerBlockType(pluginName2, blockTypeName1, handler3, hints, hintCallbacks);
+ TEST_NOTEQUAL(reg.blockInfo(blockTypeName1), nullptr); // Registered successfully
+ TEST_EQUAL(reg.blockInfo(blockTypeName1)->pluginName(), pluginName2);
+ TEST_EQUAL(reg.blockInfo(blockTypeName1)->handler()->mIdent, 3);
+ TEST_EQUAL(reg.blockInfo(blockTypeName2)->handler()->mIdent, 2);
+ reg.removeAllByPlugin(pluginName2);
+ TEST_EQUAL(reg.blockInfo(blockTypeName1), nullptr); // Unregistered successfully
+ TEST_EQUAL(reg.blockInfo(blockTypeName2), nullptr); // Unregistered successfully
+}
+
+
+
+
+/** Tests that the callback-based hints work properly. */
+static void testHintCallbacks()
+{
+ LOGD("Testing hint callbacks...");
+
+ // Register the block type:
+ BlockTypeRegistry reg;
+ AString blockTypeName("test:block1");
+ AString pluginName("testPlugin");
+ AString hint1("testHint1");
+ AString hint1Value("value1");
+ AString hc1("hintCallback1");
+ int callbackCount = 0;
+ auto callback1 = [&callbackCount](const AString & aBlockType, const BlockState & aBlockState)
+ {
+ callbackCount = callbackCount + 1;
+ return aBlockType + "_hint";
+ };
+ std::shared_ptr<cBlockHandler> handler(new cBlockHandler(0x12345678));
+ std::map<AString, AString> hints = {{hint1, hint1Value}, {"testHint2", "value2"}};
+ std::map<AString, BlockInfo::HintCallback> hintCallbacks = {{hc1, callback1}};
+ reg.registerBlockType(pluginName, blockTypeName, handler, hints, hintCallbacks);
+
+ // Check that querying the hint using a callback works:
+ TEST_EQUAL(reg.blockInfo(blockTypeName)->hintValue(hc1, BlockState()), blockTypeName + "_hint");
+ TEST_EQUAL(callbackCount, 1); // Called exactly once
+}
+
+
+
+
+
+/** Tests whether thread-locking works properly by running two threads,
+one constantly (re-)registering and the other one constantly querying the same block type. */
+static void testThreadLocking()
+{
+ LOGD("Testing thread locking...");
+
+ // Register the block type:
+ BlockTypeRegistry reg;
+ AString blockTypeName("test:block1");
+ AString pluginName("testPlugin");
+ AString hint1("testHint1");
+ AString hint1Value("value1");
+ std::shared_ptr<cBlockHandler> handler(new cBlockHandler(0x12345678));
+ std::map<AString, AString> hints = {{hint1, hint1Value}, {"testHint2", "value2"}};
+ std::map<AString, BlockInfo::HintCallback> hintCallbacks;
+ reg.registerBlockType(pluginName, blockTypeName, handler, hints, hintCallbacks);
+
+ // Run the two threads for at least a second:
+ auto endTime = time(nullptr) + 2;
+ auto keepRegistering = [&]()
+ {
+ while (time(nullptr) < endTime)
+ {
+ reg.registerBlockType(pluginName, blockTypeName, handler, hints, hintCallbacks);
+ }
+ };
+ auto keepQuerying = [&]()
+ {
+ unsigned numQueries = 0;
+ while (time(nullptr) < endTime)
+ {
+ TEST_NOTEQUAL(reg.blockInfo(blockTypeName), nullptr);
+ numQueries += 1;
+ }
+ LOGD("%u queries have been executed", numQueries);
+ };
+ std::thread thr1(keepRegistering);
+ std::thread thr2(keepQuerying);
+ thr1.join();
+ thr2.join();
+}
+
+
+
+
+
+static void testBlockTypeRegistry()
+{
+ testSimpleReg();
+ testPlugins();
+ testHintCallbacks();
+ testThreadLocking();
+}
+
+
+
+
+
+int main()
+{
+ LOGD("BlockTypeRegistryTest started");
+
+ try
+ {
+ testBlockTypeRegistry();
+ }
+ catch (const TestException & exc)
+ {
+ LOGERROR("BlockTypeRegistryTest has failed, an unhandled exception was thrown: %s", exc.mMessage.c_str());
+ return 1;
+ }
+ catch (...)
+ {
+ LOGERROR("BlockTypeRegistryTest has failed, an unhandled exception was thrown.");
+ return 1;
+ }
+
+ LOGD("BlockTypeRegistryTest finished");
+
+ return 0;
+}
+
+
+
+