2 * Copyright 2017 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <boost/thread/barrier.hpp>
20 #include <glog/logging.h>
22 #include <folly/Singleton.h>
23 #include <folly/experimental/io/FsUtil.h>
24 #include <folly/io/async/EventBase.h>
25 #include <folly/portability/GMock.h>
26 #include <folly/portability/GTest.h>
27 #include <folly/test/SingletonTestStructs.h>
30 #include <folly/Subprocess.h>
33 FOLLY_GCC_DISABLE_WARNING("-Wdeprecated-declarations")
35 using namespace folly;
37 TEST(Singleton, MissingSingleton) {
38 EXPECT_DEATH([]() { auto u = Singleton<UnregisteredWatchdog>::try_get(); }(),
42 struct BasicUsageTag {};
43 template <typename T, typename Tag = detail::DefaultTag>
44 using SingletonBasicUsage = Singleton <T, Tag, BasicUsageTag>;
46 // Exercise some basic codepaths ensuring registration order and
47 // destruction order happen as expected, that instances are created
48 // when expected, etc etc.
49 TEST(Singleton, BasicUsage) {
50 auto& vault = *SingletonVault::singleton<BasicUsageTag>();
52 EXPECT_EQ(vault.registeredSingletonCount(), 0);
53 SingletonBasicUsage<Watchdog> watchdog_singleton;
54 EXPECT_EQ(vault.registeredSingletonCount(), 1);
56 SingletonBasicUsage<ChildWatchdog> child_watchdog_singleton;
57 EXPECT_EQ(vault.registeredSingletonCount(), 2);
59 vault.registrationComplete();
61 // limit a scope to release references so we can destroy them later
63 std::shared_ptr<Watchdog> s1 = SingletonBasicUsage<Watchdog>::try_get();
64 EXPECT_NE(s1, nullptr);
66 std::shared_ptr<Watchdog> s2 = SingletonBasicUsage<Watchdog>::try_get();
67 EXPECT_NE(s2, nullptr);
70 EXPECT_EQ(s1.get(), SingletonBasicUsage<Watchdog>::try_get_fast().get());
72 std::shared_ptr<ChildWatchdog> s3 =
73 SingletonBasicUsage<ChildWatchdog>::try_get();
74 EXPECT_NE(s3, nullptr);
77 EXPECT_EQ(vault.registeredSingletonCount(), 2);
78 EXPECT_EQ(vault.livingSingletonCount(), 2);
81 vault.destroyInstances();
82 EXPECT_EQ(vault.registeredSingletonCount(), 2);
83 EXPECT_EQ(vault.livingSingletonCount(), 0);
86 struct DirectUsageTag {};
87 template <typename T, typename Tag = detail::DefaultTag>
88 using SingletonDirectUsage = Singleton <T, Tag, DirectUsageTag>;
90 TEST(Singleton, DirectUsage) {
91 auto& vault = *SingletonVault::singleton<DirectUsageTag>();
93 EXPECT_EQ(vault.registeredSingletonCount(), 0);
95 // Verify we can get to the underlying singletons via directly using
96 // the singleton definition.
97 SingletonDirectUsage<Watchdog> watchdog;
99 SingletonDirectUsage<Watchdog, TestTag> named_watchdog;
100 EXPECT_EQ(vault.registeredSingletonCount(), 2);
101 vault.registrationComplete();
103 EXPECT_NE(watchdog.try_get(), nullptr);
104 EXPECT_EQ(watchdog.try_get(), SingletonDirectUsage<Watchdog>::try_get());
105 EXPECT_NE(watchdog.try_get(), named_watchdog.try_get());
106 EXPECT_EQ(watchdog.try_get()->livingWatchdogCount(), 2);
108 vault.destroyInstances();
111 struct NamedUsageTag {};
112 template <typename T, typename Tag = detail::DefaultTag>
113 using SingletonNamedUsage = Singleton <T, Tag, NamedUsageTag>;
115 TEST(Singleton, NamedUsage) {
116 auto& vault = *SingletonVault::singleton<NamedUsageTag>();
118 EXPECT_EQ(vault.registeredSingletonCount(), 0);
120 // Define two named Watchdog singletons and one unnamed singleton.
123 typedef detail::DefaultTag Watchdog3;
124 SingletonNamedUsage<Watchdog, Watchdog1> watchdog1_singleton;
125 EXPECT_EQ(vault.registeredSingletonCount(), 1);
126 SingletonNamedUsage<Watchdog, Watchdog2> watchdog2_singleton;
127 EXPECT_EQ(vault.registeredSingletonCount(), 2);
128 SingletonNamedUsage<Watchdog, Watchdog3> watchdog3_singleton;
129 EXPECT_EQ(vault.registeredSingletonCount(), 3);
131 vault.registrationComplete();
133 // Verify our three singletons are distinct and non-nullptr.
134 auto s1 = SingletonNamedUsage<Watchdog, Watchdog1>::try_get();
135 EXPECT_EQ(s1, watchdog1_singleton.try_get());
136 auto s2 = SingletonNamedUsage<Watchdog, Watchdog2>::try_get();
137 EXPECT_EQ(s2, watchdog2_singleton.try_get());
139 auto s3 = SingletonNamedUsage<Watchdog, Watchdog3>::try_get();
140 EXPECT_EQ(s3, watchdog3_singleton.try_get());
144 // Verify the "default" singleton is the same as the DefaultTag-tagged
146 auto s4 = SingletonNamedUsage<Watchdog>::try_get();
147 EXPECT_EQ(s4, watchdog3_singleton.try_get());
150 vault.destroyInstances();
153 struct NaughtyUsageTag {};
154 template <typename T, typename Tag = detail::DefaultTag>
155 using SingletonNaughtyUsage = Singleton <T, Tag, NaughtyUsageTag>;
156 struct NaughtyUsageTag2 {};
157 template <typename T, typename Tag = detail::DefaultTag>
158 using SingletonNaughtyUsage2 = Singleton <T, Tag, NaughtyUsageTag2>;
160 // Some pathological cases such as getting unregistered singletons,
161 // double registration, etc.
162 TEST(Singleton, NaughtyUsage) {
163 auto& vault = *SingletonVault::singleton<NaughtyUsageTag>();
165 vault.registrationComplete();
168 EXPECT_DEATH(Singleton<Watchdog>::try_get(), "");
169 EXPECT_DEATH(SingletonNaughtyUsage<Watchdog>::try_get(), "");
171 vault.destroyInstances();
173 auto& vault2 = *SingletonVault::singleton<NaughtyUsageTag2>();
175 EXPECT_DEATH(SingletonNaughtyUsage2<Watchdog>::try_get(), "");
176 SingletonNaughtyUsage2<Watchdog> watchdog_singleton;
178 // double registration
179 EXPECT_DEATH([]() { SingletonNaughtyUsage2<Watchdog> w2; }(), "");
180 vault2.destroyInstances();
182 // double registration after destroy
183 EXPECT_DEATH([]() { SingletonNaughtyUsage2<Watchdog> w3; }(), "");
186 struct SharedPtrUsageTag {};
187 template <typename T, typename Tag = detail::DefaultTag>
188 using SingletonSharedPtrUsage = Singleton <T, Tag, SharedPtrUsageTag>;
190 // TODO (anob): revisit this test
191 TEST(Singleton, SharedPtrUsage) {
192 struct WatchdogHolder {
195 LOG(ERROR) << "The following log message with stack trace is expected";
199 std::shared_ptr<Watchdog> watchdog;
202 auto& vault = *SingletonVault::singleton<SharedPtrUsageTag>();
204 EXPECT_EQ(vault.registeredSingletonCount(), 0);
205 std::vector<std::unique_ptr<Watchdog>> watchdog_instances;
206 SingletonSharedPtrUsage<Watchdog> watchdog_singleton(
208 watchdog_instances.push_back(std::make_unique<Watchdog>());
209 return watchdog_instances.back().get();
212 // Make sure that only second instance is destroyed. First instance is
213 // expected to be leaked.
214 EXPECT_EQ(watchdog_instances[1].get(), ptr);
215 watchdog_instances[1].reset();
217 EXPECT_EQ(vault.registeredSingletonCount(), 1);
219 SingletonSharedPtrUsage<ChildWatchdog> child_watchdog_singleton;
220 EXPECT_EQ(vault.registeredSingletonCount(), 2);
223 SingletonSharedPtrUsage<Watchdog, ATag> named_watchdog_singleton;
225 SingletonSharedPtrUsage<WatchdogHolder> watchdog_holder_singleton;
227 vault.registrationComplete();
229 // Initilize holder singleton first, so that it's the last one to be
231 watchdog_holder_singleton.try_get();
233 auto s1 = SingletonSharedPtrUsage<Watchdog>::try_get().get();
234 EXPECT_NE(s1, nullptr);
236 auto s2 = SingletonSharedPtrUsage<Watchdog>::try_get().get();
237 EXPECT_NE(s2, nullptr);
241 auto weak_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
243 auto shared_s1 = weak_s1.lock();
244 EXPECT_EQ(shared_s1.get(), s1);
245 EXPECT_EQ(shared_s1.use_count(), 2);
247 auto old_serial = shared_s1->serial_number;
251 SingletonSharedPtrUsage<Watchdog, ATag>::get_weak();
252 auto locked = named_weak_s1.lock();
253 EXPECT_NE(locked.get(), shared_s1.get());
256 // We should release externally locked shared_ptr, otherwise it will be
258 watchdog_holder_singleton.try_get()->watchdog = std::move(shared_s1);
260 LOG(ERROR) << "The following log message regarding shared_ptr is expected";
262 auto start_time = std::chrono::steady_clock::now();
263 vault.destroyInstances();
264 auto duration = std::chrono::steady_clock::now() - start_time;
265 EXPECT_TRUE(duration > std::chrono::seconds{4} &&
266 duration < std::chrono::seconds{6});
268 EXPECT_EQ(vault.registeredSingletonCount(), 4);
269 EXPECT_EQ(vault.livingSingletonCount(), 0);
271 EXPECT_TRUE(weak_s1.expired());
273 auto empty_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
274 EXPECT_FALSE(empty_s1.lock());
276 vault.reenableInstances();
279 // Singleton should be re-created only after reenableInstances() was called.
280 auto new_s1 = SingletonSharedPtrUsage<Watchdog>::try_get();
281 // Track serial number rather than pointer since the memory could be
282 // re-used when we create new_s1.
283 EXPECT_NE(new_s1->serial_number, old_serial);
286 auto new_s1_weak = SingletonSharedPtrUsage<Watchdog>::get_weak();
287 auto new_s1_shared = new_s1_weak.lock();
288 std::thread t([new_s1_shared]() mutable {
289 std::this_thread::sleep_for(std::chrono::seconds{2});
290 new_s1_shared.reset();
292 new_s1_shared.reset();
294 auto start_time = std::chrono::steady_clock::now();
295 vault.destroyInstances();
296 auto duration = std::chrono::steady_clock::now() - start_time;
297 EXPECT_TRUE(duration > std::chrono::seconds{1} &&
298 duration < std::chrono::seconds{3});
300 EXPECT_TRUE(new_s1_weak.expired());
304 // Some classes to test singleton dependencies. NeedySingleton has a
305 // dependency on NeededSingleton, which happens during its
308 template <typename T, typename Tag = detail::DefaultTag>
309 using SingletonNeedy = Singleton <T, Tag, NeedyTag>;
311 struct NeededSingleton {};
312 struct NeedySingleton {
314 auto unused = SingletonNeedy<NeededSingleton>::try_get();
315 EXPECT_NE(unused, nullptr);
319 // Ensure circular dependencies fail -- a singleton that needs itself, whoops.
320 struct SelfNeedyTag {};
321 template <typename T, typename Tag = detail::DefaultTag>
322 using SingletonSelfNeedy = Singleton <T, Tag, SelfNeedyTag>;
324 struct SelfNeedySingleton {
325 SelfNeedySingleton() {
326 auto unused = SingletonSelfNeedy<SelfNeedySingleton>::try_get();
327 EXPECT_NE(unused, nullptr);
331 TEST(Singleton, SingletonDependencies) {
332 SingletonNeedy<NeededSingleton> needed_singleton;
333 SingletonNeedy<NeedySingleton> needy_singleton;
334 auto& needy_vault = *SingletonVault::singleton<NeedyTag>();
336 needy_vault.registrationComplete();
338 EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
339 EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
341 auto needy = SingletonNeedy<NeedySingleton>::try_get();
342 EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
344 SingletonSelfNeedy<SelfNeedySingleton> self_needy_singleton;
345 auto& self_needy_vault = *SingletonVault::singleton<SelfNeedyTag>();
347 self_needy_vault.registrationComplete();
348 EXPECT_DEATH([]() { SingletonSelfNeedy<SelfNeedySingleton>::try_get(); }(),
352 // A test to ensure multiple threads contending on singleton creation
353 // properly wait for creation rather than thinking it is a circular
355 class Slowpoke : public Watchdog {
357 Slowpoke() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); }
360 struct ConcurrencyTag {};
361 template <typename T, typename Tag = detail::DefaultTag>
362 using SingletonConcurrency = Singleton <T, Tag, ConcurrencyTag>;
364 TEST(Singleton, SingletonConcurrency) {
365 auto& vault = *SingletonVault::singleton<ConcurrencyTag>();
366 SingletonConcurrency<Slowpoke> slowpoke_singleton;
367 vault.registrationComplete();
369 std::mutex gatekeeper;
371 auto func = [&gatekeeper]() {
374 auto unused = SingletonConcurrency<Slowpoke>::try_get();
377 EXPECT_EQ(vault.livingSingletonCount(), 0);
378 std::vector<std::thread> threads;
379 for (int i = 0; i < 100; ++i) {
380 threads.emplace_back(func);
382 // If circular dependency checks fail, the unlock would trigger a
383 // crash. Instead, it succeeds, and we have exactly one living
386 for (auto& t : threads) {
389 EXPECT_EQ(vault.livingSingletonCount(), 1);
392 struct ErrorConstructor {
393 static size_t constructCount_;
395 if ((constructCount_++) == 0) {
396 throw std::runtime_error("first time fails");
400 size_t ErrorConstructor::constructCount_(0);
402 struct CreationErrorTag {};
403 template <typename T, typename Tag = detail::DefaultTag>
404 using SingletonCreationError = Singleton<T, Tag, CreationErrorTag>;
406 TEST(Singleton, SingletonCreationError) {
407 SingletonCreationError<ErrorConstructor> error_once_singleton;
408 SingletonVault::singleton<CreationErrorTag>()->registrationComplete();
410 // first time should error out
411 EXPECT_THROW(error_once_singleton.try_get(), std::runtime_error);
413 // second time it'll work fine
414 error_once_singleton.try_get();
418 struct ConcurrencyStressTag {};
419 template <typename T, typename Tag = detail::DefaultTag>
420 using SingletonConcurrencyStress = Singleton <T, Tag, ConcurrencyStressTag>;
422 TEST(Singleton, SingletonConcurrencyStress) {
423 auto& vault = *SingletonVault::singleton<ConcurrencyStressTag>();
424 SingletonConcurrencyStress<Slowpoke> slowpoke_singleton;
425 vault.registrationComplete();
427 std::vector<std::thread> ts;
428 for (size_t i = 0; i < 100; ++i) {
429 ts.emplace_back([&]() {
430 slowpoke_singleton.try_get();
434 for (size_t i = 0; i < 100; ++i) {
435 std::chrono::milliseconds d(20);
437 std::this_thread::sleep_for(d);
438 vault.destroyInstances();
439 std::this_thread::sleep_for(d);
440 vault.destroyInstances();
449 struct EagerInitSyncTag {};
451 template <typename T, typename Tag = detail::DefaultTag>
452 using SingletonEagerInitSync = Singleton<T, Tag, EagerInitSyncTag>;
453 TEST(Singleton, SingletonEagerInitSync) {
454 auto& vault = *SingletonVault::singleton<EagerInitSyncTag>();
455 bool didEagerInit = false;
456 auto sing = SingletonEagerInitSync<std::string>(
457 [&] {didEagerInit = true; return new std::string("foo"); })
459 vault.registrationComplete();
460 EXPECT_FALSE(didEagerInit);
462 EXPECT_TRUE(didEagerInit);
463 sing.get_weak(); // (avoid compile error complaining about unused var 'sing')
467 struct EagerInitAsyncTag {};
469 template <typename T, typename Tag = detail::DefaultTag>
470 using SingletonEagerInitAsync = Singleton<T, Tag, EagerInitAsyncTag>;
471 TEST(Singleton, SingletonEagerInitAsync) {
472 auto& vault = *SingletonVault::singleton<EagerInitAsyncTag>();
473 bool didEagerInit = false;
474 auto sing = SingletonEagerInitAsync<std::string>(
475 [&] {didEagerInit = true; return new std::string("foo"); })
479 vault.registrationComplete();
480 EXPECT_FALSE(didEagerInit);
481 vault.doEagerInitVia(eb, &done);
484 EXPECT_TRUE(didEagerInit);
485 sing.get_weak(); // (avoid compile error complaining about unused var 'sing')
489 class TestEagerInitParallelExecutor : public folly::Executor {
491 explicit TestEagerInitParallelExecutor(const size_t threadCount) {
492 eventBases_.reserve(threadCount);
493 threads_.reserve(threadCount);
494 for (size_t i = 0; i < threadCount; i++) {
495 eventBases_.push_back(std::make_shared<folly::EventBase>());
496 auto eb = eventBases_.back();
497 threads_.emplace_back(std::make_shared<std::thread>(
498 [eb] { eb->loopForever(); }));
502 ~TestEagerInitParallelExecutor() override {
503 for (auto eb : eventBases_) {
504 eb->runInEventBaseThread([eb] { eb->terminateLoopSoon(); });
506 for (auto thread : threads_) {
511 void add(folly::Func func) override {
512 const auto index = (counter_ ++) % eventBases_.size();
513 eventBases_[index]->add(std::move(func));
517 std::vector<std::shared_ptr<folly::EventBase>> eventBases_;
518 std::vector<std::shared_ptr<std::thread>> threads_;
519 std::atomic<size_t> counter_ {0};
524 struct EagerInitParallelTag {};
526 template <typename T, typename Tag = detail::DefaultTag>
527 using SingletonEagerInitParallel = Singleton<T, Tag, EagerInitParallelTag>;
528 TEST(Singleton, SingletonEagerInitParallel) {
529 const static size_t kIters = 1000;
530 const static size_t kThreads = 20;
532 std::atomic<size_t> initCounter;
534 auto& vault = *SingletonVault::singleton<EagerInitParallelTag>();
536 auto sing = SingletonEagerInitParallel<std::string>(
537 [&] {++initCounter; return new std::string(""); })
540 for (size_t i = 0; i < kIters; i++) {
542 // clean up each time
543 vault.destroyInstances();
544 vault.reenableInstances();
547 initCounter.store(0);
550 std::vector<std::shared_ptr<std::thread>> threads;
551 boost::barrier barrier(kThreads);
552 TestEagerInitParallelExecutor exe(kThreads);
553 vault.registrationComplete();
555 EXPECT_EQ(0, initCounter.load());
557 for (size_t j = 0; j < kThreads; j++) {
558 threads.push_back(std::make_shared<std::thread>([&] {
560 vault.doEagerInitVia(exe);
564 for (auto thread : threads) {
569 EXPECT_EQ(1, initCounter.load());
571 sing.get_weak(); // (avoid compile error complaining about unused var)
576 template <typename T, typename Tag = detail::DefaultTag>
577 using SingletonMock = Singleton <T, Tag, MockTag>;
579 // Verify that existing Singleton's can be overridden
580 // using the make_mock functionality.
581 TEST(Singleton, MockTest) {
582 auto& vault = *SingletonVault::singleton<MockTag>();
584 SingletonMock<Watchdog> watchdog_singleton;
585 vault.registrationComplete();
587 // Registring singletons after registrationComplete called works
588 // with make_mock (but not with Singleton ctor).
589 EXPECT_EQ(vault.registeredSingletonCount(), 1);
590 int serial_count_first = SingletonMock<Watchdog>::try_get()->serial_number;
592 // Override existing mock using make_mock.
593 SingletonMock<Watchdog>::make_mock();
595 EXPECT_EQ(vault.registeredSingletonCount(), 1);
596 int serial_count_mock = SingletonMock<Watchdog>::try_get()->serial_number;
598 // If serial_count value is the same, then singleton was not replaced.
599 EXPECT_NE(serial_count_first, serial_count_mock);
601 // Override existing mock using make_mock one more time
602 SingletonMock<Watchdog>::make_mock();
604 EXPECT_EQ(vault.registeredSingletonCount(), 1);
605 int serial_count_mock2 = SingletonMock<Watchdog>::try_get()->serial_number;
607 // If serial_count value is the same, then singleton was not replaced.
608 EXPECT_NE(serial_count_first, serial_count_mock2);
609 EXPECT_NE(serial_count_mock, serial_count_mock2);
611 vault.destroyInstances();
615 // Subprocess isn't currently supported under MSVC.
616 TEST(Singleton, DoubleRegistrationLogging) {
617 const auto basename = "singleton_double_registration";
618 const auto sub = fs::executable_path().remove_filename() / basename;
620 std::vector<std::string>{sub.string()},
621 Subprocess::Options()
622 .stdinFd(Subprocess::CLOSE)
623 .stdoutFd(Subprocess::CLOSE)
626 auto err = p.communicate("").second;
628 EXPECT_EQ(ProcessReturnCode::KILLED, res.state());
629 EXPECT_EQ(SIGABRT, res.killSignal());
630 EXPECT_THAT(err, testing::StartsWith("Double registration of singletons"));
634 // Singleton using a non default constructor test/example:
636 X() : X(-1, "unset") {}
637 X(int a1, std::string a2) : a1(a1), a2(a2) {
638 LOG(INFO) << "X(" << a1 << "," << a2 << ")";
641 const std::string a2;
644 folly::Singleton<X> singleton_x([]() { return new X(42, "foo"); });
646 TEST(Singleton, CustomCreator) {
648 std::shared_ptr<X> x2p = singleton_x.try_get();
649 EXPECT_NE(nullptr, x2p);
650 EXPECT_NE(x1.a1, x2p->a1);
651 EXPECT_NE(x1.a2, x2p->a2);
652 EXPECT_EQ(42, x2p->a1);
653 EXPECT_EQ(std::string("foo"), x2p->a2);
656 struct ConcurrentCreationDestructionTag {};
657 template <typename T, typename Tag = detail::DefaultTag>
658 using SingletonConcurrentCreationDestruction =
659 Singleton<T, Tag, ConcurrentCreationDestructionTag>;
661 folly::Baton<> slowpokeNeedySingletonBaton;
663 struct SlowpokeNeedySingleton {
664 SlowpokeNeedySingleton() {
665 slowpokeNeedySingletonBaton.post();
666 /* sleep override */ std::this_thread::sleep_for(
667 std::chrono::milliseconds(100));
669 SingletonConcurrentCreationDestruction<NeededSingleton>::try_get();
670 EXPECT_NE(unused, nullptr);
674 TEST(Singleton, ConcurrentCreationDestruction) {
675 auto& vault = *SingletonVault::singleton<ConcurrentCreationDestructionTag>();
676 SingletonConcurrentCreationDestruction<NeededSingleton> neededSingleton;
677 SingletonConcurrentCreationDestruction<SlowpokeNeedySingleton> needySingleton;
678 vault.registrationComplete();
680 std::thread needyThread([&] { needySingleton.try_get(); });
682 slowpokeNeedySingletonBaton.wait();
684 vault.destroyInstances();
689 struct MainThreadDestructorTag {};
690 template <typename T, typename Tag = detail::DefaultTag>
691 using SingletonMainThreadDestructor =
692 Singleton<T, Tag, MainThreadDestructorTag>;
694 struct ThreadLoggingSingleton {
695 ThreadLoggingSingleton() {
696 initThread = std::this_thread::get_id();
699 ~ThreadLoggingSingleton() {
700 destroyThread = std::this_thread::get_id();
703 static std::thread::id initThread;
704 static std::thread::id destroyThread;
706 std::thread::id ThreadLoggingSingleton::initThread{};
707 std::thread::id ThreadLoggingSingleton::destroyThread{};
709 TEST(Singleton, MainThreadDestructor) {
710 auto& vault = *SingletonVault::singleton<MainThreadDestructorTag>();
711 SingletonMainThreadDestructor<ThreadLoggingSingleton> singleton;
713 vault.registrationComplete();
714 EXPECT_EQ(std::thread::id(), ThreadLoggingSingleton::initThread);
717 EXPECT_EQ(std::this_thread::get_id(), ThreadLoggingSingleton::initThread);
719 std::thread t([instance = singleton.try_get()] {
720 /* sleep override */ std::this_thread::sleep_for(
721 std::chrono::milliseconds{100});
724 EXPECT_EQ(std::thread::id(), ThreadLoggingSingleton::destroyThread);
726 vault.destroyInstances();
727 EXPECT_EQ(std::this_thread::get_id(), ThreadLoggingSingleton::destroyThread);
732 TEST(Singleton, DoubleMakeMockAfterTryGet) {
733 // to keep track of calls to ctor and dtor below
739 // a test type which keeps track of its ctor and dtor calls
741 struct PrivateTag {};
743 explicit Object(Counts& counts) : counts_(counts) {
751 using SingletonObject = Singleton<Object, PrivateTag, VaultTag>;
753 // register everything
755 auto& vault = *SingletonVault::singleton<VaultTag>();
756 auto new_object = [&] { return new Object(counts); };
757 SingletonObject object_(new_object);
758 vault.registrationComplete();
760 // no eager inits, nada (sanity)
761 EXPECT_EQ(0, counts.ctor);
762 EXPECT_EQ(0, counts.dtor);
764 // explicit request, ctor
765 SingletonObject::try_get();
766 EXPECT_EQ(1, counts.ctor);
767 EXPECT_EQ(0, counts.dtor);
769 // first make_mock, dtor (ctor is lazy)
770 SingletonObject::make_mock(new_object);
771 EXPECT_EQ(1, counts.ctor);
772 EXPECT_EQ(1, counts.dtor);
774 // second make_mock, nada (dtor already ran, ctor is lazy)
775 SingletonObject::make_mock(new_object);
776 EXPECT_EQ(1, counts.ctor);
777 EXPECT_EQ(1, counts.dtor);