TEST_F(AutoInjectableTest, VerifySimpleThreadWait) {
  // Immediate kickoff:
  AutoCurrentContext()->Initiate();

  // Make an injectable, run it, and stuff it right into a future:
  AutoFuture future;
  MakeInjectable<CoreThread>()(&future);

  // Make a thread and then start it going:
  Autowired<CoreThread> thread;
  ASSERT_TRUE(thread.IsAutowired()) << "Thread was not injected by an injector as expected";

  AutoRequired<std::mutex> barr;
  {
    std::lock_guard<std::mutex> lk(*barr);

    // Add a lambda that we intentionally block:
    *thread += [] {
      Autowired<CoreThread> thread;
      Autowired<std::mutex> barr;
      ASSERT_TRUE(thread && barr) << "Failed to find a required type in the current context";
      std::lock_guard<std::mutex> lk(*barr);
      thread->Stop();
    };

    // Instant wait:
    ASSERT_FALSE(future.WaitFor(std::chrono::nanoseconds(1))) << "Premature wait return on an injector-provided future";
  }

  // Now that the thread is unblocked, verify that it quits:
  ASSERT_TRUE(future.WaitFor(std::chrono::seconds(5))) << "Wait failed to return on an injector-provided future";
}
void AutowiringEnclosure::OnTestEnd(const testing::TestInfo& info) {
  // Verify we can grab the test case back out and that the pointer is correct:
  Autowired<TestInfoProxy> ti;
  Autowired<AutowiringEnclosureExceptionFilter> ecef;
  auto ctxt = ecef ? ecef->GetContext() : nullptr;

  // Unconditionally reset the global context as the current context
  AutoGlobalContext()->SetCurrent();

  // Global initialization tests are special, we don't bother checking closure principle on them:
  if(!strcmp("GlobalInitTest", info.test_case_name()))
    return;

  // Need to make sure we got back our exception filter before continuing:
  ASSERT_TRUE(ecef.IsAutowired()) << "Failed to find the enclosed context exception filter; unit test may have incorrectly reset the enclosing context before returning";

  // Now try to tear down the test context enclosure:
  ctxt->SignalShutdown();

  // Do not allow teardown to take more than 250 milliseconds or so
  if(!ctxt->Wait(std::chrono::milliseconds(250))) {
    // Critical error--took too long to tear down
    assert(false);
  }

  static const char s_autothrow[] = "AUTOTHROW_";
  if(!strncmp(s_autothrow, info.name(), ARRAYCOUNT(s_autothrow) - 1))
    // Throw expected, end here
    return;

  // If an exception occurred somewhere, report it:
  ASSERT_FALSE(ecef->m_excepted)
    << "An unhandled exception occurred in this context" << std::endl
    << "[" << (ecef->m_ti ? ecef->m_ti->name() : "unknown") << "] " << ecef->m_what;
}
TEST_F(AutoInjectableTest, VerifySimpleInjection) {
  auto injector = MakeInjectable<SimpleObject>();
  injector();

  Autowired<SimpleObject> myobj;
  ASSERT_TRUE(myobj.IsAutowired()) << "Injectable failed to introduce a zero-arguments constructed item into the context";
}
Example #4
0
TEST_F(CoreContextTest, CoreContextAdd) {
  auto myClass = std::make_shared<CoreContextAddTestClass>();
  AutoCurrentContext ctxt;
  ctxt->Add(myClass);

  Autowired<CoreContextAddTestClass> mc;
  ASSERT_TRUE(mc.IsAutowired()) << "Manually registered interface was not detected as expected";
}
TEST_F(AutoInjectableTest, VerifyReduplicatedInjection) {
  auto injector = MakeInjectable<StealsConstructorArgument>("Hello") + MakeInjectable<StealsConstructorArgument>("World");
  injector();

  Autowired<StealsConstructorArgument> myobj;
  ASSERT_TRUE(myobj.IsAutowired()) << "Injectable failed to introduce a single-arguments constructed item into the context";
  ASSERT_EQ("Hello", myobj->myVal) << "Injectable failed to copy an rvalue argument properly";
}
Example #6
0
TEST_F(PostConstructTest, DelayedNotifyWhenAutowired) {
  // Autorequire, and add a registration:
  bool called = false;
  Autowired<SimpleObject> so;
  so.NotifyWhenAutowired([&called] { called = true; });

  // Inject a type after:
  AutoRequired<SimpleObject>();
  ASSERT_TRUE(called) << "An autowiring notification was not invoked on an already-satisfied field as expected";
}
Example #7
0
TEST_F(PostConstructTest, InjectNotifyWhenAutowired) {
  // Autorequire, and add a registration:
  bool called = false;
  Autowired<Interface3> interface;
  interface.NotifyWhenAutowired([&called] { called = true; });

  // Inject a type after:
  AutoCurrentContext()->Inject<Implementation3>();
  ASSERT_TRUE(called) << "An autowiring notification was not invoked on an already-satisfied field as expected";
}
Example #8
0
TEST_F(PostConstructTest, NotificationTeardownRace) {
  if (std::thread::hardware_concurrency() == 1)
    return; // Don't bother running on a single-core machine

  std::shared_ptr<CoreContext> pContext;

  auto quit = false;
  auto shouldQuit = MakeAtExit([&quit] { quit = true; });
  std::atomic<size_t> counter{0};

  // This thread sets up the race pathology:
  std::thread t([&] {
    while(!quit) {
      // Barrier until setup time:
      while(counter != 1)
        std::this_thread::yield();

      if(!pContext)
        break;

      // Set the context current, then try to autowire:
      CurrentContextPusher pshr(pContext);
      Autowired<SimpleObject> sobj;
      sobj.NotifyWhenAutowired([] {});

      // Now barrier, and then we will try to race against the context
      // for teardown.
      counter++;
    }
  });

  for(size_t i = 0; i < 200; i++) {
    // Make a new context:
    AutoCreateContext ctxt;
    pContext = ctxt;

    // Wake up the other thread, let it set a notify-when-autowired:
    counter++;
    while(counter != 2)
      std::this_thread::yield();

    // Counter goes back to zero before we make the next loop iteration:
    counter = 0;

    // Now we reset our pContext pointer, and then tell the thread
    // to race with us against context teardown:
    pContext.reset();
  }

  // All done, wait for the thread to back out:
  quit = true;
  counter = 1;
  t.join();
}
TEST_F(AutoInjectableTest, VerifyInjectableAdditionPermutation2) {
  auto injector = MakeInjectable<StealsConstructorArgument>("Hello");
  auto injector2 = MakeInjectable<SimpleObject>() + injector;
  injector2();

  Autowired<StealsConstructorArgument> myStealObj;
  Autowired<SimpleObject> mySimpleObj;
  ASSERT_TRUE(myStealObj.IsAutowired()) << "Combined injectable failed to introduce a single-argument constructed item";
  ASSERT_EQ("Hello", myStealObj->myVal) << "Combined injectable failed to copy an rvalue argument";
  ASSERT_TRUE(mySimpleObj.IsAutowired()) << "Combined injectable failed to introduce a zero-arguments constructed";
}
Example #10
0
TEST_F(PostConstructTest, MultiNotifyWhenAutowired) {
  // Add multiple notifications on the same space:
  int field = 0;
  Autowired<SimpleObject> so;
  for(size_t i = 10; i--;)
    so.NotifyWhenAutowired([&field] { field++; });

  // Inject the type to trigger the autowiring
  AutoRequired<SimpleObject>();

  // Verify that the notification got hit ten times:
  ASSERT_EQ(10, field) << "Autowiring lambdas did not run the expected number of times";
}
Example #11
0
TEST_F(MultiInheritTest, VerifyCast) {
  // Create a dummy context and make it current:
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);

  // Insert a MultiInherit object:
  auto obj = ctxt->Inject<MultiInherit>();

  // Autowire in the pObj:
  Autowired<MultiInherit> wiredPobj;
  ASSERT_TRUE(wiredPobj.IsAutowired()) << "Autowiring failed for a multi-inheritance object";

  // Verify that we get a pObj back with correct casting:
  ASSERT_EQ(obj.get(), wiredPobj.get()) << "Autowiring failed on a multiple inheritance object";
}
Example #12
0
TEST_F(PostConstructTest, VerifySmartBehavior) {
  AutoCurrentContext ctxt;

  // Add the smart class, which has a member that autowired type A
  ctxt->Inject<Smarter>();

  // Check that we can get the item we just injected
  Autowired<Smarter> smarter;
  ASSERT_TRUE(smarter.IsAutowired()) << "Slot was not satisfied as expected";
  ASSERT_EQ(1, smarter->value) << "Unexpected initial value of SmarterA instance";

  // Now inject A, and see if delayed autowiring has taken place:
  ctxt->Inject<A>();
  ASSERT_FALSE(!smarter->m_a.get()) << "Autowired member was not wired as expected";

  // Verify the value was updated by the notification routine
  ASSERT_EQ(2, smarter->value) << "Post-construction notification routine wasn't invoked as expected";
}
TEST_F(ContextMemberTest, PathologicalResetCase) {
  Autowired<TypeThatIsNotInjected>* pv;
  volatile std::atomic<size_t> nBarr{ 0 };
  volatile bool proceed = true;
  volatile bool go = false;

  auto resetsV = [&] {
    while(proceed) {
      ++nBarr;
      while (proceed && !go)
        std::this_thread::yield();
      if (!proceed)
        break;

      pv->reset();
      --nBarr;
      while (proceed && go)
        std::this_thread::yield();
    }
  };

  std::thread a{ resetsV };
  std::thread b{ resetsV };

  for (size_t i = 1000; i--;) {
    Autowired<TypeThatIsNotInjected> v;
    pv = &v;
    for (size_t j = 10; j--;)
      v.NotifyWhenAutowired([] {});

    // Bump the threads to spin around:
    while (nBarr != 2)
      std::this_thread::yield();
    go = true;
    while (nBarr)
      std::this_thread::yield();
    go = false;
  }

  proceed = false;
  a.join();
  b.join();
}
Example #14
0
int main() {
  // Initiate the current context
  AutoCurrentContext()->Initiate();
  
  // Inject our AutoFilter enabled context members into the context
  AutoRequired<StringFilter>();
  AutoRequired<StringIntFilter>();
  
  // Each context automatically includes an AutoPacketFactory type. This
  // can be used to create new packets in the AutoFilter network
  Autowired<AutoPacketFactory> factory;
  
  // When decorating a packet, all AutoFilters that have that type as an argument
  // will be called. It is only called when all argument types have been decorated
  auto packet = factory->NewPacket();
  
  packet->Decorate(std::string("Hello World"));
  
  std::cout << "StringIntFilter not called yet" << std::endl;
  
  // StringIntFilter will now be called since all AutoFilter arguments have ben decorated
  packet->Decorate(42);
}
Example #15
0
 void Run(void) override {
   // Wait for our event to be signalled, then leave
   m_signal->Delay();
 }
