//========================================================= double TesterManager::runTest(const std::string& strTName) { double dRez = TM_EMPTY; if (m_MTC.empty()) { return dRez; } if (strTName == std::string()) { // run all tests // first resolve dependencies std::vector<std::string> vcStrDeps; if (!resolveDeps(vcStrDeps)) { DBG_ERR("Manager '%s', looped dependency detected, final results could seem better than actual", m_strName.c_str()); } for (std::vector<std::string>::const_iterator vscit = vcStrDeps.begin(); vscit != vcStrDeps.end(); ++vscit) { const std::string& strDepName = *vscit; double dDepRez = runTest(strDepName); if (0.0 <= dDepRez && dDepRez <= 1.0) { m_DRM[strDepName] = dDepRez; } else { DBG_ERR("Manager '%s', error running dependency test, runTest returned %g", m_strName.c_str(), dDepRez); } } // now run all the rest std::size_t sztTestsRun = m_MTC.size(); double dSum = 0.0; for (MapTesterClasses::iterator mtcit = m_MTC.begin(); mtcit != m_MTC.end(); ++mtcit) { const std::string& strCName = mtcit->first; if (strCName == std::string()) { DBG_ERR("Manager '%s', empty class name detected", m_strName.c_str()); continue; } double dTest = runTest(strCName); if (0.0 <= dTest && dTest <= 1.0) { dSum += dTest; } } dRez = dSum / double(sztTestsRun); } else { // run specific test TesterMethod* pTM = nullptr; TesterClass* pTC = nullptr; if (getByName(strTName, pTC, pTM)) { if (pTM) { if (m_DRM.find(strTName) != m_DRM.end()) { dRez = m_DRM[strTName]; } else { dRez = pTM->runTest(); if (0.0 <= dRez && dRez <= 1.0) { m_DRM[strTName] = dRez; } } } else { dRez = pTC->runTest(); } } else { dRez = TM_ERROR; } } return dRez; }
int elektraSortTopology (KeySet * ks, Key ** array) { if (ks == NULL || array == NULL) return -1; KeySet * done = ksNew (0, KS_END); ksRewind (ks); Key * cur; ssize_t size = ksGetSize (ks); Key * orderCounter = keyNew ("/#", KEY_CASCADING_NAME, KEY_END); elektraArrayIncName (orderCounter); _adjMatrix adjMatrix[size]; int i = 0; int retVal = 1; int depCount = 0; Key ** localArray = elektraMalloc (size * sizeof (Key *)); elektraKsToMemArray (ks, localArray); qsort (localArray, size, sizeof (Key *), topCmpOrder); for (long j = 0; j < size; ++j) { adjMatrix[j].key = localArray[j]; adjMatrix[j].isResolved = 0; adjMatrix[j].deps = elektraCalloc (sizeof (unsigned long) * size); } kdb_octet_t hasOrder = 0; if (keyGetMeta (localArray[0], "order")) hasOrder = 1; unsigned int unresolved = 0; for (int j = 0; j < size; ++j) { cur = localArray[j]; KeySet * deps = elektraMetaArrayToKS (cur, "dep"); keyDel (ksLookupByName (deps, "dep", KDB_O_POP)); Key * tmpDep; switch (ksGetSize (deps)) { case -1: { // key has no dependencies, give it an order number and add it to list of resolved dependencies keySetMeta (cur, "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (cur)); adjMatrix[j].isResolved = 1; ksDel (deps); break; } case 1: { // only 1 dependency: // test if it's reflexive tmpDep = ksHead (deps); if (!strcmp (keyName (cur), keyString (tmpDep))) { keySetMeta (cur, "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (cur)); adjMatrix[j].isResolved = 1; ksDel (deps); break; } // if not, fallthrough to normal dependency handling } default: { int gotUnresolved = 0; while ((tmpDep = ksNext (deps)) != NULL) { if (!isValidKeyName (keyString (tmpDep))) { // invalid keyname -> ERROR retVal = -1; break; } i = getArrayIndex (tmpDep, adjMatrix, size); if (i == -1) { // key doesn't exist yet but has valid name, ignore it. continue; } else if (i == j) { // reflexiv depencency, do nothing } else { if (!adjMatrix[i].isResolved) { // unresolved dependency adjMatrix[j].deps[i] = 1; ++gotUnresolved; // simple cycle detection if (adjMatrix[i].deps[j]) { retVal = 0; break; } } } } if (gotUnresolved) { adjMatrix[j].isResolved = 0; ++unresolved; // cound unresolved dependencies depCount += gotUnresolved; } ksDel (deps); break; } } if (retVal <= 0) break; } if (retVal <= 0) { // error or cycle: goto cleanup goto TopSortCleanup; } // resolve all dependencies that can be resolved immediately for (int j = 0; j < size; ++j) { if (adjMatrix[j].isResolved) depCount -= resolveDep (j, adjMatrix, size); } ssize_t resolved = ksGetSize (done); if (((depCount + resolved) >= size) && (unresolved)) { // more dependencies dependencies than keys: // cycle found ! retVal = 0; goto TopSortCleanup; } if (unresolved) { int found = 1; // we have unresolved dependencies for (int j = 0; j < size + 1; ++j) { // loop until no dependency can be resolved anymore if (j == size) { if (found) { found = 0; j = -1; unresolved = 0; continue; } else break; } if (adjMatrix[j].isResolved) continue; ++unresolved; if (hasOrder) { // resolve by order int ret = resolveDeps (j, adjMatrix, size, done, orderCounter); if (ret == -1) break; j = -1; found = 1; continue; } else { // resolve next possible dependency in keyset if (!hasUnresolvedDependencies (j, adjMatrix, size)) { adjMatrix[j].isResolved = 1; resolveDep (j, adjMatrix, size); keySetMeta (localArray[j], "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (localArray[j])); found = 1; } } } } if (unresolved == 0) { // everything resolved // add dependencies in topological order to array elektraKsToMemArray (ks, array); qsort (array, size, sizeof (Key *), topCmpOrder); retVal = 1; } else { // still unresolved dependencies left: // there must be a cycle somewhere retVal = 0; } TopSortCleanup: ksDel (done); keyDel (orderCounter); elektraFree (localArray); for (ssize_t j = 0; j < size; ++j) { elektraFree (adjMatrix[j].deps); } return retVal; }