Beispiel #1
0
// Some pathological cases such as getting unregistered singletons,
// double registration, etc.
TEST(Singleton, NaughtyUsage) {
  SingletonVault vault;
  vault.registrationComplete();

  // Unregistered.
  EXPECT_THROW(Singleton<Watchdog>::get(), std::out_of_range);
  EXPECT_THROW(Singleton<Watchdog>::get(&vault), std::out_of_range);

  // Registring singletons after registrationComplete called.
  EXPECT_THROW([&vault]() {
                 Singleton<Watchdog> watchdog_singleton(
                     nullptr, nullptr, &vault);
               }(),
               std::logic_error);

  EXPECT_THROW([]() { Singleton<Watchdog> watchdog_singleton; }(),
               std::logic_error);

  SingletonVault vault_2;
  EXPECT_THROW(Singleton<Watchdog>::get(&vault_2), std::logic_error);
  Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault_2);
  // double registration
  EXPECT_THROW([&vault_2]() {
                 Singleton<Watchdog> watchdog_singleton(
                     nullptr, nullptr, &vault_2);
               }(),
               std::logic_error);
  vault_2.destroyInstances();
  // double registration after destroy
  EXPECT_THROW([&vault_2]() {
                 Singleton<Watchdog> watchdog_singleton(
                     nullptr, nullptr, &vault_2);
               }(),
               std::logic_error);
}
Beispiel #2
0
// Exercise some basic codepaths ensuring registration order and
// destruction order happen as expected, that instances are created
// when expected, etc etc.
TEST(Singleton, BasicUsage) {
  SingletonVault vault;

  EXPECT_EQ(vault.registeredSingletonCount(), 0);
  Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
  EXPECT_EQ(vault.registeredSingletonCount(), 1);

  Singleton<ChildWatchdog> child_watchdog_singleton(nullptr, nullptr, &vault);
  EXPECT_EQ(vault.registeredSingletonCount(), 2);

  vault.registrationComplete();

  Watchdog* s1 = Singleton<Watchdog>::get(&vault);
  EXPECT_NE(s1, nullptr);

  Watchdog* s2 = Singleton<Watchdog>::get(&vault);
  EXPECT_NE(s2, nullptr);

  EXPECT_EQ(s1, s2);

  auto s3 = Singleton<ChildWatchdog>::get(&vault);
  EXPECT_NE(s3, nullptr);
  EXPECT_NE(s2, s3);

  EXPECT_EQ(vault.registeredSingletonCount(), 2);
  EXPECT_EQ(vault.livingSingletonCount(), 2);

  vault.destroyInstances();
  EXPECT_EQ(vault.registeredSingletonCount(), 2);
  EXPECT_EQ(vault.livingSingletonCount(), 0);
}
Beispiel #3
0
TEST(Singleton, SingletonConcurrency) {
  SingletonVault vault;
  Singleton<Slowpoke> slowpoke_singleton(nullptr, nullptr, &vault);
  vault.registrationComplete();

  std::mutex gatekeeper;
  gatekeeper.lock();
  auto func = [&vault, &gatekeeper]() {
    gatekeeper.lock();
    gatekeeper.unlock();
    auto unused = Singleton<Slowpoke>::get(&vault);
  };

  EXPECT_EQ(vault.livingSingletonCount(), 0);
  std::vector<std::thread> threads;
  for (int i = 0; i < 100; ++i) {
    threads.emplace_back(func);
  }
  // If circular dependency checks fail, the unlock would trigger a
  // crash.  Instead, it succeeds, and we have exactly one living
  // singleton.
  gatekeeper.unlock();
  for (auto& t : threads) {
    t.join();
  }
  EXPECT_EQ(vault.livingSingletonCount(), 1);
}
Beispiel #4
0
TEST(Singleton, NamedUsage) {
  SingletonVault vault;

  EXPECT_EQ(vault.registeredSingletonCount(), 0);

  // Define two named Watchdog singletons and one unnamed singleton.
  Singleton<Watchdog> watchdog1_singleton(
      "watchdog1", nullptr, nullptr, &vault);
  EXPECT_EQ(vault.registeredSingletonCount(), 1);
  Singleton<Watchdog> watchdog2_singleton(
      "watchdog2", nullptr, nullptr, &vault);
  EXPECT_EQ(vault.registeredSingletonCount(), 2);
  Singleton<Watchdog> watchdog3_singleton(nullptr, nullptr, &vault);
  EXPECT_EQ(vault.registeredSingletonCount(), 3);

  vault.registrationComplete();

  // Verify our three singletons are distinct and non-nullptr.
  Watchdog* s1 = Singleton<Watchdog>::get("watchdog1", &vault);
  EXPECT_EQ(s1, watchdog1_singleton.ptr());
  Watchdog* s2 = Singleton<Watchdog>::get("watchdog2", &vault);
  EXPECT_EQ(s2, watchdog2_singleton.ptr());
  EXPECT_NE(s1, s2);
  Watchdog* s3 = Singleton<Watchdog>::get(&vault);
  EXPECT_EQ(s3, watchdog3_singleton.ptr());
  EXPECT_NE(s3, s1);
  EXPECT_NE(s3, s2);

  // Verify the "default" singleton is the same as the empty string
  // singleton.
  Watchdog* s4 = Singleton<Watchdog>::get("", &vault);
  EXPECT_EQ(s4, watchdog3_singleton.ptr());
}
Beispiel #5
0
TEST(Singleton, SingletonDependencies) {
  Singleton<NeededSingleton> needed_singleton(nullptr, nullptr, &needy_vault);
  Singleton<NeedySingleton> needy_singleton(nullptr, nullptr, &needy_vault);
  needy_vault.registrationComplete();

  EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
  EXPECT_EQ(needy_vault.livingSingletonCount(), 0);

  auto needy = Singleton<NeedySingleton>::get(&needy_vault);
  EXPECT_EQ(needy_vault.livingSingletonCount(), 2);

  Singleton<SelfNeedySingleton> self_needy_singleton(
      nullptr, nullptr, &self_needy_vault);
  self_needy_vault.registrationComplete();
  EXPECT_THROW([]() {
                 Singleton<SelfNeedySingleton>::get(&self_needy_vault);
               }(),
               std::out_of_range);
}
Beispiel #6
0
TEST(Singleton, SharedPtrUsage) {
  SingletonVault vault;

  EXPECT_EQ(vault.registeredSingletonCount(), 0);
  Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
  EXPECT_EQ(vault.registeredSingletonCount(), 1);

  Singleton<ChildWatchdog> child_watchdog_singleton(nullptr, nullptr, &vault);
  EXPECT_EQ(vault.registeredSingletonCount(), 2);

  vault.registrationComplete();

  Watchdog* s1 = Singleton<Watchdog>::get(&vault);
  EXPECT_NE(s1, nullptr);

  Watchdog* s2 = Singleton<Watchdog>::get(&vault);
  EXPECT_NE(s2, nullptr);

  EXPECT_EQ(s1, s2);

  auto weak_s1 = Singleton<Watchdog>::get_weak(&vault);
  auto shared_s1 = weak_s1.lock();
  EXPECT_EQ(shared_s1.get(), s1);
  EXPECT_EQ(shared_s1.use_count(), 2);

  LOG(ERROR) << "The following log message regarding ref counts is expected";
  vault.destroyInstances();
  EXPECT_EQ(vault.registeredSingletonCount(), 2);
  EXPECT_EQ(vault.livingSingletonCount(), 0);

  EXPECT_EQ(shared_s1.use_count(), 1);
  EXPECT_EQ(shared_s1.get(), s1);

  auto locked_s1 = weak_s1.lock();
  EXPECT_EQ(locked_s1.get(), s1);
  EXPECT_EQ(shared_s1.use_count(), 2);
  locked_s1.reset();
  EXPECT_EQ(shared_s1.use_count(), 1);

  // Track serial number rather than pointer since the memory could be
  // re-used when we create new_s1.
  auto old_serial = shared_s1->serial_number;
  shared_s1.reset();
  locked_s1 = weak_s1.lock();
  EXPECT_TRUE(weak_s1.expired());

  Watchdog* new_s1 = Singleton<Watchdog>::get(&vault);
  EXPECT_NE(new_s1->serial_number, old_serial);
}
Beispiel #7
0
TEST(Singleton, DirectUsage) {
  SingletonVault vault;

  EXPECT_EQ(vault.registeredSingletonCount(), 0);

  // Verify we can get to the underlying singletons via directly using
  // the singleton definition.
  Singleton<Watchdog> watchdog(nullptr, nullptr, &vault);
  Singleton<Watchdog> named_watchdog("named", nullptr, nullptr, &vault);
  EXPECT_EQ(vault.registeredSingletonCount(), 2);
  vault.registrationComplete();

  EXPECT_NE(watchdog.ptr(), nullptr);
  EXPECT_EQ(watchdog.ptr(), Singleton<Watchdog>::get(&vault));
  EXPECT_NE(watchdog.ptr(), named_watchdog.ptr());
  EXPECT_EQ(watchdog->livingWatchdogCount(), 2);
  EXPECT_EQ((*watchdog).livingWatchdogCount(), 2);
}