%description: Stress test for gate manipulation: create, delete, set size, etc. Also tests GateIterator, and all gate access functions in cModule (positive test cases only). Also tests that gate Ids are stable (resize or anything does not change them), and unique (Ids of deleted gates do not get reused). %file: test.ned simple Node { } network Test { submodules: node: Node; } %file: test.cc #include using namespace omnetpp; namespace @TESTNAME@ { //redefine ASSERT so that checks remain in the code even with NDEBUG defined #undef ASSERT #define ASSERT(expr) \ ((void) ((expr) ? 0 : (throw cRuntimeError("ASSERT: condition %s false in function %s, %s line %d", \ #expr, __FUNCTION__, __FILE__, __LINE__), 0))) class Node : public cSimpleModule { private: int counter; std::map gateIds; // name->id map std::set currentNames; std::set deletedNames; int numGates; // total gate count public: Node() : cSimpleModule(16384) { } virtual void activity() override; void createRandomGate(); void deleteRandomGate(); void setRandomGateSize(); void testGateIterator(); void checkAllGateIds(); void createTestGate(const char *gatename, cGate::Type type, bool isVector); void checkOneGate(const char *gatename, cGate::Type type, int size=-1, int index=-1); void deleteTestGate(const char *gatename); void setTestGateSize(const char *gatename, int size); std::string chooseRandom(const std::set& names); }; Define_Module(Node); void Node::createTestGate(const char *gatename, cGate::Type type, bool isVector) { EV << "creating " << gatename << (isVector?"[]":"") << "\n"; addGate(gatename, type, isVector); if (!isVector) numGates += (type==cGate::INOUT) ? 2 : 1; currentNames.insert(gatename); if (type==cGate::INOUT) { ASSERT(gateType(gatename)==type); std::string namei = std::string(gatename)+"$i"; std::string nameo = std::string(gatename)+"$o"; gateIds[namei] = gateBaseId(namei.c_str()); gateIds[nameo] = gateBaseId(nameo.c_str()); checkOneGate(namei.c_str(), cGate::INPUT, isVector ? 0 : -1); checkOneGate(nameo.c_str(), cGate::OUTPUT, isVector ? 0 : -1); } else { gateIds[gatename] = gateBaseId(gatename); checkOneGate(gatename, type, isVector ? 0 : -1); } } void Node::checkOneGate(const char *gatename, cGate::Type type, int size, int index) { ASSERT(type!=cGate::INOUT); // TODO assert that getGateNames() contains gatename (less $i/$o) ASSERT(hasGate(gatename)); ASSERT(gateType(gatename)==type); ASSERT(isGateVector(gatename)==(size!=-1)); ASSERT(gateSize(gatename)==(size!=-1 ? size : 1)); if (size!=0) { ASSERT(hasGate(gatename, index)); cGate *g = gate(gatename, index); ASSERT(g != nullptr); int id = g->getId(); ASSERT(findGate(gatename, index) == id); ASSERT(gate(id) == g); ASSERT(g->getName() == std::string(gatename)); ASSERT(g->getType() == type); if (size>0) { // is vector ASSERT(g->getIndex() == index); ASSERT(g->size() == size); } if (strchr(gatename, '$')) { std::string basename = std::string(gatename, strlen(gatename)-2); ASSERT(gateHalf(basename.c_str(),type,index) == g); } } } void Node::createRandomGate() { char gatename[30]; sprintf(gatename, "gate%d", counter++); switch (intrand(6)) { case 0: createTestGate(gatename, cGate::INPUT, false); break; case 1: createTestGate(gatename, cGate::OUTPUT, false); break; case 2: createTestGate(gatename, cGate::INOUT, false); break; case 3: createTestGate(gatename, cGate::INPUT, true); break; case 4: createTestGate(gatename, cGate::OUTPUT, true); break; case 5: createTestGate(gatename, cGate::INOUT, true); break; } } void Node::deleteRandomGate() { if (!currentNames.empty()) { std::string gatename = chooseRandom(currentNames); deleteTestGate(gatename.c_str()); } } void Node::deleteTestGate(const char *gatename) { EV << "deleting " << gatename << (isGateVector(gatename)?"[]":"") << "\n"; int size = isGateVector(gatename) ? gateSize(gatename) : 1; numGates -= size * (gateType(gatename)==cGate::INOUT ? 2 : 1); deleteGate(gatename); currentNames.erase(gatename); deletedNames.insert(gatename); ASSERT(hasGate(gatename) == false); } void Node::setRandomGateSize() { if (!currentNames.empty()) { std::string gatename = chooseRandom(currentNames); if (isGateVector(gatename.c_str())) setTestGateSize(gatename.c_str(), exponential(5)); // again gatename = chooseRandom(currentNames); if (isGateVector(gatename.c_str())) setTestGateSize(gatename.c_str(), exponential(30)); } } void Node::setTestGateSize(const char *gatename, int size) { EV << "resizing " << gatename << "[" << gateSize(gatename) << "] to [" << size << "]\n"; cGate::Type type = gateType(gatename); int oldSize = gateSize(gatename); setGateSize(gatename, size); numGates += (type==cGate::INOUT ? 2 : 1) * (size - oldSize); ASSERT(gateSize(gatename)==size); for (int i=0; i visited; for (GateIterator it(this); !it.end(); it++) { cGate *g = *it; ASSERT(g!=nullptr); ASSERT(gate(g->getId()) == g); ASSERT(visited.count(g)==0); visited.insert(g); ASSERT(visited.count(g)==1); n++; } ASSERT(n == numGates); } void Node::checkAllGateIds() { // // check gate IDs: // 1. when a gate still exists, it must be accessible by the same ID (IDs must be stable) // 2. when a gate was deleted, no gate should be accesible at its ID (ie IDs must not be reused) // //EV <<"checking " << gateIds.size() << " gates\n"; std::map::iterator it; for (it=gateIds.begin(); it!=gateIds.end(); it++) { const char *gatename = it->first.c_str(); int id = it->second; bool exists = hasGate(gatename); cGate *g = nullptr; try { g = gate(id); } catch(std::exception& e) { } if (g && id!=g->getId()) throw cRuntimeError("gate(id) and g->getId() inconsistent!"); if (g && !g->isName(gatename)) throw cRuntimeError("found another gate under the same ID -- IDs get reused???"); if (exists && gateSize(gatename)!=0 && g==nullptr) throw cRuntimeError("gate not found by old ID -- IDs change???"); if (!exists && g!=nullptr) throw cRuntimeError("found a gate with the ID of a deleted gate -- IDs get reused???"); } } std::string Node::chooseRandom(const std::set& names) { int k = intrand(names.size()); std::set::const_iterator it = names.begin(); for (int i=0; i