Exemple #1
0
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();
}
Exemple #2
0
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 );
}
Exemple #3
0
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();
}
Exemple #4
0
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();
}
Exemple #5
0
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;
}
Exemple #6
0
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();
}
Exemple #7
0
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();
}
Exemple #8
0
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;
}
Exemple #9
0
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();
}
Exemple #10
0
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();
}
Exemple #11
0
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();
}
Exemple #12
0
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();
}
Exemple #13
0
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 );
}
Exemple #14
0
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 );
}
Exemple #15
0
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 );
}
Exemple #16
0
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 );
  }
Exemple #17
0
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 );
}