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;
266 duration > std::chrono::seconds{4} &&
267 duration < std::chrono::seconds{folly::kIsSanitizeAddress ? 30 : 6});
269 EXPECT_EQ(vault.registeredSingletonCount(), 4);
270 EXPECT_EQ(vault.livingSingletonCount(), 0);
272 EXPECT_TRUE(weak_s1.expired());
274 auto empty_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
275 EXPECT_FALSE(empty_s1.lock());
277 vault.reenableInstances();
280 // Singleton should be re-created only after reenableInstances() was called.
281 auto new_s1 = SingletonSharedPtrUsage<Watchdog>::try_get();
282 // Track serial number rather than pointer since the memory could be
283 // re-used when we create new_s1.
284 EXPECT_NE(new_s1->serial_number, old_serial);
287 auto new_s1_weak = SingletonSharedPtrUsage<Watchdog>::get_weak();
288 auto new_s1_shared = new_s1_weak.lock();
289 std::thread t([new_s1_shared]() mutable {
290 std::this_thread::sleep_for(std::chrono::seconds{2});
291 new_s1_shared.reset();
293 new_s1_shared.reset();
295 auto start_time = std::chrono::steady_clock::now();
296 vault.destroyInstances();
297 auto duration = std::chrono::steady_clock::now() - start_time;
298 EXPECT_TRUE(duration > std::chrono::seconds{1} &&
299 duration < std::chrono::seconds{3});
301 EXPECT_TRUE(new_s1_weak.expired());
305 // Some classes to test singleton dependencies. NeedySingleton has a
306 // dependency on NeededSingleton, which happens during its
309 template <typename T, typename Tag = detail::DefaultTag>
310 using SingletonNeedy = Singleton <T, Tag, NeedyTag>;
312 struct NeededSingleton {};
313 struct NeedySingleton {
315 auto unused = SingletonNeedy<NeededSingleton>::try_get();
316 EXPECT_NE(unused, nullptr);
320 // Ensure circular dependencies fail -- a singleton that needs itself, whoops.
321 struct SelfNeedyTag {};
322 template <typename T, typename Tag = detail::DefaultTag>
323 using SingletonSelfNeedy = Singleton <T, Tag, SelfNeedyTag>;
325 struct SelfNeedySingleton {
326 SelfNeedySingleton() {
327 auto unused = SingletonSelfNeedy<SelfNeedySingleton>::try_get();
328 EXPECT_NE(unused, nullptr);
332 TEST(Singleton, SingletonDependencies) {
333 SingletonNeedy<NeededSingleton> needed_singleton;
334 SingletonNeedy<NeedySingleton> needy_singleton;
335 auto& needy_vault = *SingletonVault::singleton<NeedyTag>();
337 needy_vault.registrationComplete();
339 EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
340 EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
342 auto needy = SingletonNeedy<NeedySingleton>::try_get();
343 EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
345 SingletonSelfNeedy<SelfNeedySingleton> self_needy_singleton;
346 auto& self_needy_vault = *SingletonVault::singleton<SelfNeedyTag>();
348 self_needy_vault.registrationComplete();
349 EXPECT_DEATH([]() { SingletonSelfNeedy<SelfNeedySingleton>::try_get(); }(),
353 // A test to ensure multiple threads contending on singleton creation
354 // properly wait for creation rather than thinking it is a circular
356 class Slowpoke : public Watchdog {
358 Slowpoke() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); }
361 struct ConcurrencyTag {};
362 template <typename T, typename Tag = detail::DefaultTag>
363 using SingletonConcurrency = Singleton <T, Tag, ConcurrencyTag>;
365 TEST(Singleton, SingletonConcurrency) {
366 auto& vault = *SingletonVault::singleton<ConcurrencyTag>();
367 SingletonConcurrency<Slowpoke> slowpoke_singleton;
368 vault.registrationComplete();
370 std::mutex gatekeeper;
372 auto func = [&gatekeeper]() {
375 auto unused = SingletonConcurrency<Slowpoke>::try_get();
378 EXPECT_EQ(vault.livingSingletonCount(), 0);
379 std::vector<std::thread> threads;
380 for (int i = 0; i < 100; ++i) {
381 threads.emplace_back(func);
383 // If circular dependency checks fail, the unlock would trigger a
384 // crash. Instead, it succeeds, and we have exactly one living
387 for (auto& t : threads) {
390 EXPECT_EQ(vault.livingSingletonCount(), 1);
393 struct ErrorConstructor {
394 static size_t constructCount_;
396 if ((constructCount_++) == 0) {
397 throw std::runtime_error("first time fails");
401 size_t ErrorConstructor::constructCount_(0);
403 struct CreationErrorTag {};
404 template <typename T, typename Tag = detail::DefaultTag>
405 using SingletonCreationError = Singleton<T, Tag, CreationErrorTag>;
407 TEST(Singleton, SingletonCreationError) {
408 SingletonCreationError<ErrorConstructor> error_once_singleton;
409 SingletonVault::singleton<CreationErrorTag>()->registrationComplete();
411 // first time should error out
412 EXPECT_THROW(error_once_singleton.try_get(), std::runtime_error);
414 // second time it'll work fine
415 error_once_singleton.try_get();
419 struct ConcurrencyStressTag {};
420 template <typename T, typename Tag = detail::DefaultTag>
421 using SingletonConcurrencyStress = Singleton <T, Tag, ConcurrencyStressTag>;
423 TEST(Singleton, SingletonConcurrencyStress) {
424 auto& vault = *SingletonVault::singleton<ConcurrencyStressTag>();
425 SingletonConcurrencyStress<Slowpoke> slowpoke_singleton;
426 vault.registrationComplete();
428 std::vector<std::thread> ts;
429 for (size_t i = 0; i < 100; ++i) {
430 ts.emplace_back([&]() {
431 slowpoke_singleton.try_get();
435 for (size_t i = 0; i < 100; ++i) {
436 std::chrono::milliseconds d(20);
438 std::this_thread::sleep_for(d);
439 vault.destroyInstances();
440 std::this_thread::sleep_for(d);
441 vault.destroyInstances();
450 struct EagerInitSyncTag {};
452 template <typename T, typename Tag = detail::DefaultTag>
453 using SingletonEagerInitSync = Singleton<T, Tag, EagerInitSyncTag>;
454 TEST(Singleton, SingletonEagerInitSync) {
455 auto& vault = *SingletonVault::singleton<EagerInitSyncTag>();
456 bool didEagerInit = false;
457 auto sing = SingletonEagerInitSync<std::string>(
458 [&] {didEagerInit = true; return new std::string("foo"); })
460 vault.registrationComplete();
461 EXPECT_FALSE(didEagerInit);
463 EXPECT_TRUE(didEagerInit);
464 sing.get_weak(); // (avoid compile error complaining about unused var 'sing')
468 struct EagerInitAsyncTag {};
470 template <typename T, typename Tag = detail::DefaultTag>
471 using SingletonEagerInitAsync = Singleton<T, Tag, EagerInitAsyncTag>;
472 TEST(Singleton, SingletonEagerInitAsync) {
473 auto& vault = *SingletonVault::singleton<EagerInitAsyncTag>();
474 bool didEagerInit = false;
475 auto sing = SingletonEagerInitAsync<std::string>(
476 [&] {didEagerInit = true; return new std::string("foo"); })
480 vault.registrationComplete();
481 EXPECT_FALSE(didEagerInit);
482 vault.doEagerInitVia(eb, &done);
485 EXPECT_TRUE(didEagerInit);
486 sing.get_weak(); // (avoid compile error complaining about unused var 'sing')
490 class TestEagerInitParallelExecutor : public folly::Executor {
492 explicit TestEagerInitParallelExecutor(const size_t threadCount) {
493 eventBases_.reserve(threadCount);
494 threads_.reserve(threadCount);
495 for (size_t i = 0; i < threadCount; i++) {
496 eventBases_.push_back(std::make_shared<folly::EventBase>());
497 auto eb = eventBases_.back();
498 threads_.emplace_back(std::make_shared<std::thread>(
499 [eb] { eb->loopForever(); }));
503 ~TestEagerInitParallelExecutor() override {
504 for (auto eb : eventBases_) {
505 eb->runInEventBaseThread([eb] { eb->terminateLoopSoon(); });
507 for (auto thread : threads_) {
512 void add(folly::Func func) override {
513 const auto index = (counter_ ++) % eventBases_.size();
514 eventBases_[index]->add(std::move(func));
518 std::vector<std::shared_ptr<folly::EventBase>> eventBases_;
519 std::vector<std::shared_ptr<std::thread>> threads_;
520 std::atomic<size_t> counter_ {0};
525 struct EagerInitParallelTag {};
527 template <typename T, typename Tag = detail::DefaultTag>
528 using SingletonEagerInitParallel = Singleton<T, Tag, EagerInitParallelTag>;
529 TEST(Singleton, SingletonEagerInitParallel) {
530 const static size_t kIters = 1000;
531 const static size_t kThreads = 20;
533 std::atomic<size_t> initCounter;
535 auto& vault = *SingletonVault::singleton<EagerInitParallelTag>();
537 auto sing = SingletonEagerInitParallel<std::string>(
538 [&] {++initCounter; return new std::string(""); })
541 for (size_t i = 0; i < kIters; i++) {
543 // clean up each time
544 vault.destroyInstances();
545 vault.reenableInstances();
548 initCounter.store(0);
551 std::vector<std::shared_ptr<std::thread>> threads;
552 boost::barrier barrier(kThreads);
553 TestEagerInitParallelExecutor exe(kThreads);
554 vault.registrationComplete();
556 EXPECT_EQ(0, initCounter.load());
558 for (size_t j = 0; j < kThreads; j++) {
559 threads.push_back(std::make_shared<std::thread>([&] {
561 vault.doEagerInitVia(exe);
565 for (auto thread : threads) {
570 EXPECT_EQ(1, initCounter.load());
572 sing.get_weak(); // (avoid compile error complaining about unused var)
577 template <typename T, typename Tag = detail::DefaultTag>
578 using SingletonMock = Singleton <T, Tag, MockTag>;
580 // Verify that existing Singleton's can be overridden
581 // using the make_mock functionality.
582 TEST(Singleton, MockTest) {
583 auto& vault = *SingletonVault::singleton<MockTag>();
585 SingletonMock<Watchdog> watchdog_singleton;
586 vault.registrationComplete();
588 // Registring singletons after registrationComplete called works
589 // with make_mock (but not with Singleton ctor).
590 EXPECT_EQ(vault.registeredSingletonCount(), 1);
591 int serial_count_first = SingletonMock<Watchdog>::try_get()->serial_number;
593 // Override existing mock using make_mock.
594 SingletonMock<Watchdog>::make_mock();
596 EXPECT_EQ(vault.registeredSingletonCount(), 1);
597 int serial_count_mock = SingletonMock<Watchdog>::try_get()->serial_number;
599 // If serial_count value is the same, then singleton was not replaced.
600 EXPECT_NE(serial_count_first, serial_count_mock);
602 // Override existing mock using make_mock one more time
603 SingletonMock<Watchdog>::make_mock();
605 EXPECT_EQ(vault.registeredSingletonCount(), 1);
606 int serial_count_mock2 = SingletonMock<Watchdog>::try_get()->serial_number;
608 // If serial_count value is the same, then singleton was not replaced.
609 EXPECT_NE(serial_count_first, serial_count_mock2);
610 EXPECT_NE(serial_count_mock, serial_count_mock2);
612 vault.destroyInstances();
616 // Subprocess isn't currently supported under MSVC.
617 TEST(Singleton, DoubleRegistrationLogging) {
618 const auto basename = "singleton_double_registration";
619 const auto sub = fs::executable_path().remove_filename() / basename;
621 std::vector<std::string>{sub.string()},
622 Subprocess::Options()
623 .stdinFd(Subprocess::CLOSE)
624 .stdoutFd(Subprocess::CLOSE)
627 auto err = p.communicate("").second;
629 EXPECT_EQ(ProcessReturnCode::KILLED, res.state());
630 EXPECT_EQ(SIGABRT, res.killSignal());
631 EXPECT_THAT(err, testing::StartsWith("Double registration of singletons"));
635 // Singleton using a non default constructor test/example:
637 X() : X(-1, "unset") {}
638 X(int a1, std::string a2) : a1(a1), a2(a2) {
639 LOG(INFO) << "X(" << a1 << "," << a2 << ")";
642 const std::string a2;
645 folly::Singleton<X> singleton_x([]() { return new X(42, "foo"); });
647 TEST(Singleton, CustomCreator) {
649 std::shared_ptr<X> x2p = singleton_x.try_get();
650 EXPECT_NE(nullptr, x2p);
651 EXPECT_NE(x1.a1, x2p->a1);
652 EXPECT_NE(x1.a2, x2p->a2);
653 EXPECT_EQ(42, x2p->a1);
654 EXPECT_EQ(std::string("foo"), x2p->a2);
657 struct ConcurrentCreationDestructionTag {};
658 template <typename T, typename Tag = detail::DefaultTag>
659 using SingletonConcurrentCreationDestruction =
660 Singleton<T, Tag, ConcurrentCreationDestructionTag>;
662 folly::Baton<> slowpokeNeedySingletonBaton;
664 struct SlowpokeNeedySingleton {
665 SlowpokeNeedySingleton() {
666 slowpokeNeedySingletonBaton.post();
667 /* sleep override */ std::this_thread::sleep_for(
668 std::chrono::milliseconds(100));
670 SingletonConcurrentCreationDestruction<NeededSingleton>::try_get();
671 EXPECT_NE(unused, nullptr);
675 TEST(Singleton, ConcurrentCreationDestruction) {
676 auto& vault = *SingletonVault::singleton<ConcurrentCreationDestructionTag>();
677 SingletonConcurrentCreationDestruction<NeededSingleton> neededSingleton;
678 SingletonConcurrentCreationDestruction<SlowpokeNeedySingleton> needySingleton;
679 vault.registrationComplete();
681 std::thread needyThread([&] { needySingleton.try_get(); });
683 slowpokeNeedySingletonBaton.wait();
685 vault.destroyInstances();
690 struct MainThreadDestructorTag {};
691 template <typename T, typename Tag = detail::DefaultTag>
692 using SingletonMainThreadDestructor =
693 Singleton<T, Tag, MainThreadDestructorTag>;
695 struct ThreadLoggingSingleton {
696 ThreadLoggingSingleton() {
697 initThread = std::this_thread::get_id();
700 ~ThreadLoggingSingleton() {
701 destroyThread = std::this_thread::get_id();
704 static std::thread::id initThread;
705 static std::thread::id destroyThread;
707 std::thread::id ThreadLoggingSingleton::initThread{};
708 std::thread::id ThreadLoggingSingleton::destroyThread{};
710 TEST(Singleton, MainThreadDestructor) {
711 auto& vault = *SingletonVault::singleton<MainThreadDestructorTag>();
712 SingletonMainThreadDestructor<ThreadLoggingSingleton> singleton;
714 vault.registrationComplete();
715 EXPECT_EQ(std::thread::id(), ThreadLoggingSingleton::initThread);
718 EXPECT_EQ(std::this_thread::get_id(), ThreadLoggingSingleton::initThread);
720 std::thread t([instance = singleton.try_get()] {
721 /* sleep override */ std::this_thread::sleep_for(
722 std::chrono::milliseconds{100});
725 EXPECT_EQ(std::thread::id(), ThreadLoggingSingleton::destroyThread);
727 vault.destroyInstances();
728 EXPECT_EQ(std::this_thread::get_id(), ThreadLoggingSingleton::destroyThread);
733 TEST(Singleton, DoubleMakeMockAfterTryGet) {
734 // to keep track of calls to ctor and dtor below
740 // a test type which keeps track of its ctor and dtor calls
742 struct PrivateTag {};
744 explicit Object(Counts& counts) : counts_(counts) {
752 using SingletonObject = Singleton<Object, PrivateTag, VaultTag>;
754 // register everything
756 auto& vault = *SingletonVault::singleton<VaultTag>();
757 auto new_object = [&] { return new Object(counts); };
758 SingletonObject object_(new_object);
759 vault.registrationComplete();
761 // no eager inits, nada (sanity)
762 EXPECT_EQ(0, counts.ctor);
763 EXPECT_EQ(0, counts.dtor);
765 // explicit request, ctor
766 SingletonObject::try_get();
767 EXPECT_EQ(1, counts.ctor);
768 EXPECT_EQ(0, counts.dtor);
770 // first make_mock, dtor (ctor is lazy)
771 SingletonObject::make_mock(new_object);
772 EXPECT_EQ(1, counts.ctor);
773 EXPECT_EQ(1, counts.dtor);
775 // second make_mock, nada (dtor already ran, ctor is lazy)
776 SingletonObject::make_mock(new_object);
777 EXPECT_EQ(1, counts.ctor);
778 EXPECT_EQ(1, counts.dtor);