Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: test/plugin/DetachedInitializationTest.cpp

Issue 29332660: Issue #3391 - Add detached initialization class
Patch Set: Created Dec. 14, 2015, 6:06 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« src/plugin/DetachedInitialization.h ('K') | « src/plugin/DetachedInitialization.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/plugin/DetachedInitializationTest.cpp
===================================================================
new file mode 100644
--- /dev/null
+++ b/test/plugin/DetachedInitializationTest.cpp
@@ -0,0 +1,198 @@
+/*
+ * This file is part of Adblock Plus <https://adblockplus.org/>,
+ * Copyright (C) 2006-2015 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <exception>
+#include <gtest/gtest.h>
+#include "../../src/plugin/DetachedInitialization.h"
+
+// Initializer that does nothing
+void NullFunction()
+{}
+
+// Initializer that always throws
+const std::string failMessage = "initializer failed on purpose";
+void FailFunction()
+{
+ throw std::runtime_error(failMessage);
+}
+
+/*
+ * The destructor has to be able to block to wait for the initializer
+ * This test ensures that it doesn't block unnecessarily.
+ */
+TEST(DetachedInitializer, DestructorDoesNotBlockAfterNoActivity)
+{
+ DetachedInitializer<NullFunction> x;
+}
+
+TEST(DetachedInitializer, NullInstance)
+{
+ ASSERT_NO_THROW(
+ {
+ DetachedInitializer<NullFunction> x;
+ x.SpawnInitializer();
+ x.EnsureInitialized();
+ }
+ );
+}
+
+/*
+ * This test illustrates a defect in Google Test.
+ * This test fails with a message that the test threw an exception.
+ * The exception message is the one thrown by FailFunction.
+ * It does not fail, importantly, because SpawnInitializer() throws.
+ * This can be verified in the debugger.
+ *
+ * It's disabled in the present code base so it doesn't break the unit test.
+ * Check this test again when we upgrade past GTest 1.60 and the VS 2012 toolset.
+ */
+TEST(DetachedInitializer, DISABLED_EnsureInitializedThrowingGtestDefectIllustration)
+{
+ DetachedInitializer<FailFunction> x;
+ bool threw = false;
+ try
+ {
+ x.SpawnInitializer();
+ }
+ catch (...)
+ {
+ threw = true;
+ FAIL() << "SpawnInitializer() threw";
+ }
+ ASSERT_FALSE(threw);
+}
+
+/*
+ * This test fails because of a defect in Google Test.
+ * It's disabled at present, but should be enabled when the previous test is working.
+ */
+TEST(DetachedInitializer, DISABLED_EnsureInitializedThrowing)
+{
+ DetachedInitializer<FailFunction> x;
+ try
+ {
+ x.SpawnInitializer();
+ }
+ catch (...)
+ {
+ FAIL() << "SpawnInitializer() threw";
+ return;
+ }
+ try
+ {
+ x.EnsureInitialized();
+ FAIL() << "EnsureInitialized() did not throw";
+ }
+ catch (std::runtime_error& e)
+ {
+ ASSERT_EQ(failMessage, e.what());
+ }
+}
+
+/*
+ * Resetable version of DetachedInitializer
+ */
+template<void(&F)()>
+class DidReset
+ : public DetachedInitializer<F>
+{
+public:
+ void Reset()
+ {
+ isInitializationComplete.store(false, std::memory_order_relaxed);
+ hasInitializerStarted.store(false, std::memory_order_relaxed);
+ initializerException = nullptr;
+ // Lock and unlock the mutex to clear any previous state
+ // It will also detect a locked mutex left over from a previous test.
+ mutex.lock();
+ mutex.unlock();
+ }
+};
+
+/*
+ * Uses designated implementation pattern of DetachedInitializer
+ */
+struct DeferredIncrementingInitializer
+{
+ static int initializedCount;
+
+ static void Incrementer()
+ {
+ ++initializedCount;
+ }
+
+ typedef DidReset<Incrementer> InitializerType;
+ static InitializerType di;
+
+public:
+ DeferredIncrementingInitializer()
+ {
+ di.SpawnInitializer();
+ }
+
+ static void ResetClass()
+ {
+ initializedCount = 0;
+ di.Reset();
+ }
+
+ static int GetInitializerCount ()
+ {
+ di.EnsureInitialized();
+ return initializedCount;
+ }
+};
+DeferredIncrementingInitializer::InitializerType DeferredIncrementingInitializer::di;
+int DeferredIncrementingInitializer::initializedCount = 0;
+
+TEST(DetachedInitializer, Single)
+{
+ DeferredIncrementingInitializer::ResetClass();
+ DeferredIncrementingInitializer x;
+ ASSERT_EQ(1, DeferredIncrementingInitializer::GetInitializerCount());
+}
+
+TEST(DetachedInitializer, Two)
+{
+ DeferredIncrementingInitializer::ResetClass();
+ DeferredIncrementingInitializer x;
+ DeferredIncrementingInitializer y;
+ ASSERT_EQ(1, DeferredIncrementingInitializer::GetInitializerCount());
+}
+
+/*
+ * This test implicitly calls EnsureInitialized before the second call to SpawnInitializer.
+ */
+TEST(DetachedInitializer, TwoInterleaved)
+{
+ DeferredIncrementingInitializer::ResetClass();
+ DeferredIncrementingInitializer x;
+ EXPECT_EQ(1, DeferredIncrementingInitializer::GetInitializerCount());
+ DeferredIncrementingInitializer y;
+ ASSERT_EQ(1, DeferredIncrementingInitializer::GetInitializerCount());
+}
+
+TEST(DetachedInitializer, Many)
+{
+ DeferredIncrementingInitializer::ResetClass();
+ const int many = 1000000;
+ for (int j = 0; j < many;++j)
+ {
+ DeferredIncrementingInitializer x;
+ }
+ ASSERT_EQ(1, DeferredIncrementingInitializer::GetInitializerCount());
+}
« src/plugin/DetachedInitialization.h ('K') | « src/plugin/DetachedInitialization.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld