TEST_F(ContextEnumeratorTest, VerifySimpleEnumeration) { // Create a pair of descendant contexts, verify we don't accidentally hit these when enumerating children AutoCreateContext outer; AutoCreateContext inner; CurrentContextPusher pshr(inner); // Add a few children to the current context: AutoCreateContext c1; AutoCreateContext c2; AutoCreateContext c3; AutoCreateContext c4; std::unordered_set<std::shared_ptr<CoreContext>> allCtxts; allCtxts.insert(AutoCurrentContext()); allCtxts.insert(c1); allCtxts.insert(c2); allCtxts.insert(c3); allCtxts.insert(c4); // Create the enumerator, verify we get the expected count: size_t nContexts = 0; for(const std::shared_ptr<CoreContext>& cur : CurrentContextEnumerator()) { ASSERT_TRUE(!!allCtxts.count(cur)) << "Context enumerator accidentally enumerated a context not rooted in the specified parent"; allCtxts.erase(cur); nContexts++; } ASSERT_EQ(5UL, nContexts) << "Context enumerator did not encounter the number of expected children"; ASSERT_TRUE(allCtxts.empty()) << "Context enumerator did not encounter all children as expected"; }
TEST_F(ContextEnumeratorTest, ComplexRemovalInterference) { static const size_t nChildren = 50; // This time we use a vector, and we pop from the back of the vector unpredictably: std::vector<std::shared_ptr<CoreContext>> children(nChildren); for(size_t i = nChildren; i--;) children.push_back(AutoCreateContext()); // Shuffle the collection to prevent the order here from being equivalent to the order in the context std::random_shuffle(children.begin(), children.end()); // These are the elements actually encountered in the enumeration, held here to prevent expiration in the // event that we enumerate a context which should have already been evicted std::unordered_set<std::shared_ptr<CoreContext>> enumerated; // These are the elements eliminated from the vector. By the time we're done the should all be expired. std::vector<std::weak_ptr<CoreContext>> eliminated; // Go through the enumeration, the totals should line up by the time we're done: for(const auto& cur : CurrentContextEnumerator()) { enumerated.insert(cur); // Pull off the last element: auto removed = children.back(); children.pop_back(); // If we haven't enumerated this element already, we want to mark it as eliminated-before-enumerated if(!enumerated.count(removed)) eliminated.push_back(removed); } // Now verify that nothing we eliminated was enumerated: for(auto& cur : eliminated) ASSERT_TRUE(cur.expired()) << "Found an element that was iterated after it should have been unreachable"; }
TEST_F(CoreContextTest, TestEnumerateChildren) { AutoCurrentContext ctxt; // Create a few anonymous children: AutoCreateContext child1; AutoCreateContext child2; AutoCreateContext child3; // Enumerate and see what we get back: std::set<std::shared_ptr<CoreContext>> allChildren; for(const auto& cur : CurrentContextEnumerator()) allChildren.insert(cur); // Verify we get exactly four back: ASSERT_EQ(4UL, allChildren.size()) << "Failed to enumerate the correct number of child contexts"; // Verify full membership: ASSERT_EQ(1UL, allChildren.count(ctxt)) << "Failed to find the root context in the returned context collection"; const char* childMissing = "Failed to find a child context in the set of children"; ASSERT_EQ(1UL, allChildren.count(child1)) << childMissing; ASSERT_EQ(1UL, allChildren.count(child2)) << childMissing; ASSERT_EQ(1UL, allChildren.count(child3)) << childMissing; //Check if filtering by sigil works AutoCreateContextT<Foo> fooCtxt; AutoCreateContextT<Bar> barCtxt; auto childFoo = barCtxt->Create<Foo>(); ContextEnumeratorT<Foo> enumerator1(ctxt); std::vector<std::shared_ptr<CoreContext>> onlyFoos(enumerator1.begin(), enumerator1.end()); ASSERT_EQ(2UL, onlyFoos.size()) << "Didn't collect only contexts with 'Foo' sigil"; ASSERT_NE(std::find(onlyFoos.begin(), onlyFoos.end(), fooCtxt), onlyFoos.end()) << "Context not enumerated"; ASSERT_NE(std::find(onlyFoos.begin(), onlyFoos.end(), childFoo), onlyFoos.end()) << "Context not enumerated"; ContextEnumeratorT<Bar> enumerator2(ctxt); std::vector<std::shared_ptr<CoreContext>> onlyBars(enumerator2.begin(), enumerator2.end()); ASSERT_EQ(1UL, onlyBars.size()) << "Didn't collect only contexts with 'Bar' sigil"; ASSERT_NE(std::find(onlyBars.begin(), onlyBars.end(), barCtxt), onlyBars.end()) << "Context not enumerated"; ContextEnumeratorT<Baz> enumerator3(ctxt); std::vector<std::shared_ptr<CoreContext>> noBaz(enumerator3.begin(), enumerator3.end()); ASSERT_TRUE(noBaz.empty()) << "Incorrectly collected contexts with 'Baz' sigil"; }
TEST_F(ContextEnumeratorTest, SimpleRemovalInterference) { static const size_t nChildren = 5; // Create a few contexts which we intend to destroy as we go along: std::unordered_set<std::shared_ptr<CoreContext>> contexts; for(size_t i = nChildren; i--;) contexts.insert(AutoCreateContext()); // Also add ourselves: contexts.insert(AutoCurrentContext()); // Enumerate contexts, and remove them from the set: size_t nRemoved = 0; for(const auto& cur : CurrentContextEnumerator()) { ASSERT_TRUE(!!contexts.count(cur)) << "Failed to find a context enumerated by the context enumerator"; contexts.erase(cur); nRemoved++; } // Verify we got the number removed we expected: ASSERT_EQ(nChildren + 1UL, nRemoved) << "Context enumerator did not remove the expected number of children"; }
TEST_F(CoreContextTest, TestEarlyLambdaReturn) { AutoCurrentContext ctxt; // Create three children: AutoCreateContext child1; AutoCreateContext child2; AutoCreateContext child3; // Enumerate, but stop after three: std::vector<std::shared_ptr<CoreContext>> allChildren; size_t totalSoFar = 0; for(const auto& ctxt : CurrentContextEnumerator()) { if(totalSoFar++ == 3) break; allChildren.push_back(ctxt); } ASSERT_EQ(3UL, allChildren.size()) << "Enumeration routine failed to quit early"; // Verify that the root context is the first one enumerated--needed to assure that we are executing a depth-first search ASSERT_EQ(ctxt, allChildren[0]) << "EnumerateChildContexts did not execute depth-first"; }