TEST basic_test_ltrim(int _commit) { int retval; unsigned char *key = UNSIGN("my key"); long keylen = strlen((char *)key); long i, size; unsigned char **values; long *valueslen; rlite *db = NULL; RL_CALL_VERBOSE(setup_db, RL_OK, &db, _commit, 1); RL_CALL_VERBOSE(create, RL_OK, db, key, keylen, 200, _commit, 1); RL_CALL_VERBOSE(rl_ltrim, RL_OK, db, key, keylen, 50, -50); RL_BALANCED(); RL_CALL_VERBOSE(rl_lrange, RL_OK, db, key, keylen, 0, -1, &size, &values, &valueslen); EXPECT_LONG(size, 101); for (i = 0; i < size; i++) { EXPECT_LONG(valueslen[i], 2); EXPECT_INT(values[i][0], ((50 + i) % CHAR_MAX)); EXPECT_INT(values[i][1], 0); rl_free(values[i]); } rl_free(values); rl_free(valueslen); RL_CALL_VERBOSE(rl_ltrim, RL_DELETED, db, key, keylen, 1, 0); RL_BALANCED(); rl_close(db); PASS(); }
REGISTER_UNIT_TEST( MojoSetTestString, Container ) { MojoSet< MojoHashableCString > set( __FUNCTION__ ); // Verify insertion set.Insert( "Apple" ); set.Insert( "Banana" ); set.Insert( "Orange" ); set.Insert( "Kiwi" ); EXPECT_INT( 4, set.GetCount() ); // Verify re-insertion set.Insert( "Apple" ); set.Insert( "Banana" ); EXPECT_INT( 4, set.GetCount() ); // Verify removal set.Remove( "Banana" ); set.Remove( "Kiwi" ); EXPECT_INT( 2, set.GetCount() ); // Verify retrieval EXPECT_TRUE( set.Contains( "Apple" ) ); EXPECT_FALSE( set.Contains( "Banana" ) ); EXPECT_TRUE( set.Contains( "Orange" ) ); EXPECT_FALSE( set.Contains( "Kiwi" ) ); set.Destroy(); EXPECT_INT( 0, MyCountingAlloc.m_ActiveAlloc ); }
REGISTER_UNIT_TEST( RefCountedIntTest, UnitTest ) { bool old_use_assert = RefCountedInt::s_UseAssert; RefCountedInt::s_UseAssert = false; RefCountedInt::s_InfoErrorMessage = NULL; { RefCountedInt a; a.~RefCountedInt(); a = 1; EXPECT_NOT_NULL( RefCountedInt::s_InfoErrorMessage ); } RefCountedInt::ClearInfo(); // Test scoping { RefCountedInt a( 1 ); RefCountedInt b; RefCountedInt c = a; EXPECT_STRING( NULL, RefCountedInt::s_InfoErrorMessage ); EXPECT_INT( 3, RefCountedInt::s_InfoConstructedCount ); // a, b, c EXPECT_INT( 2, RefCountedInt::s_InfoAssignedCount ); // a, c } EXPECT_INT( 0, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( 0, RefCountedInt::s_InfoAssignedCount ); RefCountedInt::s_UseAssert = old_use_assert; RefCountedInt::ClearInfo(); }
static int assert_cmp(rlite *db, long p1, unsigned char *data, long size, int expected_cmp) { long p2; int retval, cmp; RL_CALL_VERBOSE(rl_multi_string_cmp_str, RL_OK, db, p1, data, size, &cmp); EXPECT_INT(cmp, expected_cmp); if (data) { RL_CALL_VERBOSE(rl_multi_string_set, RL_OK, db, &p2, data, size); RL_CALL_VERBOSE(rl_multi_string_cmp, RL_OK, db, p1, p2, &cmp); EXPECT_INT(cmp, expected_cmp); } PASS(); }
fftw_status fftw_import_wisdom(int (*g) (void *), void *data) { int n; int flags; fftw_direction dir; int dir_int; enum fftw_wisdom_category category; int category_int; enum fftw_node_type type; int recurse_kind_int; fftw_recurse_kind recurse_kind; int type_int; int signature; int istride, ostride; get_input = g; input_error = FFTW_SUCCESS; read_char(data); eat_blanks(data); EXPECT('('); eat_blanks(data); EXPECT_STRING(WISDOM_FORMAT_VERSION); eat_blanks(data); while (next_char != ')') { EXPECT('('); EXPECT_INT(n); EXPECT_INT(flags); /* paranoid respect for enumerated types */ EXPECT_INT(dir_int); dir = (fftw_direction) dir_int; EXPECT_INT(category_int); category = (enum fftw_wisdom_category) category_int; EXPECT_INT(istride); EXPECT_INT(ostride); EXPECT_INT(type_int); type = (enum fftw_node_type) type_int; EXPECT_INT(signature); EXPECT_INT(recurse_kind_int); recurse_kind = (fftw_recurse_kind) recurse_kind_int; eat_blanks(data); EXPECT(')'); /* the wisdom has been read properly. Add it */ fftw_wisdom_add(n, flags, dir, category, istride, ostride, type, signature, recurse_kind); /* prepare for next morsel of wisdom */ eat_blanks(data); } return FFTW_SUCCESS; }
TEST btree_create_oom() { rl_btree *btree = NULL; int i, retval; long btree_node_size = 10; rlite *db = NULL; RL_CALL_VERBOSE(setup_db, RL_OK, &db, 0, 1); for (i = 1; ;i++) { test_mode = 1; test_mode_caller = "rl_btree_create_size"; test_mode_counter = i; retval = rl_btree_create_size(db, &btree, &rl_btree_type_hash_long_long, btree_node_size); if (retval == RL_OK) { if (i == 1) { fprintf(stderr, "No OOM triggered\n"); test_mode = 0; FAIL(); } break; } EXPECT_INT(retval, RL_OUT_OF_MEMORY); } rl_btree_destroy(db, btree); rl_close(db); PASS(); }
static int test_cmp2_internal(int expected_cmp, long position) { unsigned char data[CMP_SIZE], data2[CMP_SIZE]; long size = CMP_SIZE, i; int retval, cmp; long p1; rlite *db = NULL; RL_CALL_VERBOSE(rl_open, RL_OK, ":memory:", &db, RLITE_OPEN_READWRITE | RLITE_OPEN_CREATE); for (i = 0; i < CMP_SIZE; i++) { data[i] = data2[i] = i % CHAR_MAX; } if (expected_cmp != 0) { if (data[position] == CHAR_MAX && expected_cmp > 0) { data2[position]--; } else if (data[position] == 0 && expected_cmp < 0) { data2[position]++; } else if (expected_cmp > 0) { data[position]++; } else { data[position]--; } } RL_CALL_VERBOSE(rl_multi_string_set, RL_OK, db, &p1, data, size); RL_CALL_VERBOSE(rl_multi_string_cmp_str, RL_OK, db, p1, data2, size, &cmp); EXPECT_INT(cmp, expected_cmp); rl_close(db); PASS(); }
fftw_status fftw_import_wisdom(int (*g)(void *), void *data) { int n; int flags; fftw_direction dir; enum fftw_node_type type; int signature; get_input = g; input_error = FFTW_SUCCESS; read_char(data); eat_blanks(data); EXPECT('('); eat_blanks(data); EXPECT_STRING(WISDOM_FORMAT_VERSION); eat_blanks(data); while (next_char != ')') { EXPECT('('); EXPECT_INT(n); EXPECT_INT(flags); EXPECT_INT(dir); EXPECT_INT(type); EXPECT_INT(signature); eat_blanks(data); EXPECT(')'); /* the wisdom has been read properly. Add it */ fftw_wisdom_add(n, flags, dir, type, signature); /* prepare for next morsel of wisdom */ eat_blanks(data); } return FFTW_SUCCESS; }
TEST empty_set_get() { int retval; long size, number; unsigned char *data; rlite *db = NULL; RL_CALL_VERBOSE(rl_open, RL_OK, ":memory:", &db, RLITE_OPEN_READWRITE | RLITE_OPEN_CREATE); RL_CALL_VERBOSE(rl_multi_string_set, RL_OK, db, &number, NULL, 0); RL_CALL_VERBOSE(rl_multi_string_get, RL_OK, db, number, &data, &size); EXPECT_INT(size, 0); EXPECT_PTR(data, NULL); rl_close(db); PASS(); }
TEST test_has_key() { rlite *db = NULL; int retval; const char *filepath = "rlite-test.rld"; if (access(filepath, F_OK) == 0) { unlink(filepath); } RL_CALL_VERBOSE(rl_open, RL_OK, filepath, &db, RLITE_OPEN_CREATE | RLITE_OPEN_READWRITE); unsigned char type = 'C', type2; const unsigned char *key = (unsigned char *)"random key"; long keylen = strlen((char *) key); long value = 529, value2; RL_CALL_VERBOSE(rl_key_get, RL_NOT_FOUND, db, key, keylen, NULL, NULL, NULL, NULL, NULL); RL_CALL_VERBOSE(rl_key_set, RL_OK, db, key, keylen, type, value, 0, 0); RL_CALL_VERBOSE(rl_key_get, RL_FOUND, db, key, keylen, &type2, NULL, &value2, NULL, NULL); EXPECT_LONG(value, value2); EXPECT_INT(type, type2); rl_close(db); PASS(); }
TEST basic_test_sadd_smembers(int _commit) { int retval; rlite *db = NULL; RL_CALL_VERBOSE(setup_db, RL_OK, &db, _commit, 1); unsigned char *key = UNSIGN("my key"); long keylen = strlen((char *)key); unsigned char *data = UNSIGN("my data"); long datalen = strlen((char *)data); unsigned char *data2 = UNSIGN("other data2"); long data2len = strlen((char *)data2); unsigned char *datas[2] = {data, data2}; long dataslen[2] = {datalen, data2len}; unsigned char *testdata; long testdatalen; int i; rl_set_iterator *iterator; RL_CALL_VERBOSE(rl_sadd, RL_OK, db, key, keylen, 2, datas, dataslen, NULL); RL_BALANCED(); RL_CALL_VERBOSE(rl_smembers, RL_OK, db, &iterator, key, keylen); i = 0; while ((retval = rl_set_iterator_next(iterator, &testdata, &testdatalen)) == RL_OK) { if (i++ == 1) { EXPECT_BYTES(data, datalen, testdata, testdatalen); } else { EXPECT_BYTES(data2, data2len, testdata, testdatalen); } rl_free(testdata); } EXPECT_INT(retval, RL_END); rl_close(db); PASS(); }
TEST rl_open_oom() { int j, i, retval; rlite *db = NULL; for (j = 0; j < 2; j++) { for (i = 1; ; i++) { test_mode = 1; test_mode_counter = i; retval = rl_open(j == 0 ? ":memory:" : "rlite-test.rld", &db, RLITE_OPEN_CREATE | RLITE_OPEN_READWRITE); if (retval == RL_OK) { if (i == 1) { fprintf(stderr, "No OOM triggered\n"); test_mode = 0; FAIL(); } rl_close(db); break; } EXPECT_INT(retval, RL_OUT_OF_MEMORY); } } test_mode = 0; PASS(); }
REGISTER_UNIT_TEST( MojoArrayTest, Container ) { MojoArray< RefCountedInt > array; MojoStatus status = array.Create( __FUNCTION__, -1 ); EXPECT_INT( kMojoStatus_Ok, status ); EXPECT_INT( 1, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( 1, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( 0, array.GetCount() ); const int max_count = 1000; // Verify insertion, also correct constructor behavior. Note: scope is used to limit RefCountedInt life span for( int i = 0; i < max_count; ++i ) { status = array.Push( i ); EXPECT_INT( kMojoStatus_Ok, status ); } EXPECT_INT( max_count + 1, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( max_count + 1, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( max_count, array.GetCount() ); // Verify value retrieval int sum = 0; for( int i = 0; i < array.GetCount(); ++i ) { sum += array[ i ]; } EXPECT_INT( ( max_count * ( max_count - 1 ) ) / 2, sum ); // Verify shift sum = 0; while( array.GetCount() ) { sum += array.Shift(); } EXPECT_INT( ( max_count * ( max_count - 1 ) ) / 2, sum ); // Verify unshift for( int i = 0; i < max_count; ++i ) { array.Unshift( i ); } EXPECT_INT( max_count + 1, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( max_count + 1, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( max_count, array.GetCount() ); // Verify pop sum = 0; while( array.GetCount() ) { sum += array.Pop(); } EXPECT_INT( ( max_count * ( max_count - 1 ) ) / 2, sum ); // Verify that you can mix push and unshift array.Push( 3 ); array.Unshift( 2 ); array.Push( 4 ); array.Unshift( 1 ); EXPECT_INT( 1, array[ 0 ] ); EXPECT_INT( 2, array[ 1 ] ); EXPECT_INT( 3, array[ 2 ] ); EXPECT_INT( 4, array[ 3 ] ); // Verify shift and push in a single call (move first element to end) array.Push( array.Shift() ); EXPECT_INT( 2, array[ 0 ] ); EXPECT_INT( 3, array[ 1 ] ); EXPECT_INT( 4, array[ 2 ] ); EXPECT_INT( 1, array[ 3 ] ); // Verify pop and unshift (last element to front) array.Unshift( array.Pop() ); EXPECT_INT( 1, array[ 0 ] ); EXPECT_INT( 2, array[ 1 ] ); EXPECT_INT( 3, array[ 2 ] ); EXPECT_INT( 4, array[ 3 ] ); // Remove all elements array.Pop(); array.Pop(); array.Pop(); array.Pop(); // Should be back at beginning state. EXPECT_INT( 1, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( 1, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( 0, array.GetCount() ); array.Destroy(); EXPECT_INT( 0, MyCountingAlloc.m_ActiveAlloc ); }
REGISTER_UNIT_TEST( MojoMapTest, Container ) { MojoConfig config; config.m_AllocCountMin = 10; config.m_TableCountMin = 10; MojoMap< MojoHash< uint32_t >, RefCountedInt > map; map.Create( __FUNCTION__, RefCountedInt(), &config ); uint32_t key; EXPECT_INT( 0, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( 0, map.GetCount() ); const int key_max_count = 100; uint32_t keys[ key_max_count ]; // Generate keys for( int i = 0; i < key_max_count; ++i ) { key = Random(); keys[ i ] = key; } // Verify insertion, also correct constructor behavior. for( int i = 0; i < key_max_count; ++i ) { key = keys[ i ]; map.Insert( key, 5 ); } EXPECT_INT( key_max_count, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( key_max_count, map.GetCount() ); // Verify value retrieval for( int i = 0; i < key_max_count; ++i ) { key = keys[ i ]; EXPECT_INT( 5, map.Find( key ).GetValue() ); } // Verify find failure key = 1; EXPECT_TRUE( map.Find( key ).IsNull() ); // Reinsert keys, different values. Should have no effect on key count for( int i = 0; i < key_max_count; ++i ) { key = keys[ i ]; map.Insert( key, RefCountedInt( i ) ); } EXPECT_INT( key_max_count, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( key_max_count, map.GetCount() ); // Verify that changes values are correct for( int i = 0; i < key_max_count; ++i ) { key = keys[ i ]; EXPECT_INT( i, map.Find( key ).GetValue() ); } // Verify key iterator int iteration_count = 0; MojoForEachKey( map, key ) { iteration_count += 1; } EXPECT_INT( key_max_count, iteration_count ); // Verify removal for( int i = 0; i < key_max_count; ++i ) { key = keys[ i ]; map.Remove( key ); } EXPECT_INT( 0, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( 0, map.GetCount() ); map.Destroy(); EXPECT_INT( 1, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( 0, MyCountingAlloc.m_ActiveAlloc ); }
REGISTER_UNIT_TEST( MojoSetTest, Container ) { MojoSet< MojoHash< uint32_t > > set; uint32_t key; MojoStatus status; status = set.Create( __FUNCTION__ ); EXPECT_INT( kMojoStatus_Ok, status ); EXPECT_INT( 0, set.GetCount() ); const int key_max_count = 1000; uint32_t keys[ key_max_count ]; // Generate keys for( int i = 0; i < key_max_count; ++i ) { key = Random(); keys[ i ] = key; } // Insert the keys, verify set count for( int i = 0; i < key_max_count; ++i ) { key = keys[ i ]; status = set.Insert( key ); EXPECT_INT( kMojoStatus_Ok, status ); } EXPECT_INT( key_max_count, set.GetCount() ); // Reinsert the same keys (should have no effect on set count) for( int i = 0; i < key_max_count; ++i ) { key = keys[ i ]; status = set.Insert( key ); EXPECT_INT( kMojoStatus_Ok, status ); } EXPECT_INT( key_max_count, set.GetCount() ); // Verify Contains() returns true for all inserted key values for( int i = 0; i < key_max_count; ++i ) { key = keys[ i ]; EXPECT_TRUE( set.Contains( key ) ); } // Verify Contains() returns false for other key values for( int i = 0; i < key_max_count; ++i ) { key = Random(); EXPECT_FALSE( set.Contains( key ) ); } // Verify Remove() is cool to call for non-existent key values for( int i = 0; i < key_max_count; ++i ) { key = Random(); status = set.Remove( key ); EXPECT_INT( kMojoStatus_NotFound, status ); } // Verify iterator int iteration_count = 0; MojoForEachKey( set, key ) { iteration_count += 1; } EXPECT_INT( key_max_count, iteration_count ); // Verify removal for( int i = 0; i < key_max_count; ++i ) { key = keys[ i ]; status = set.Remove( key ); EXPECT_INT( kMojoStatus_Ok, status ); } EXPECT_INT( 0, set.GetCount() ); set.Destroy(); EXPECT_INT( 0, MyCountingAlloc.m_ActiveAlloc ); }
REGISTER_UNIT_TEST( MojoRelationTest, Container ) { MojoRelation< MojoId > rel( "test" ); // For 0..49, insert consecutively for( char c = 'a'; c <= 'z'; ++c ) { char group[ 20 ]; snprintf( group, sizeof group, "%c", c ); MojoId parent = group; for( int i = 0; i < 50; ++i ) { MojoId child = MakeId( group, i ); rel.InsertChildParent( child, parent ); } } // For 50..99, insert jumbled up for( int i = 50; i < 100; ++i ) { for( char c = 'z'; c >= 'a'; --c ) { char group[ 20 ]; snprintf( group, sizeof group, "%c", c ); MojoId parent = group; MojoId child = MakeId( group, i ); rel.InsertChildParent( child, parent ); } } // Now remove all even children, to exercise reordering. for( char c = 'a'; c <= 'z'; ++c ) { char group[ 20 ]; snprintf( group, sizeof group, "%c", c ); MojoId parent = group; for( int i = 0; i < 100; i += 2 ) { MojoId child = MakeId( group, i ); rel.RemoveChild( child ); } } // Now remove all parents above and including 'q'. for( char c = 'q'; c <= 'z'; ++c ) { char group[ 20 ]; snprintf( group, sizeof group, "%c", c ); MojoId parent = group; for( int i = 1; i < 100; i += 2 ) { MojoId child = MakeId( group, i ); rel.RemoveChild( child ); } } // Now table contains parents 'a'-'p', and only oddly numbered children // Find all children's parents for( char c = 'a'; c < 'q'; ++c ) { char group[ 20 ]; snprintf( group, sizeof group, "%c", c ); MojoId parent = group; for( int i = 1; i < 100; i += 2 ) { MojoId child = MakeId( group, i ); MojoId found_parent = rel.FindParent( child ); EXPECT_BOOL( false, found_parent.IsNull() ); EXPECT_STRING( parent.AsCString(), found_parent.AsCString() ); } } // Verify all even children are missing for( char c = 'a'; c < 'q'; ++c ) { char group[ 20 ]; snprintf( group, sizeof group, "%c", c ); MojoId parent = group; for( int i = 0; i < 100; i += 2 ) { MojoId child = MakeId( group, i ); MojoId found_parent = rel.FindParent( child ); EXPECT_BOOL( true, found_parent.IsNull() ); } } // Verify children of groups 'q'-'z' are gone as well for( char c = 'q'; c <= 'z'; ++c ) { char group[ 20 ]; snprintf( group, sizeof group, "%c", c ); MojoId parent = group; for( int i = 0; i < 100; i += 1 ) { MojoId child = MakeId( group, i ); MojoId found_parent = rel.FindParent( child ); EXPECT_BOOL( true, found_parent.IsNull() ); } } // Find children of parents for( char c = 'a'; c < 'q'; ++c ) { char group[ 20 ]; snprintf( group, sizeof group, "%c", c ); MojoId parent = group; MojoId child; int count = 0; MojoForEachMultiValue( rel, parent, child ) { count += 1; EXPECT_INT( c, child.AsCString()[ 0 ] ); } EXPECT_INT( 50, count ); }
REGISTER_UNIT_TEST( MojoArrayTestEdge, Container ) { const int max_count = 1000; const int small_count = 100; MojoConfig config; config.m_AllocCountMin = max_count; config.m_DynamicAlloc = false; MojoArray< RefCountedInt > array; MojoStatus status = array.Create( __FUNCTION__, -1, &config ); EXPECT_INT( kMojoStatus_Ok, status ); EXPECT_INT( 1, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( 1, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( 0, array.GetCount() ); // Fill it to the brim. for( int i = 0; i < max_count; ++i ) { status = array.Push( i ); EXPECT_INT( kMojoStatus_Ok, status ); } EXPECT_INT( max_count + 1, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( max_count + 1, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( max_count, array.GetCount() ); // Add some more, should status for( int i = max_count; i < max_count + small_count; ++i ) { status = array.Push( i ); // Does not change array. EXPECT_INT( kMojoStatus_CouldNotAlloc, status ); } // Now rotate the (filled to the brim) array, by pushing what we shift for( int i = 0; i < small_count; ++i ) { status = array.Push( array.Shift() ); EXPECT_INT( kMojoStatus_Ok, status ); } // Same in reverse: unshift what we pop for( int i = 0; i < small_count; ++i ) { status = array.Unshift( array.Pop() ); EXPECT_INT( kMojoStatus_Ok, status ); } // Pushing what we pop should do nothing for( int i = 0; i < small_count; ++i ) { status = array.Push( array.Pop() ); EXPECT_INT( kMojoStatus_Ok, status ); } // Also unshifting what we shift for( int i = 0; i < small_count; ++i ) { status = array.Unshift( array.Shift() ); EXPECT_INT( kMojoStatus_Ok, status ); } // Array should be at its original filled state. for( int i = 0; i < max_count; ++i ) { EXPECT_INT( i, array[ i ] ); } EXPECT_INT( max_count + 1, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( max_count + 1, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( max_count, array.GetCount() ); array.Destroy(); EXPECT_INT( 1, RefCountedInt::s_InfoAssignedCount ); // Remember not_found_value is still in there. EXPECT_INT( 1, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( 0, MyCountingAlloc.m_ActiveAlloc ); // Re-creating a destroyed object should work. (Note this time it's NOT restricted) status = array.Create( __FUNCTION__, -1 ); EXPECT_INT( kMojoStatus_Ok, status ); EXPECT_INT( 1, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( 1, RefCountedInt::s_InfoConstructedCount ); // Try some slicing and dicing. // Add some content. for( int i = 0; i < max_count; ++i ) { status = array.Push( i ); EXPECT_INT( kMojoStatus_Ok, status ); } EXPECT_INT( max_count + 1, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( max_count + 1, RefCountedInt::s_InfoConstructedCount ); int value = array.Remove( small_count ); EXPECT_INT( small_count, value ); // Removed element should be returned EXPECT_INT( max_count - 1, array.GetCount() ); EXPECT_INT( max_count, RefCountedInt::s_InfoAssignedCount ); EXPECT_INT( max_count, RefCountedInt::s_InfoConstructedCount ); // Verify new content for( int i = 0; i < max_count - 1; ++i ) { int expect = i; if( i >= small_count ) { expect += 1; } EXPECT_INT( expect, array[ i ] ); } EXPECT_INT( -1, array[ max_count - 1 ] ); // This should no longer be there (-1 is not_found_value) array.Destroy(); EXPECT_INT( 1, RefCountedInt::s_InfoAssignedCount ); // Remember not_found_value is still in there. EXPECT_INT( 1, RefCountedInt::s_InfoConstructedCount ); EXPECT_INT( 0, MyCountingAlloc.m_ActiveAlloc ); }