OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 * Copyright (C) 2006-2016 Eyeo GmbH |
| 4 * |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify |
| 6 * it under the terms of the GNU General Public License version 3 as |
| 7 * published by the Free Software Foundation. |
| 8 * |
| 9 * Adblock Plus is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. |
| 13 * |
| 14 * You should have received a copy of the GNU General Public License |
| 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| 16 */ |
| 17 |
| 18 #include <exception> |
| 19 #include <gtest/gtest.h> |
| 20 #include "../../src/plugin/DetachedInitialization.h" |
| 21 |
| 22 // Initializer that does nothing |
| 23 void NullFunction() |
| 24 {} |
| 25 |
| 26 // Initializer that always throws |
| 27 const std::string failMessage = "initializer failed on purpose"; |
| 28 void FailFunction() |
| 29 { |
| 30 throw std::runtime_error(failMessage); |
| 31 } |
| 32 |
| 33 /* |
| 34 * The destructor has to be able to block to wait for the initializer |
| 35 * This test ensures that it doesn't block unnecessarily. |
| 36 */ |
| 37 TEST(DetachedInitializer, DestructorDoesNotBlockAfterNoActivity) |
| 38 { |
| 39 DetachedInitializer<NullFunction> x; |
| 40 } |
| 41 |
| 42 TEST(DetachedInitializer, NullInstance) |
| 43 { |
| 44 ASSERT_NO_THROW( |
| 45 { |
| 46 DetachedInitializer<NullFunction> x; |
| 47 x.SpawnInitializer(); |
| 48 x.EnsureInitialized(); |
| 49 } |
| 50 ); |
| 51 } |
| 52 |
| 53 /* |
| 54 * This test illustrates a defect in Google Test. |
| 55 * This test fails with a message that the test threw an exception. |
| 56 * The exception message is the one thrown by FailFunction. |
| 57 * It does not fail, importantly, because SpawnInitializer() throws. |
| 58 * This can be verified in the debugger. |
| 59 * |
| 60 * It's disabled in the present code base so it doesn't break the unit test. |
| 61 * Check this test again when we upgrade past GTest 1.60 and the VS 2012 toolset
. |
| 62 */ |
| 63 TEST(DetachedInitializer, DISABLED_EnsureInitializedThrowingGtestDefectIllustrat
ion) |
| 64 { |
| 65 DetachedInitializer<FailFunction> x; |
| 66 bool threw = false; |
| 67 try |
| 68 { |
| 69 x.SpawnInitializer(); |
| 70 } |
| 71 catch (...) |
| 72 { |
| 73 threw = true; |
| 74 FAIL() << "SpawnInitializer() threw"; |
| 75 } |
| 76 ASSERT_FALSE(threw); |
| 77 } |
| 78 |
| 79 /* |
| 80 * This test fails because of a defect in Google Test. |
| 81 * It's disabled at present, but should be enabled when the previous test is wor
king. |
| 82 */ |
| 83 TEST(DetachedInitializer, DISABLED_EnsureInitializedThrowing) |
| 84 { |
| 85 DetachedInitializer<FailFunction> x; |
| 86 try |
| 87 { |
| 88 x.SpawnInitializer(); |
| 89 } |
| 90 catch (...) |
| 91 { |
| 92 FAIL() << "SpawnInitializer() threw"; |
| 93 return; |
| 94 } |
| 95 try |
| 96 { |
| 97 x.EnsureInitialized(); |
| 98 FAIL() << "EnsureInitialized() did not throw"; |
| 99 } |
| 100 catch (std::runtime_error& e) |
| 101 { |
| 102 ASSERT_EQ(failMessage, e.what()); |
| 103 } |
| 104 } |
| 105 |
| 106 /* |
| 107 * Resetable version of DetachedInitializer |
| 108 */ |
| 109 template<void(&F)()> |
| 110 class DidReset |
| 111 : public DetachedInitializer<F> |
| 112 { |
| 113 public: |
| 114 void Reset() |
| 115 { |
| 116 isInitializationComplete.store(false, std::memory_order_relaxed); |
| 117 hasInitializerStarted.store(false, std::memory_order_relaxed); |
| 118 initializerException = nullptr; |
| 119 // Lock and unlock the mutex to clear any previous state |
| 120 // It will also detect a locked mutex left over from a previous test. |
| 121 mutex.lock(); |
| 122 mutex.unlock(); |
| 123 } |
| 124 }; |
| 125 |
| 126 /* |
| 127 * Uses designated implementation pattern of DetachedInitializer |
| 128 */ |
| 129 struct DeferredIncrementingInitializer |
| 130 { |
| 131 static int initializedCount; |
| 132 |
| 133 static void Incrementer() |
| 134 { |
| 135 ++initializedCount; |
| 136 } |
| 137 |
| 138 typedef DidReset<Incrementer> InitializerType; |
| 139 static InitializerType di; |
| 140 |
| 141 public: |
| 142 DeferredIncrementingInitializer() |
| 143 { |
| 144 di.SpawnInitializer(); |
| 145 } |
| 146 |
| 147 static void ResetClass() |
| 148 { |
| 149 initializedCount = 0; |
| 150 di.Reset(); |
| 151 } |
| 152 |
| 153 static int GetInitializerCount () |
| 154 { |
| 155 di.EnsureInitialized(); |
| 156 return initializedCount; |
| 157 } |
| 158 }; |
| 159 DeferredIncrementingInitializer::InitializerType DeferredIncrementingInitializer
::di; |
| 160 int DeferredIncrementingInitializer::initializedCount = 0; |
| 161 |
| 162 TEST(DetachedInitializer, Single) |
| 163 { |
| 164 DeferredIncrementingInitializer::ResetClass(); |
| 165 DeferredIncrementingInitializer x; |
| 166 ASSERT_EQ(1, DeferredIncrementingInitializer::GetInitializerCount()); |
| 167 } |
| 168 |
| 169 TEST(DetachedInitializer, Two) |
| 170 { |
| 171 DeferredIncrementingInitializer::ResetClass(); |
| 172 DeferredIncrementingInitializer x; |
| 173 DeferredIncrementingInitializer y; |
| 174 ASSERT_EQ(1, DeferredIncrementingInitializer::GetInitializerCount()); |
| 175 } |
| 176 |
| 177 /* |
| 178 * This test implicitly calls EnsureInitialized before the second call to SpawnI
nitializer. |
| 179 */ |
| 180 TEST(DetachedInitializer, TwoInterleaved) |
| 181 { |
| 182 DeferredIncrementingInitializer::ResetClass(); |
| 183 DeferredIncrementingInitializer x; |
| 184 EXPECT_EQ(1, DeferredIncrementingInitializer::GetInitializerCount()); |
| 185 DeferredIncrementingInitializer y; |
| 186 ASSERT_EQ(1, DeferredIncrementingInitializer::GetInitializerCount()); |
| 187 } |
| 188 |
| 189 TEST(DetachedInitializer, Many) |
| 190 { |
| 191 DeferredIncrementingInitializer::ResetClass(); |
| 192 const int many = 1000000; |
| 193 for (int j = 0; j < many;++j) |
| 194 { |
| 195 DeferredIncrementingInitializer x; |
| 196 } |
| 197 ASSERT_EQ(1, DeferredIncrementingInitializer::GetInitializerCount()); |
| 198 } |
OLD | NEW |