void testOneThousandInserts() { // Test case used to validate fix to issue XPL-169 const int COUNT = 1000; const char stringPrefix[] = "Apofur81Kb"; UtlHashBag bag; char tmpString[20]; for( int i = 0; i < COUNT; i++) { sprintf(tmpString, "%s%d", stringPrefix, i); UtlString *stringToInsert = new UtlString(); *stringToInsert = tmpString; CPPUNIT_ASSERT( ! bag.contains( stringToInsert ) ); bag.insert( stringToInsert ); CPPUNIT_ASSERT_EQUAL( i+1, (int)bag.entries() ); for( unsigned int j = 0; j < bag.entries(); j++ ) { // verify that all entries are indeed in the bag sprintf( tmpString, "%s%d", stringPrefix, j ); UtlString stringTolookUp( tmpString ); CPPUNIT_ASSERT_MESSAGE( tmpString, bag.contains( &stringTolookUp ) ); } } }
/*!a Test case to test the DestroyAll() * method. */ void testClearAndDestroy() { const int testCount = 3 ; int cCountBefore = UtlContainableTestStub :: getCount() ; const char* prefix = "test the destroyAll() method " ; const char* suffix1 = " :- sanity check to double check that the counter was incremented for every new() call" ; const char* suffix2 = " :- Verify that all entries are removed and the objects are deleted" ; UtlContainableTestStub* uStub ; UtlContainableTestStub* uStubPtr ; UtlContainableTestStub* uStubPtr2 ; uStub = new UtlContainableTestStub(0) ; uStubPtr = new UtlContainableTestStub(201) ; uStubPtr2 = new UtlContainableTestStub(201) ; emptyList.insert(uStub) ; emptyList.insert(uStubPtr) ; emptyList.insert(uStubPtr2) ; cCountBefore = UtlContainableTestStub :: getCount() - cCountBefore ; emptyList.destroyAll() ; int cCountAfter = UtlContainableTestStub :: getCount() ; string msg ; // Make sure that static count was incremented for every instance // of the TestStub that was created. TestUtilities::createMessage(2, &msg, prefix, suffix1) ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), testCount, cCountBefore) ; // Verify that the list has no entries left after destroyAll() // and also ensure that all the TestStub instances were deleted. TestUtilities::createMessage(2, &msg, prefix, suffix2) ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), 0, cCountAfter) ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), 0, (int)emptyList.entries()) ; } //testClearAndDestroy
/*!a Test case for testRemove() * * The Test data for this test case is * a) is an entry's reference * b) is an entry's value(not reference) * c) is the first of multiple matches and is the value match * d) is the second of multiple matches. * e) has no match at all */ void testRemove() { int testCount = 4 ; const char* prefix = "test the remove(UtlContainable* c) method where c " ; const char* Msgs[] = { \ "is an entry's reference ", \ "is an entry's value(not reference) ", \ "is first of multiple value matches ", \ "has no match at all " \ } ; const char* suffix1 = " :- Verify returned value" ; const char* suffix2 = " :- Verify total entries" ; // Insert a new value such that its value matches(isEqual to) // one of the existing items commonList.insert(commonContainables_Clone[4]) ; UtlString notExistContainable("This cannot and willnot exist"); UtlContainable* dataForRemove[] = { \ commonContainables[0], \ commonContainables_Clone[2], \ commonContainables[4], \ ¬ExistContainable \ } ; int totalEnt = commonEntriesCount + 1; UtlBoolean expectedReturnValues[] = { \ true, true, true, false \ } ; int entriesValue[] = { --totalEnt, --totalEnt, --totalEnt, totalEnt } ; totalEnt = commonEntriesCount + 1; for (int i = 0 ; i < testCount ; i++) { string msg ; TestUtilities::createMessage(3, &msg, prefix, Msgs[i], suffix1) ; UtlContainable* retValue ; retValue = commonList.remove(dataForRemove[i]) ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), (UtlBoolean)(retValue!=NULL), \ (UtlBoolean)expectedReturnValues[i]) ; TestUtilities::createMessage(3, &msg, prefix, Msgs[i], suffix2) ; int expCount = (int)commonList.entries() ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), entriesValue[i], expCount) ; } } //testRemove
void testRemoveReference() { // the following two entries collide if the initial bucket size is 16 UtlInt int1(1); UtlInt int16(16); UtlInt int2a(2); UtlInt int2b(2); UtlInt int3(3); UtlHashBag bag; CPPUNIT_ASSERT( bag.numberOfBuckets() == 16 ); // check assumption of collision // Load all the test objects CPPUNIT_ASSERT( bag.insert(&int1) == &int1 ); CPPUNIT_ASSERT( bag.insert(&int16) == &int16 ); CPPUNIT_ASSERT( bag.insert(&int2a) == &int2a ); CPPUNIT_ASSERT( bag.insert(&int2b) == &int2b ); CPPUNIT_ASSERT( bag.insert(&int3) == &int3 ); // Check that everything is there CPPUNIT_ASSERT( bag.entries() == 5 ); CPPUNIT_ASSERT( bag.contains(&int1) ); CPPUNIT_ASSERT( bag.contains(&int16) ); CPPUNIT_ASSERT( bag.contains(&int2a) ); // cannot test for 2a and 2b independently CPPUNIT_ASSERT( bag.contains(&int3) ); // Take entry 1 out (might collide w/ 16) CPPUNIT_ASSERT( bag.removeReference(&int1) == &int1 ); // Check that everything except entry 1 is still there, and that 1 is gone CPPUNIT_ASSERT( bag.entries() == 4 ); CPPUNIT_ASSERT( ! bag.contains(&int1) ); CPPUNIT_ASSERT( bag.contains(&int16) ); CPPUNIT_ASSERT( bag.contains(&int2a) );// cannot test for 2a and 2b independently CPPUNIT_ASSERT( bag.contains(&int3) ); // Put entry 1 back in (so that 16 will collide w/ it again) CPPUNIT_ASSERT( bag.insert(&int1) == &int1 ); // Check that everything is there CPPUNIT_ASSERT( bag.entries() == 5 ); CPPUNIT_ASSERT( bag.contains(&int1) ); CPPUNIT_ASSERT( bag.contains(&int16) ); CPPUNIT_ASSERT( bag.contains(&int2a) ); CPPUNIT_ASSERT( bag.contains(&int3) ); // Take entry 16 out (might collide w/ 1) CPPUNIT_ASSERT( bag.removeReference(&int16) == &int16 ); // Check that everything except entry 16 is still there, and that 16 is gone CPPUNIT_ASSERT( bag.entries() == 4 ); CPPUNIT_ASSERT( bag.contains(&int1) ); CPPUNIT_ASSERT( ! bag.contains(&int16) ); CPPUNIT_ASSERT( bag.contains(&int2a) );// cannot test for 2a and 2b independently CPPUNIT_ASSERT( bag.contains(&int3) ); // remove 2a (and ensure that you don't get back 2b) CPPUNIT_ASSERT( bag.removeReference(&int2a) == &int2a ); // Check that everything that should be is still there CPPUNIT_ASSERT( bag.entries() == 3 ); CPPUNIT_ASSERT( bag.contains(&int1) ); CPPUNIT_ASSERT( ! bag.contains(&int16) ); CPPUNIT_ASSERT( bag.find(&int2a) == &int2b ); // equal values, but now there's only one CPPUNIT_ASSERT( bag.contains(&int3) ); // remove 3 (no collision for this one) CPPUNIT_ASSERT( bag.removeReference(&int3) == &int3 ); // Check that everything that should be is still there CPPUNIT_ASSERT( bag.entries() == 2 ); CPPUNIT_ASSERT( bag.contains(&int1) ); CPPUNIT_ASSERT( ! bag.contains(&int16) ); CPPUNIT_ASSERT( bag.find(&int2a) == &int2b ); // equal values, but now there's only one CPPUNIT_ASSERT( ! bag.contains(&int3) ); // remove 3 again - should fail this time CPPUNIT_ASSERT( bag.removeReference(&int3) == NULL ); // Check that everything that should be is still there CPPUNIT_ASSERT( bag.entries() == 2 ); CPPUNIT_ASSERT( bag.contains(&int1) ); CPPUNIT_ASSERT( ! bag.contains(&int16) ); CPPUNIT_ASSERT( bag.find(&int2a) == &int2b ); // equal values, but now there's only one CPPUNIT_ASSERT( ! bag.contains(&int3) ); }
/*!a Test case to test the destroy() * method. */ void testRemoveAndDestroy() { const char* prefix = "test the destroy() method " ; // The ContainableTestStub has been implemented such that a static // counter is incremented everytime an instance is created and // the counter is decremented everytime an instance is destroyed. UtlContainableTestStub* uStub = new UtlContainableTestStub(0) ; UtlContainableTestStub* uStubPtr = new UtlContainableTestStub(101) ; commonList.insert(uStub) ; commonList.insert(uStubPtr) ; string msg ; int cCountBefore = UtlContainableTestStub :: getCount() ; UtlBoolean retValue = commonList.destroy(uStubPtr) ; int cCountAfter ; uStubPtr = NULL ; TestUtilities::createMessage(2, &msg, prefix, ":- Verify the return value") ; CPPUNIT_ASSERT_MESSAGE(msg.data(), retValue) ; // To verify that the object was destroyed, check to see if the static count has been // decremented. If yes, it means that the destructor was called. cCountAfter = UtlContainableTestStub :: getCount() ; TestUtilities::createMessage(2, &msg, prefix, ":- Verify that the object was deleted") ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), cCountBefore -1, cCountAfter) ; // THe way to verify if the object has been removed is to // create a new stub such that it has the same value as // the removed stub. Try to find the new stub UtlContainableTestStub uStubNew(101) ; UtlContainable* uSearch = commonList.find(&uStubNew) ; TestUtilities::createMessage(2, &msg, prefix, ":- Verify that the entry is removed") ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), (void*)NULL, (void*)uSearch) ; // Now test the case when you have added multiple deletable keys // and the first key inserted is deleted first. UtlContainableTestStub* uStubPtr2 = new UtlContainableTestStub(201) ; UtlContainableTestStub* uStubPtr3 = new UtlContainableTestStub(201) ; commonList.insert(uStubPtr2) ; commonList.insert(uStubPtr3) ; UtlInt uTestInt(2031) ; commonList.insert(&uTestInt) ; // after destroying, either uStubPtr or uStubPtr3 might have gotten deleted and // we have no way to find out which one. So create a new ContainableTestStub // and use that for search UtlContainableTestStub uStubTemp(201) ; cCountBefore = UtlContainableTestStub :: getCount() ; commonList.destroy(&uStubTemp) ; cCountAfter = UtlContainableTestStub :: getCount() ; uSearch = commonList.find(&uStubTemp) ; const char* msgTemp = "Verify that doing a removeAndDestroy on " \ "an item that has multiple matches removes only one entry " ; TestUtilities::createMessage(2, &msg, msgTemp, " :- Verify value is still found") ; CPPUNIT_ASSERT_MESSAGE("Verify that doing a removeAndDestroy on " \ "an item that has multiple matches removes only one entry", \ uSearch == uStubPtr2 || uSearch == uStubPtr3) ; TestUtilities::createMessage(2, &msg, msgTemp, " :- Verify value *was* destroyed") ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), cCountBefore -1, cCountAfter) ; msgTemp = "Verify that the remaining entry can also be deleted" ; cCountBefore = UtlContainableTestStub :: getCount() ; commonList.destroy(&uStubTemp) ; cCountAfter = UtlContainableTestStub :: getCount() ; TestUtilities::createMessage(2, &msg, msgTemp, " :- Verify value *was* destroyed") ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), cCountBefore -1, cCountAfter) ; // In all the above tests, a total of 5 entries were added // and 3 were removed. int finalCount = commonEntriesCount + 2 ; msgTemp = "Verify that the HashTable stil has the other entries" ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msgTemp, finalCount, (int)commonList.entries()) ; }
/*a! Test the insert method for a list that is not empty. Add both unique and non-unique entries. * * The test data for this test is :- * a) Add a new UtlInt * b) Add a new UtlString * c) Add a new UtlVoidPtr * d) Add a new Containable such that a similar one (value match) exists already * e) Add a new Containable such that the same one (reference match) exists already */ void testInsert() { struct testInsertStructure { const char* testDescription ; UtlContainable* itemToAdd ; UtlContainable* expectedReturnValue ; // In case of the hashtable, searching for a key can return *ANY* of the values // that matches and we dont care about which one. so we need two set of expected values UtlContainable* expectedFoundValue ; UtlContainable* altExpectedFoundValue ; } ; const char* prefix = "Test the insert(UtlContainable*) method for a non empty HashTable " ; const char* suffix1 = " :- Verify return value" ; const char* suffix2 = " :- Verify that the value is inserted" ; const char* suffix3 = " :- Verify that the number of entries is incremented by one" ; UtlInt uInt = UtlInt(1234) ; UtlString uString = UtlString("Test String") ; UtlVoidPtr uVoidPtr((char*)"Hello world") ; testInsertStructure testData[] = { \ { "Add a new UtlInt ", &uInt, &uInt, &uInt, &uInt}, \ { "Add a new UtlString ", &uString, &uString, &uString, &uString}, \ { "Add a new UtlVoidPtr ", &uVoidPtr, &uVoidPtr, &uVoidPtr, &uVoidPtr}, \ { "Add a Containable such that an identical one(value match) " \ "exists in the table ", commonContainables_Clone[3], commonContainables_Clone[3], \ commonContainables[3], commonContainables_Clone[3] }, \ { "Add a Containable such that an exact duplicate " \ "(including reference match) exists in the table ", commonContainables[4], commonContainables[4], commonContainables[4] } \ } ; int expCount = commonEntriesCount; string msg ; UtlContainable* uAct ; UtlContainable* uReturn ; /* :TODO: this part of the test is in error. * when there is more than one of the same value in the bage, * the find() method may return any of the objects with that value. */ int testCount = sizeof(testData)/sizeof(testData[0]) ; for (int i = 0 ; i < testCount ; i++) { uReturn = commonList.insert(testData[i].itemToAdd) ; expCount++ ; uAct = commonList.find(testData[i].itemToAdd) ; TestUtilities::createMessage(3, &msg, prefix, \ testData[i].testDescription, suffix1) ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), \ testData[i].expectedReturnValue, uReturn) ; // when there is more than one of the same value in the bag, // the find() method may return any of the objects with that value. bool isFound = (uAct == testData[i].expectedFoundValue) || \ (uAct == testData[i].altExpectedFoundValue) ; TestUtilities::createMessage(3, &msg, prefix, \ testData[i].testDescription, suffix2) ; CPPUNIT_ASSERT_MESSAGE(msg.data(), isFound) ; TestUtilities::createMessage(3, &msg, prefix, \ testData[i].testDescription, suffix3) ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), expCount, (int)commonList.entries()) ; } } //testInsert
/*a! This test is more of a sanity check to verify that * the basic insert(), entries() and at() methods work as expected. * All future tests will depend heavily on the at() method * and the most common way of having something in the list is * by means of the insert() method. * */ void checkSanity_Insert_Entries_And_At() { // Verify that the hashtables that were created and populated in the setup method // have their entries set to the right value. CPPUNIT_ASSERT_EQUAL_MESSAGE("Verify that the entries() for an empty HashTable returns 0", (int)emptyList.entries(), 0) ; CPPUNIT_ASSERT_EQUAL_MESSAGE("Verify the entries() method for a HashTable", commonEntriesCount, (int)commonList.entries()) ; }// checkSanity_Append_And_At()
/*!a Test case for the () operator and the key() method. * * The test data for this test is :- * 1) The next entry is a UtlString * 2) The next entry is a UtlInt * 3) The next entry is the last entry * 4) All entries have been read */ void testAdvancingOperator_And_KeyMethod() { const int testCount = 5; const char* prefix = "Verify the () operator " ; const char* prefix_for_key = "Verify the key() method " ; const char* Msgs[] = { \ "when the entry is the first of two value matches of UtlString type", \ "when the entry is the first of two reference matches of UtlInt type", \ "when the entry is a unique Containable", \ "when the entry is the second of two reference matches of UtlInt type", \ "when the entry is the second of two value matches of UtlString type" \ } ; // Create a Hashtable such that it has one unique element (commonString2) , // 2 elements that has value matches (commonString1 / commonString1_clone) , // and 2 elements that *ARE* the same (commonInt1) UtlHashBag testList ; testList.insert(&commonString1) ; testList.insert(&commonInt1) ; testList.insert(&commonString1_clone) ; testList.insert(&commonString2) ; testList.insert(&commonInt1) ; UtlContainable* exp[] = { \ &commonString1 , &commonInt1, &commonString2, &commonInt1, &commonString1_clone } ; int expEntries = testCount; UtlHashBagIterator iter(testList) ; UtlContainable* act ; UtlContainable* expected_value_for_key_method ; string msg ; // Test the key method when the iterator has been reset. iter.reset() ; act = iter.key() ; TestUtilities::createMessage(2, &msg, prefix, "when the iterator has been reset") ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), (void*)NULL, (void*)act) ; // Now iterate through the whole iterator and verify that all the items are // retreived. The () operator retreives the next item in the list. The // key item should retreive the item under the current position. (That is, // the key() method should always return what the previous () returned) for (int i = 0 ; i < testCount ; i++) { act = iter() ; expected_value_for_key_method = act; const char* curMessage = ""; bool wasFound = false ; // We dont care about which item matches where. We only want to make sure // that each item *IS* retreived once and *ONLY* once. for (int j =0 ; j < testCount; j++) { // If the item was already found during a previous iteration, // we would have set the exp. value to NULL. so ignore all NULL // expected values. // The idea behind this is illustrated with the following example. // Let us say that invoking foo.search(bar) can return either return // either 90, 100 or 120 on the first search(either return is valid). // Let's say that it returns 100. But if foo.search(bar) is invoked the // second time, it should only return 90 or 120. So setting the element // of the expected array that used to contain 100 to NULL means that // that '100' is no longer a valid expected value. if (exp[j] != NULL && act == exp[j]) { wasFound = true ; exp[j] = NULL ; // Unlike traditional tests in which we know before hand the message // for a particular iteration, in this case, the message is constructed // based on the return value. curMessage = Msgs[j] ; break ; } } if (!wasFound) { curMessage = " :- One of the expected items was not retreived" \ " using an indexing operator" ; } TestUtilities::createMessage(3, &msg, prefix, curMessage, " :- Verify return value") ; CPPUNIT_ASSERT_MESSAGE(msg.data(), wasFound) ; TestUtilities::createMessage(3, &msg, prefix, curMessage, " :- Verify that the number of entries has not changed") ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), expEntries, (int)testList.entries()) ; // Verfiy that using the key() method retreives the value at the current position. // without repositioning the iterator. act = iter.key() ; TestUtilities::createMessage(2, &msg, prefix_for_key, curMessage) ; CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.data(), expected_value_for_key_method, act) ; } // Test the () operator when the whole list has been iterated act = iter() ; CPPUNIT_ASSERT_EQUAL_MESSAGE("Verify that the indexing operator on a list that has been traversed fully returns NULL", \ (void*)NULL, (void*)act) ; // Test the () operator for an empty list UtlHashBagIterator emptyIter(emptyList) ; act = emptyIter() ; CPPUNIT_ASSERT_EQUAL_MESSAGE("Test the () operator for an empty list iterator" , (void*)NULL, (void*)act) ; } //testAdvancingOperator()
int MpTopologyGraph::linkTopologyResources(MpResourceTopology& resourceTopology, UtlHashBag& newResources, UtlBoolean replaceNumInName, int resourceNum) { // Link the resources int connectionIndex = 0; UtlString outputResourceName; UtlString inputResourceName; int outputResourcePortIndex; int inputResourcePortIndex; MpResource* outputResource = NULL; MpResource* inputResource = NULL; OsStatus result; UtlHashMap newConnectionIds; #ifdef TEST_PRINT osPrintf("%d new resources in the list\n", newResources.entries()); UtlHashBagIterator iterator(newResources); MpResource* containerResource = NULL; while(containerResource = (MpResource*) iterator()) { osPrintf("found list resource: \"%s\" value: \"%s\"\n", containerResource->getName().data(), containerResource->data()); } #endif while(resourceTopology.getConnection(connectionIndex, outputResourceName, outputResourcePortIndex, inputResourceName, inputResourcePortIndex) == OS_SUCCESS) { if(replaceNumInName) { resourceTopology.replaceNumInName(outputResourceName, resourceNum); resourceTopology.replaceNumInName(inputResourceName, resourceNum); } // Look in the container of new resources first as this is more // efficient and new resources are not added immediately to a running // flowgraph outputResource = (MpResource*) newResources.find(&outputResourceName); if(outputResource == NULL) { result = lookupResource(outputResourceName, outputResource); if(result != OS_SUCCESS) { int virtPortIdx = outputResourcePortIndex>=0?outputResourcePortIndex:-1; int realPortIdx; result = lookupVirtualOutput(outputResourceName, virtPortIdx, outputResource, realPortIdx); if (result == OS_SUCCESS && outputResourcePortIndex>=0) { outputResourcePortIndex = realPortIdx; } } assert(result == OS_SUCCESS); } inputResource = (MpResource*) newResources.find(&inputResourceName); if(inputResource == NULL) { result = lookupResource(inputResourceName, inputResource); if(result != OS_SUCCESS) { int virtPortIdx = inputResourcePortIndex>=0?inputResourcePortIndex:-1; int realPortIdx; result = lookupVirtualInput(inputResourceName, virtPortIdx, inputResource, realPortIdx); if (result == OS_SUCCESS && inputResourcePortIndex>=0) { inputResourcePortIndex = realPortIdx; } } assert(result == OS_SUCCESS); } assert(outputResource); assert(inputResource); if(outputResource && inputResource) { if(outputResourcePortIndex == MpResourceTopology::MP_TOPOLOGY_NEXT_AVAILABLE_PORT) { outputResourcePortIndex = outputResource->reserveFirstUnconnectedOutput(); assert(outputResourcePortIndex >= 0); } else if(outputResourcePortIndex < MpResourceTopology::MP_TOPOLOGY_NEXT_AVAILABLE_PORT) { // First see if a real port is already in the dictionary UtlInt searchKey(outputResourcePortIndex); UtlInt* foundValue = NULL; if((foundValue = (UtlInt*) newConnectionIds.findValue(&searchKey))) { // Use the mapped index outputResourcePortIndex = foundValue->getValue(); } else { // Find an available port and add it to the map int realPortNum = outputResource->reserveFirstUnconnectedOutput(); assert(realPortNum >= 0); UtlInt* portKey = new UtlInt(outputResourcePortIndex); UtlInt* portValue = new UtlInt(realPortNum); newConnectionIds.insertKeyAndValue(portKey, portValue); outputResourcePortIndex = realPortNum; } } if(inputResourcePortIndex == MpResourceTopology::MP_TOPOLOGY_NEXT_AVAILABLE_PORT) { inputResourcePortIndex = inputResource->reserveFirstUnconnectedInput(); assert(inputResourcePortIndex >= 0); } else if(inputResourcePortIndex < MpResourceTopology::MP_TOPOLOGY_NEXT_AVAILABLE_PORT) { // First see if a real port is already in the dictionary UtlInt searchKey(inputResourcePortIndex); UtlInt* foundValue = NULL; if((foundValue = (UtlInt*) newConnectionIds.findValue(&searchKey))) { // Use the mapped index inputResourcePortIndex = foundValue->getValue(); } else { // Find an available port and add it to the map int realPortNum = inputResource->reserveFirstUnconnectedInput(); assert(realPortNum >= 0); UtlInt* portKey = new UtlInt(inputResourcePortIndex); UtlInt* portValue = new UtlInt(realPortNum); newConnectionIds.insertKeyAndValue(portKey, portValue); inputResourcePortIndex = realPortNum; } } result = addLink(*outputResource, outputResourcePortIndex, *inputResource, inputResourcePortIndex); assert(result == OS_SUCCESS); } connectionIndex++; } newConnectionIds.destroyAll(); return(connectionIndex); }