Example #16
0
 void Run(void) override {
   m_exitRace->Wait();
 }
Example #17
0
int main () {
  // Initialization of context, injection of context members, obtaining access to the factory.
  AutoCurrentContext()->Initiate();
  AutoRequired<Hippo1> hippo1;
  AutoRequired<Hippo2> hippo2;
  AutoRequired<Hippo3> hippo3;
  AutoRequired<Hippo4> hippo4;
  AutoRequired<Hippo5> hippo5;
  AutoRequired<Hippo6> hippo6;
  Autowired<AutoPacketFactory> factory;
  // Declare a packet to use in the following code blocks.
  std::shared_ptr<AutoPacket> packet;

/// At this point we will execute the filter network a number of times, each with a different type related to `std::string`,
/// in order to observe which filters are executed.  The first six executions demonstrate the types that are equivalent to
/// `std::string` as input parameters (in which we expect only `Hippo#::AutoFilter` to be called). 
  {
    packet = factory->NewPacket();
    std::cout << "Decorating packet with instance of `std::string`:\n";
    std::string s("std::string");
    packet->Decorate(s);
    std::cout << '\n';
  }
  
  {
    packet = factory->NewPacket();
    std::cout << "Decorating packet with instance of `const std::string`:\n";
    const std::string s("const std::string");
    packet->Decorate(s);
    std::cout << '\n';
  }
  
  {
    packet = factory->NewPacket();
    std::cout << "Decorating packet with instance of `std::shared_ptr<std::string>`:\n";
    std::shared_ptr<std::string> s = std::make_shared<std::string>("std::shared_ptr<std::string>");
    packet->Decorate(s);
    std::cout << '\n';
  }
  
  {
    packet = factory->NewPacket();
    std::cout << "Decorating packet with instance of `const std::shared_ptr<std::string>`:\n";
    const std::shared_ptr<std::string> s = std::make_shared<std::string>("const std::shared_ptr<std::string>");
    packet->Decorate(s);
    std::cout << '\n';
  }
  
  {
    packet = factory->NewPacket();
    std::cout << "Decorating packet with instance of `std::shared_ptr<const std::string>`:\n";
    std::shared_ptr<const std::string> s = std::make_shared<const std::string>("std::shared_ptr<const std::string>");
    packet->Decorate(s);
    std::cout << '\n';
  }
  
  {
    packet = factory->NewPacket();
    std::cout << "Decorating packet with instance of `const std::shared_ptr<const std::string>`:\n";
    const std::shared_ptr<const std::string> s = std::make_shared<const std::string>("const std::shared_ptr<const std::string>");
    packet->Decorate(s);
    std::cout << '\n';
  }

/// Verify that the accumulated values in the `m_received_input_decoration_types` for each context member are what we expect.
  {
    std::unordered_set<std::string> expected_hippo_inputs({
      "std::string",
      "const std::string",
      "std::shared_ptr<std::string>",
      "const std::shared_ptr<std::string>",
      "std::shared_ptr<const std::string>",
      "const std::shared_ptr<const std::string>"
    });
    if (hippo1->m_received_input_decoration_types != expected_hippo_inputs)
      throw std::runtime_error("Hippo1 did not receive the expected inputs.");
    if (hippo1->m_received_input_decoration_types != expected_hippo_inputs)
      throw std::runtime_error("Hippo2 did not receive the expected inputs.");
    if (hippo1->m_received_input_decoration_types != expected_hippo_inputs)
      throw std::runtime_error("Hippo3 did not receive the expected inputs.");
    if (hippo1->m_received_input_decoration_types != expected_hippo_inputs)
      throw std::runtime_error("Hippo4 did not receive the expected inputs.");
    if (hippo1->m_received_input_decoration_types != expected_hippo_inputs)
      throw std::runtime_error("Hippo5 did not receive the expected inputs.");
    if (hippo1->m_received_input_decoration_types != expected_hippo_inputs)
      throw std::runtime_error("Hippo6 did not receive the expected inputs.");
    std::cout << "All Hippo# context members received the expected inputs.\n";
  }
  std::cout << "All verifications passed.\n";

  return 0; // Return with no error.
}
Example #18
0
TEST_F(PostConstructTest, VerifyLoopingFailedAutowiring) {
  for(size_t i = 10; i--;) {
    Autowired<FailedAutowiringInstance> ignored;
    ASSERT_FALSE(ignored.IsAutowired()) << "Successfully autowired an instance that should not have been autowirable";
  }
}