2011-04-15 15:15:37 +04:00
# include <config.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2011-04-15 23:17:11 +04:00
# include <time.h>
2011-04-15 15:15:37 +04:00
# include "internal.h"
# include "hash.h"
# include "hashdata.h"
# include "testutils.h"
2011-11-18 02:04:17 +04:00
# include "memory.h"
2011-04-15 15:15:37 +04:00
# define testError(...) \
do { \
fprintf ( stderr , __VA_ARGS__ ) ; \
/* Pad to line up with test name ... in virTestRun */ \
fprintf ( stderr , " %74s " , " ... " ) ; \
} while ( 0 )
static virHashTablePtr
testHashInit ( int size )
{
virHashTablePtr hash ;
int i ;
if ( ! ( hash = virHashCreate ( size , NULL ) ) )
return NULL ;
/* entires are added in reverse order so that they will be linked in
* collision list in the same order as in the uuids array
*/
for ( i = ARRAY_CARDINALITY ( uuids ) - 1 ; i > = 0 ; i - - ) {
2011-04-15 23:17:11 +04:00
int oldsize = virHashTableSize ( hash ) ;
2011-04-15 15:15:37 +04:00
if ( virHashAddEntry ( hash , uuids [ i ] , ( void * ) uuids [ i ] ) < 0 ) {
virHashFree ( hash ) ;
return NULL ;
}
2011-04-15 23:17:11 +04:00
if ( virHashTableSize ( hash ) ! = oldsize & & virTestGetDebug ( ) ) {
fprintf ( stderr , " \n hash grown from %d to %d " ,
oldsize , virHashTableSize ( hash ) ) ;
}
}
for ( i = 0 ; i < ARRAY_CARDINALITY ( uuids ) ; i + + ) {
if ( ! virHashLookup ( hash , uuids [ i ] ) ) {
if ( virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n entry \" %s \" could not be found \n " ,
uuids [ i ] ) ;
}
virHashFree ( hash ) ;
return NULL ;
}
2011-04-15 15:15:37 +04:00
}
2011-04-15 23:17:11 +04:00
if ( size & & size ! = virHashTableSize ( hash ) & & virTestGetDebug ( ) )
fprintf ( stderr , " \n " ) ;
2011-04-15 15:15:37 +04:00
return hash ;
}
2011-04-29 23:49:36 +04:00
static void
testHashCheckForEachCount ( void * payload ATTRIBUTE_UNUSED ,
const void * name ATTRIBUTE_UNUSED ,
void * data ATTRIBUTE_UNUSED )
{
}
2011-04-15 15:15:37 +04:00
static int
testHashCheckCount ( virHashTablePtr hash , int count )
{
2011-04-29 23:49:36 +04:00
int iter_count = 0 ;
2011-04-15 15:15:37 +04:00
if ( virHashSize ( hash ) ! = count ) {
testError ( " \n hash contains %d instead of %d elements \n " ,
virHashSize ( hash ) , count ) ;
return - 1 ;
}
2011-04-29 23:49:36 +04:00
iter_count = virHashForEach ( hash , testHashCheckForEachCount , NULL ) ;
if ( count ! = iter_count ) {
testError ( " \n hash claims to have %d elements but iteration finds %d \n " ,
count , iter_count ) ;
return - 1 ;
}
2011-04-15 15:15:37 +04:00
return 0 ;
}
struct testInfo {
void * data ;
int count ;
} ;
2011-04-15 23:17:11 +04:00
static int
testHashGrow ( const void * data )
{
const struct testInfo * info = data ;
virHashTablePtr hash ;
int ret = - 1 ;
if ( ! ( hash = testHashInit ( info - > count ) ) )
return - 1 ;
if ( testHashCheckCount ( hash , ARRAY_CARDINALITY ( uuids ) ) < 0 )
goto cleanup ;
ret = 0 ;
cleanup :
virHashFree ( hash ) ;
return ret ;
}
static int
testHashUpdate ( const void * data ATTRIBUTE_UNUSED )
{
int count = ARRAY_CARDINALITY ( uuids ) + ARRAY_CARDINALITY ( uuids_new ) ;
virHashTablePtr hash ;
int i ;
int ret = - 1 ;
if ( ! ( hash = testHashInit ( 0 ) ) )
return - 1 ;
for ( i = 0 ; i < ARRAY_CARDINALITY ( uuids_subset ) ; i + + ) {
if ( virHashUpdateEntry ( hash , uuids_subset [ i ] , ( void * ) 1 ) < 0 ) {
if ( virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n entry \" %s \" could not be updated \n " ,
uuids_subset [ i ] ) ;
}
goto cleanup ;
}
}
for ( i = 0 ; i < ARRAY_CARDINALITY ( uuids_new ) ; i + + ) {
if ( virHashUpdateEntry ( hash , uuids_new [ i ] , ( void * ) 1 ) < 0 ) {
if ( virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n new entry \" %s \" could not be updated \n " ,
uuids_new [ i ] ) ;
}
goto cleanup ;
}
}
if ( testHashCheckCount ( hash , count ) < 0 )
goto cleanup ;
ret = 0 ;
cleanup :
virHashFree ( hash ) ;
return ret ;
}
static int
testHashRemove ( const void * data ATTRIBUTE_UNUSED )
{
int count = ARRAY_CARDINALITY ( uuids ) - ARRAY_CARDINALITY ( uuids_subset ) ;
virHashTablePtr hash ;
int i ;
int ret = - 1 ;
if ( ! ( hash = testHashInit ( 0 ) ) )
return - 1 ;
for ( i = 0 ; i < ARRAY_CARDINALITY ( uuids_subset ) ; i + + ) {
if ( virHashRemoveEntry ( hash , uuids_subset [ i ] ) < 0 ) {
if ( virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n entry \" %s \" could not be removed \n " ,
uuids_subset [ i ] ) ;
}
goto cleanup ;
}
}
if ( testHashCheckCount ( hash , count ) < 0 )
goto cleanup ;
ret = 0 ;
cleanup :
virHashFree ( hash ) ;
return ret ;
}
2011-04-15 15:15:37 +04:00
const int testHashCountRemoveForEachSome =
ARRAY_CARDINALITY ( uuids ) - ARRAY_CARDINALITY ( uuids_subset ) ;
static void
testHashRemoveForEachSome ( void * payload ATTRIBUTE_UNUSED ,
const void * name ,
void * data )
{
virHashTablePtr hash = data ;
int i ;
for ( i = 0 ; i < ARRAY_CARDINALITY ( uuids_subset ) ; i + + ) {
if ( STREQ ( uuids_subset [ i ] , name ) ) {
if ( virHashRemoveEntry ( hash , name ) < 0 & & virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n entry \" %s \" could not be removed " ,
uuids_subset [ i ] ) ;
}
break ;
}
}
}
const int testHashCountRemoveForEachAll = 0 ;
static void
testHashRemoveForEachAll ( void * payload ATTRIBUTE_UNUSED ,
const void * name ,
void * data )
{
virHashTablePtr hash = data ;
virHashRemoveEntry ( hash , name ) ;
}
2011-04-15 23:17:11 +04:00
const int testHashCountRemoveForEachForbidden = ARRAY_CARDINALITY ( uuids ) ;
static void
testHashRemoveForEachForbidden ( void * payload ATTRIBUTE_UNUSED ,
const void * name ,
void * data )
{
virHashTablePtr hash = data ;
int i ;
for ( i = 0 ; i < ARRAY_CARDINALITY ( uuids_subset ) ; i + + ) {
if ( STREQ ( uuids_subset [ i ] , name ) ) {
int next = ( i + 1 ) % ARRAY_CARDINALITY ( uuids_subset ) ;
if ( virHashRemoveEntry ( hash , uuids_subset [ next ] ) = = 0 & &
virTestGetVerbose ( ) ) {
fprintf ( stderr ,
" \n entry \" %s \" should not be allowed to be removed " ,
uuids_subset [ next ] ) ;
}
break ;
}
}
}
2011-04-15 15:15:37 +04:00
static int
testHashRemoveForEach ( const void * data )
{
const struct testInfo * info = data ;
virHashTablePtr hash ;
int count ;
int ret = - 1 ;
if ( ! ( hash = testHashInit ( 0 ) ) )
return - 1 ;
count = virHashForEach ( hash , ( virHashIterator ) info - > data , hash ) ;
if ( count ! = ARRAY_CARDINALITY ( uuids ) ) {
if ( virTestGetVerbose ( ) ) {
testError ( " \n virHashForEach didn't go through all entries, "
2011-04-21 18:23:59 +04:00
" %d != %zu \n " ,
2011-04-15 15:15:37 +04:00
count , ARRAY_CARDINALITY ( uuids ) ) ;
}
goto cleanup ;
}
if ( testHashCheckCount ( hash , info - > count ) < 0 )
goto cleanup ;
ret = 0 ;
cleanup :
virHashFree ( hash ) ;
return ret ;
}
2011-04-15 23:17:11 +04:00
static int
testHashSteal ( const void * data ATTRIBUTE_UNUSED )
{
int count = ARRAY_CARDINALITY ( uuids ) - ARRAY_CARDINALITY ( uuids_subset ) ;
virHashTablePtr hash ;
int i ;
int ret = - 1 ;
if ( ! ( hash = testHashInit ( 0 ) ) )
return - 1 ;
for ( i = 0 ; i < ARRAY_CARDINALITY ( uuids_subset ) ; i + + ) {
if ( ! virHashSteal ( hash , uuids_subset [ i ] ) ) {
if ( virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n entry \" %s \" could not be stolen \n " ,
uuids_subset [ i ] ) ;
}
goto cleanup ;
}
}
if ( testHashCheckCount ( hash , count ) < 0 )
goto cleanup ;
ret = 0 ;
cleanup :
virHashFree ( hash ) ;
return ret ;
}
static void
testHashIter ( void * payload ATTRIBUTE_UNUSED ,
const void * name ATTRIBUTE_UNUSED ,
void * data ATTRIBUTE_UNUSED )
{
return ;
}
static void
testHashForEachIter ( void * payload ATTRIBUTE_UNUSED ,
const void * name ATTRIBUTE_UNUSED ,
void * data )
{
virHashTablePtr hash = data ;
if ( virHashAddEntry ( hash , uuids_new [ 0 ] , NULL ) = = 0 & &
virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n adding entries in ForEach should be forbidden " ) ;
}
if ( virHashUpdateEntry ( hash , uuids_new [ 0 ] , NULL ) = = 0 & &
virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n updating entries in ForEach should be forbidden " ) ;
}
if ( virHashSteal ( hash , uuids_new [ 0 ] ) ! = NULL & &
virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n stealing entries in ForEach should be forbidden " ) ;
}
if ( virHashSteal ( hash , uuids_new [ 0 ] ) ! = NULL & &
virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n stealing entries in ForEach should be forbidden " ) ;
}
if ( virHashForEach ( hash , testHashIter , NULL ) > = 0 & &
virTestGetVerbose ( ) ) {
fprintf ( stderr , " \n iterating through hash in ForEach "
" should be forbidden " ) ;
}
}
static int
testHashForEach ( const void * data ATTRIBUTE_UNUSED )
{
virHashTablePtr hash ;
int count ;
int ret = - 1 ;
if ( ! ( hash = testHashInit ( 0 ) ) )
return - 1 ;
count = virHashForEach ( hash , testHashForEachIter , hash ) ;
if ( count ! = ARRAY_CARDINALITY ( uuids ) ) {
if ( virTestGetVerbose ( ) ) {
testError ( " \n virHashForEach didn't go through all entries, "
2011-04-27 20:46:12 +04:00
" %d != %zu \n " ,
2011-04-15 23:17:11 +04:00
count , ARRAY_CARDINALITY ( uuids ) ) ;
}
goto cleanup ;
}
ret = 0 ;
cleanup :
virHashFree ( hash ) ;
return ret ;
}
static int
testHashRemoveSetIter ( const void * payload ATTRIBUTE_UNUSED ,
const void * name ,
const void * data )
{
int * count = ( int * ) data ;
bool rem = false ;
int i ;
for ( i = 0 ; i < ARRAY_CARDINALITY ( uuids_subset ) ; i + + ) {
if ( STREQ ( uuids_subset [ i ] , name ) ) {
rem = true ;
break ;
}
}
if ( rem | | rand ( ) % 2 ) {
( * count ) + + ;
return 1 ;
} else {
return 0 ;
}
}
static int
testHashRemoveSet ( const void * data ATTRIBUTE_UNUSED )
{
virHashTablePtr hash ;
int count = 0 ;
int rcount ;
int ret = - 1 ;
if ( ! ( hash = testHashInit ( 0 ) ) )
return - 1 ;
/* seed the generator so that rand() provides reproducible sequence */
srand ( 9000 ) ;
rcount = virHashRemoveSet ( hash , testHashRemoveSetIter , & count ) ;
if ( count ! = rcount ) {
if ( virTestGetVerbose ( ) ) {
testError ( " \n virHashRemoveSet didn't remove expected number of "
" entries, %d != %u \n " ,
rcount , count ) ;
}
goto cleanup ;
}
if ( testHashCheckCount ( hash , ARRAY_CARDINALITY ( uuids ) - count ) < 0 )
goto cleanup ;
ret = 0 ;
cleanup :
virHashFree ( hash ) ;
return ret ;
}
const int testSearchIndex = ARRAY_CARDINALITY ( uuids_subset ) / 2 ;
static int
testHashSearchIter ( const void * payload ATTRIBUTE_UNUSED ,
const void * name ,
const void * data ATTRIBUTE_UNUSED )
{
return STREQ ( uuids_subset [ testSearchIndex ] , name ) ;
}
static int
testHashSearch ( const void * data ATTRIBUTE_UNUSED )
{
virHashTablePtr hash ;
void * entry ;
int ret = - 1 ;
if ( ! ( hash = testHashInit ( 0 ) ) )
return - 1 ;
entry = virHashSearch ( hash , testHashSearchIter , NULL ) ;
if ( ! entry | | STRNEQ ( uuids_subset [ testSearchIndex ] , entry ) ) {
if ( virTestGetVerbose ( ) ) {
testError ( " \n virHashSearch didn't find entry '%s' \n " ,
uuids_subset [ testSearchIndex ] ) ;
}
goto cleanup ;
}
if ( testHashCheckCount ( hash , ARRAY_CARDINALITY ( uuids ) ) < 0 )
goto cleanup ;
ret = 0 ;
cleanup :
virHashFree ( hash ) ;
return ret ;
}
2011-11-18 02:04:17 +04:00
static int
testHashGetItemsCompKey ( const virHashKeyValuePairPtr a ,
const virHashKeyValuePairPtr b )
{
return strcmp ( a - > key , b - > key ) ;
}
static int
testHashGetItemsCompValue ( const virHashKeyValuePairPtr a ,
const virHashKeyValuePairPtr b )
{
return strcmp ( a - > value , b - > value ) ;
}
static int
testHashGetItems ( const void * data ATTRIBUTE_UNUSED )
{
virHashTablePtr hash ;
virHashKeyValuePairPtr array = NULL ;
int ret = - 1 ;
char keya [ ] = " a " ;
char keyb [ ] = " b " ;
char keyc [ ] = " c " ;
char value1 [ ] = " 1 " ;
char value2 [ ] = " 2 " ;
char value3 [ ] = " 3 " ;
if ( ! ( hash = virHashCreate ( 0 , NULL ) ) | |
virHashAddEntry ( hash , keya , value3 ) < 0 | |
virHashAddEntry ( hash , keyc , value1 ) < 0 | |
virHashAddEntry ( hash , keyb , value2 ) < 0 ) {
if ( virTestGetVerbose ( ) ) {
testError ( " \n failed to create hash " ) ;
}
goto cleanup ;
}
if ( ! ( array = virHashGetItems ( hash , NULL ) ) | |
array [ 3 ] . key | | array [ 3 ] . value ) {
if ( virTestGetVerbose ( ) ) {
testError ( " \n failed to get items with NULL sort " ) ;
}
goto cleanup ;
}
VIR_FREE ( array ) ;
if ( ! ( array = virHashGetItems ( hash , testHashGetItemsCompKey ) ) | |
STRNEQ ( array [ 0 ] . key , " a " ) | |
STRNEQ ( array [ 0 ] . value , " 3 " ) | |
STRNEQ ( array [ 1 ] . key , " b " ) | |
STRNEQ ( array [ 1 ] . value , " 2 " ) | |
STRNEQ ( array [ 2 ] . key , " c " ) | |
STRNEQ ( array [ 2 ] . value , " 1 " ) | |
array [ 3 ] . key | | array [ 3 ] . value ) {
if ( virTestGetVerbose ( ) ) {
testError ( " \n failed to get items with key sort " ) ;
}
goto cleanup ;
}
VIR_FREE ( array ) ;
if ( ! ( array = virHashGetItems ( hash , testHashGetItemsCompValue ) ) | |
STRNEQ ( array [ 0 ] . key , " c " ) | |
STRNEQ ( array [ 0 ] . value , " 1 " ) | |
STRNEQ ( array [ 1 ] . key , " b " ) | |
STRNEQ ( array [ 1 ] . value , " 2 " ) | |
STRNEQ ( array [ 2 ] . key , " a " ) | |
STRNEQ ( array [ 2 ] . value , " 3 " ) | |
array [ 3 ] . key | | array [ 3 ] . value ) {
if ( virTestGetVerbose ( ) ) {
testError ( " \n failed to get items with value sort " ) ;
}
goto cleanup ;
}
ret = 0 ;
cleanup :
VIR_FREE ( array ) ;
virHashFree ( hash ) ;
return ret ;
}
2011-04-15 15:15:37 +04:00
static int
2011-04-29 20:21:20 +04:00
mymain ( void )
2011-04-15 15:15:37 +04:00
{
int ret = 0 ;
# define DO_TEST_FULL(name, cmd, data, count) \
do { \
struct testInfo info = { data , count } ; \
if ( virtTestRun ( name , 1 , testHash # # cmd , & info ) < 0 ) \
ret = - 1 ; \
} while ( 0 )
# define DO_TEST_DATA(name, cmd, data) \
DO_TEST_FULL ( name " ( " # data " ) " , \
cmd , \
testHash # # cmd # # data , \
testHashCount # # cmd # # data )
2011-04-15 23:17:11 +04:00
# define DO_TEST_COUNT(name, cmd, count) \
DO_TEST_FULL ( name " ( " # count " ) " , cmd , NULL , count )
# define DO_TEST(name, cmd) \
DO_TEST_FULL ( name , cmd , NULL , - 1 )
DO_TEST_COUNT ( " Grow " , Grow , 1 ) ;
DO_TEST_COUNT ( " Grow " , Grow , 10 ) ;
DO_TEST_COUNT ( " Grow " , Grow , 42 ) ;
DO_TEST ( " Update " , Update ) ;
DO_TEST ( " Remove " , Remove ) ;
2011-04-15 15:15:37 +04:00
DO_TEST_DATA ( " Remove in ForEach " , RemoveForEach , Some ) ;
DO_TEST_DATA ( " Remove in ForEach " , RemoveForEach , All ) ;
2011-04-15 23:17:11 +04:00
DO_TEST_DATA ( " Remove in ForEach " , RemoveForEach , Forbidden ) ;
DO_TEST ( " Steal " , Steal ) ;
DO_TEST ( " Forbidden ops in ForEach " , ForEach ) ;
DO_TEST ( " RemoveSet " , RemoveSet ) ;
DO_TEST ( " Search " , Search ) ;
2011-11-18 02:04:17 +04:00
DO_TEST ( " GetItems " , GetItems ) ;
2011-04-15 15:15:37 +04:00
return ( ret = = 0 ) ? EXIT_SUCCESS : EXIT_FAILURE ;
}
VIRT_TEST_MAIN ( mymain )