/* Ousía Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include namespace ousia { namespace dom { TEST(NodeDescriptor, nodeDegree) { NodeManager mgr; NodeDescriptor nd; Node n1{mgr}, n2{mgr}; // Input degree ASSERT_EQ(0, nd.refIn.size()); ASSERT_EQ(0, nd.refInCount(&n1)); nd.incrNodeDegree(RefDir::in, &n1); ASSERT_EQ(1, nd.refInCount()); ASSERT_EQ(1, nd.refInCount(&n1)); ASSERT_EQ(0, nd.refInCount(&n2)); ASSERT_EQ(1, nd.refIn.size()); nd.incrNodeDegree(RefDir::in, &n1); ASSERT_EQ(2, nd.refInCount()); ASSERT_EQ(2, nd.refInCount(&n1)); ASSERT_EQ(0, nd.refInCount(&n2)); ASSERT_EQ(1, nd.refIn.size()); nd.incrNodeDegree(RefDir::in, &n2); ASSERT_EQ(3, nd.refInCount()); ASSERT_EQ(2, nd.refInCount(&n1)); ASSERT_EQ(1, nd.refInCount(&n2)); ASSERT_EQ(2, nd.refIn.size()); nd.incrNodeDegree(RefDir::in, nullptr); ASSERT_EQ(4, nd.refInCount()); ASSERT_EQ(2, nd.refInCount(&n1)); ASSERT_EQ(1, nd.refInCount(&n2)); ASSERT_EQ(2, nd.refIn.size()); ASSERT_TRUE(nd.decrNodeDegree(RefDir::in, &n1)); ASSERT_EQ(3, nd.refInCount()); ASSERT_EQ(1, nd.refInCount(&n1)); ASSERT_EQ(1, nd.refInCount(&n2)); ASSERT_EQ(2, nd.refIn.size()); ASSERT_TRUE(nd.decrNodeDegree(RefDir::in, &n1)); ASSERT_EQ(2, nd.refInCount()); ASSERT_EQ(0, nd.refInCount(&n1)); ASSERT_EQ(1, nd.refInCount(&n2)); ASSERT_EQ(1, nd.refIn.size()); ASSERT_TRUE(nd.decrNodeDegree(RefDir::in, &n2)); ASSERT_EQ(1, nd.refInCount()); ASSERT_EQ(0, nd.refInCount(&n1)); ASSERT_EQ(0, nd.refInCount(&n2)); ASSERT_EQ(0, nd.refIn.size()); ASSERT_TRUE(nd.decrNodeDegree(RefDir::in, nullptr)); ASSERT_EQ(0, nd.refInCount()); ASSERT_EQ(0, nd.refInCount(&n1)); ASSERT_EQ(0, nd.refInCount(&n2)); ASSERT_EQ(0, nd.refIn.size()); // Output degree ASSERT_EQ(0, nd.refOut.size()); ASSERT_EQ(0, nd.refOutCount(&n1)); nd.incrNodeDegree(RefDir::out, &n1); ASSERT_EQ(1, nd.refOutCount()); ASSERT_EQ(1, nd.refOutCount(&n1)); ASSERT_EQ(0, nd.refOutCount(&n2)); ASSERT_EQ(1, nd.refOut.size()); nd.incrNodeDegree(RefDir::out, &n1); ASSERT_EQ(2, nd.refOutCount()); ASSERT_EQ(2, nd.refOutCount(&n1)); ASSERT_EQ(0, nd.refOutCount(&n2)); ASSERT_EQ(1, nd.refOut.size()); nd.incrNodeDegree(RefDir::out, &n2); ASSERT_EQ(3, nd.refOutCount()); ASSERT_EQ(2, nd.refOutCount(&n1)); ASSERT_EQ(1, nd.refOutCount(&n2)); ASSERT_EQ(2, nd.refOut.size()); nd.incrNodeDegree(RefDir::out, nullptr); ASSERT_EQ(3, nd.refOutCount()); ASSERT_EQ(2, nd.refOutCount(&n1)); ASSERT_EQ(1, nd.refOutCount(&n2)); ASSERT_EQ(2, nd.refOut.size()); ASSERT_TRUE(nd.decrNodeDegree(RefDir::out, &n1)); ASSERT_EQ(2, nd.refOutCount()); ASSERT_EQ(1, nd.refOutCount(&n1)); ASSERT_EQ(1, nd.refOutCount(&n2)); ASSERT_EQ(2, nd.refOut.size()); ASSERT_TRUE(nd.decrNodeDegree(RefDir::out, &n1)); ASSERT_EQ(1, nd.refOutCount()); ASSERT_EQ(0, nd.refOutCount(&n1)); ASSERT_EQ(1, nd.refOutCount(&n2)); ASSERT_EQ(1, nd.refOut.size()); ASSERT_TRUE(nd.decrNodeDegree(RefDir::out, &n2)); ASSERT_EQ(0, nd.refOutCount()); ASSERT_EQ(0, nd.refOutCount(&n1)); ASSERT_EQ(0, nd.refOutCount(&n2)); ASSERT_EQ(0, nd.refOut.size()); ASSERT_TRUE(nd.decrNodeDegree(RefDir::out, nullptr)); ASSERT_EQ(0, nd.refOutCount()); ASSERT_EQ(0, nd.refOutCount(&n1)); ASSERT_EQ(0, nd.refOutCount(&n2)); ASSERT_EQ(0, nd.refOut.size()); } TEST(NodeDescriptor, rootRefCount) { NodeDescriptor nd; ASSERT_EQ(0, nd.rootRefCount); nd.incrNodeDegree(RefDir::in, nullptr); ASSERT_EQ(1, nd.rootRefCount); nd.incrNodeDegree(RefDir::out, nullptr); ASSERT_EQ(2, nd.rootRefCount); ASSERT_EQ(2, nd.refInCount(nullptr)); ASSERT_EQ(2, nd.refInCount()); ASSERT_EQ(0, nd.refOutCount(nullptr)); ASSERT_EQ(0, nd.refOutCount()); ASSERT_TRUE(nd.decrNodeDegree(RefDir::out, nullptr)); ASSERT_EQ(1, nd.rootRefCount); ASSERT_TRUE(nd.decrNodeDegree(RefDir::in, nullptr)); ASSERT_EQ(0, nd.rootRefCount); ASSERT_FALSE(nd.decrNodeDegree(RefDir::in, nullptr)); ASSERT_EQ(0, nd.rootRefCount); } class TestNode : public Node { private: bool &alive; std::vector> refs; public: TestNode(NodeManager &mgr, bool &alive) : Node(mgr), alive(alive) { alive = true; } ~TestNode() override { alive = false; } void addRef(BaseHandle h) { refs.push_back(acquire(h)); } }; TEST(NodeManager, linearDependencies) { std::array a; a.fill(false); NodeManager mgr(1); { TestNode *n1, *n2, *n3; n1 = new TestNode(mgr, a[1]); n2 = new TestNode(mgr, a[2]); n3 = new TestNode(mgr, a[3]); { RootedHandle hr{new TestNode(mgr, a[0])}; // All nodes must have set their "alive" flag to true for (bool v : a) { ASSERT_TRUE(v); } // Create a linear dependency chain hr->addRef(n1); n1->addRef(n2); n2->addRef(n3); } // All nodes must have set their "alive" flag to false for (bool v : a) { ASSERT_FALSE(v); } } } TEST(NodeManager, cyclicDependencies) { std::array a; a.fill(false); NodeManager mgr(1); { TestNode *n1, *n2, *n3; n1 = new TestNode(mgr, a[1]); n2 = new TestNode(mgr, a[2]); n3 = new TestNode(mgr, a[3]); { RootedHandle hr{new TestNode(mgr, a[0])}; // All nodes must have set their "alive" flag to true for (bool v : a) { ASSERT_TRUE(v); } // Create a linear dependency chain hr->addRef(n1); n1->addRef(n2); n2->addRef(n3); n3->addRef(n1); } // All nodes must have set their "alive" flag to false for (bool v : a) { ASSERT_FALSE(v); } } } TEST(NodeManager, doubleRooted) { std::array a; a.fill(false); NodeManager mgr(1); { TestNode *n1, *n2; n1 = new TestNode(mgr, a[1]); n2 = new TestNode(mgr, a[2]); { RootedHandle hr1{new TestNode(mgr, a[0])}; { RootedHandle hr2{new TestNode(mgr, a[3])}; // All nodes must have set their "alive" flag to true for (bool v : a) { ASSERT_TRUE(v); } // Create cyclical dependency between n2 and n1 n1->addRef(n2); n2->addRef(n1); // Reference n1 and n2 in the rooted nodes hr1->addRef(n1); hr2->addRef(n2); } // hr2 is dead, all other nodes are still alive ASSERT_FALSE(a[3]); ASSERT_TRUE(a[0] && a[1] && a[2]); } // All nodes are dead for (bool v : a) { ASSERT_FALSE(v); } } } } }