2006-05-09 15:35:46 +00:00
/*
2007-01-19 20:30:05 +00:00
* testutils . c : basic test utils
2006-05-09 15:35:46 +00:00
*
2007-01-19 20:30:05 +00:00
* Copyright ( C ) 2005 - 2007 Red Hat , Inc .
2006-05-09 15:35:46 +00:00
*
* See COPYING . LIB for the License of this software
*
* Karel Zak < kzak @ redhat . com >
*
* $ Id $
*/
2008-01-29 18:15:54 +00:00
# include <config.h>
2007-12-07 10:08:06 +00:00
2006-05-09 15:35:46 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <sys/time.h>
2006-08-24 15:05:19 +00:00
# include <sys/types.h>
# include <sys/stat.h>
2006-08-24 21:46:28 +00:00
# include <sys/wait.h>
2006-08-24 15:05:19 +00:00
# include <unistd.h>
2008-04-18 15:05:29 +00:00
# include <string.h>
2006-08-24 21:46:28 +00:00
# include <fcntl.h>
# include <limits.h>
2006-05-09 15:35:46 +00:00
# include "testutils.h"
2008-04-30 12:30:55 +00:00
# include "internal.h"
2006-05-09 15:35:46 +00:00
2007-06-15 15:24:20 +00:00
# ifdef HAVE_PATHS_H
# include <paths.h>
# endif
# ifndef _PATH_DEVNULL
# define _PATH_DEVNULL " / dev / null"
# endif
2006-05-09 15:35:46 +00:00
# define GETTIMEOFDAY(T) gettimeofday(T, NULL)
2007-01-19 20:30:05 +00:00
# define DIFF_MSEC(T, U) \
( ( ( ( int ) ( ( T ) - > tv_sec - ( U ) - > tv_sec ) ) * 1000000.0 + \
( ( int ) ( ( T ) - > tv_usec - ( U ) - > tv_usec ) ) ) / 1000.0 )
2006-05-09 15:35:46 +00:00
double
virtTestCountAverage ( double * items , int nitems )
{
2007-01-19 20:30:05 +00:00
long double sum = 0 ;
int i ;
2006-05-09 15:35:46 +00:00
2007-01-19 20:30:05 +00:00
for ( i = 1 ; i < nitems ; i + + )
sum + = items [ i ] ;
2006-05-09 15:35:46 +00:00
2007-01-19 20:30:05 +00:00
return ( double ) ( sum / nitems ) ;
2006-05-09 15:35:46 +00:00
}
2007-01-19 20:30:05 +00:00
/*
2006-05-22 14:38:33 +00:00
* Runs test and count average time ( if the nloops is grater than 1 )
2007-01-19 20:30:05 +00:00
*
* returns : - 1 = error , 0 = success
2006-05-09 15:35:46 +00:00
*/
int
2007-07-18 21:08:22 +00:00
virtTestRun ( const char * title , int nloops , int ( * body ) ( const void * data ) , const void * data )
2006-05-09 15:35:46 +00:00
{
2007-01-19 20:30:05 +00:00
int i , ret = 0 ;
double * ts = NULL ;
2008-04-18 15:05:29 +00:00
static int counter = 0 ;
counter + + ;
fprintf ( stderr , " %2d) %-65s ... " , counter , title ) ;
fflush ( stderr ) ;
2007-01-19 20:30:05 +00:00
if ( nloops > 1 & & ( ts = calloc ( nloops ,
sizeof ( double ) ) ) = = NULL )
return - 1 ;
for ( i = 0 ; i < nloops ; i + + ) {
struct timeval before , after ;
if ( ts )
GETTIMEOFDAY ( & before ) ;
if ( ( ret = body ( data ) ) ! = 0 )
break ;
if ( ts ) {
GETTIMEOFDAY ( & after ) ;
ts [ i ] = DIFF_MSEC ( & after , & before ) ;
}
}
if ( ret = = 0 & & ts )
2008-04-18 15:05:29 +00:00
fprintf ( stderr , " OK [%.5f ms] \n " ,
2007-01-19 20:30:05 +00:00
virtTestCountAverage ( ts , nloops ) ) ;
else if ( ret = = 0 )
2008-04-18 15:05:29 +00:00
fprintf ( stderr , " OK \n " ) ;
2007-01-19 20:30:05 +00:00
else
2008-04-18 15:05:29 +00:00
fprintf ( stderr , " FAILED \n " ) ;
2007-01-19 20:30:05 +00:00
2008-01-29 17:41:07 +00:00
free ( ts ) ;
2007-01-19 20:30:05 +00:00
return ret ;
2006-05-09 15:35:46 +00:00
}
2006-08-24 15:05:19 +00:00
int virtTestLoadFile ( const char * name ,
2007-01-19 20:30:05 +00:00
char * * buf ,
int buflen ) {
2006-08-24 15:05:19 +00:00
FILE * fp = fopen ( name , " r " ) ;
struct stat st ;
2007-01-19 20:30:05 +00:00
2006-08-24 15:05:19 +00:00
if ( ! fp )
return - 1 ;
if ( fstat ( fileno ( fp ) , & st ) < 0 ) {
fclose ( fp ) ;
return - 1 ;
}
if ( st . st_size > ( buflen - 1 ) ) {
fclose ( fp ) ;
return - 1 ;
}
2007-01-19 20:30:05 +00:00
if ( st . st_size ) {
if ( fread ( * buf , st . st_size , 1 , fp ) ! = 1 ) {
fclose ( fp ) ;
return - 1 ;
}
2006-08-24 15:05:19 +00:00
}
( * buf ) [ st . st_size ] = ' \0 ' ;
fclose ( fp ) ;
return st . st_size ;
}
2006-08-24 21:46:28 +00:00
static
void virtTestCaptureProgramExecChild ( const char * const argv [ ] ,
2007-01-19 20:30:05 +00:00
int pipefd ) {
int i ;
int open_max ;
int stdinfd = - 1 ;
int stderrfd = - 1 ;
const char * const env [ ] = {
" LANG=C " ,
NULL
} ;
if ( ( stdinfd = open ( _PATH_DEVNULL , O_RDONLY ) ) < 0 )
goto cleanup ;
if ( ( stderrfd = open ( _PATH_DEVNULL , O_WRONLY ) ) < 0 )
goto cleanup ;
open_max = sysconf ( _SC_OPEN_MAX ) ;
for ( i = 0 ; i < open_max ; i + + ) {
if ( i ! = stdinfd & &
i ! = stderrfd & &
i ! = pipefd )
close ( i ) ;
}
if ( dup2 ( stdinfd , STDIN_FILENO ) ! = STDIN_FILENO )
goto cleanup ;
if ( dup2 ( pipefd , STDOUT_FILENO ) ! = STDOUT_FILENO )
goto cleanup ;
if ( dup2 ( stderrfd , STDERR_FILENO ) ! = STDERR_FILENO )
goto cleanup ;
/* SUS is crazy here, hence the cast */
execve ( argv [ 0 ] , ( char * const * ) argv , ( char * const * ) env ) ;
2006-08-24 21:46:28 +00:00
cleanup :
2007-01-19 20:30:05 +00:00
if ( stdinfd ! = - 1 )
close ( stdinfd ) ;
if ( stderrfd ! = - 1 )
close ( stderrfd ) ;
2006-08-24 21:46:28 +00:00
}
int virtTestCaptureProgramOutput ( const char * const argv [ ] ,
2007-01-19 20:30:05 +00:00
char * * buf ,
int buflen ) {
int pipefd [ 2 ] ;
if ( pipe ( pipefd ) < 0 )
return - 1 ;
int pid = fork ( ) ;
switch ( pid ) {
2006-08-24 21:46:28 +00:00
case 0 :
close ( pipefd [ 0 ] ) ;
2007-01-19 20:30:05 +00:00
virtTestCaptureProgramExecChild ( argv , pipefd [ 1 ] ) ;
close ( pipefd [ 1 ] ) ;
_exit ( 1 ) ;
2006-08-24 21:46:28 +00:00
case - 1 :
return - 1 ;
2007-01-19 20:30:05 +00:00
2006-08-24 21:46:28 +00:00
default :
2007-01-19 20:30:05 +00:00
{
int got = 0 ;
int ret = - 1 ;
int want = buflen - 1 ;
2006-08-24 21:46:28 +00:00
2007-01-19 20:30:05 +00:00
close ( pipefd [ 1 ] ) ;
2006-08-24 21:46:28 +00:00
2007-01-19 20:30:05 +00:00
while ( want ) {
if ( ( ret = read ( pipefd [ 0 ] , ( * buf ) + got , want ) ) < = 0 )
break ;
got + = ret ;
want - = ret ;
}
close ( pipefd [ 0 ] ) ;
2006-08-24 21:46:28 +00:00
2007-01-19 20:30:05 +00:00
if ( ! ret )
( * buf ) [ got ] = ' \0 ' ;
2006-08-24 21:46:28 +00:00
2007-01-19 20:30:05 +00:00
waitpid ( pid , NULL , 0 ) ;
2006-08-24 21:46:28 +00:00
2007-01-19 20:30:05 +00:00
return ret ;
}
}
2006-08-24 21:46:28 +00:00
}
2008-04-18 15:05:29 +00:00
/**
* @ param stream : output stream write to differences to
* @ param expect : expected output text
* @ param actual : actual output text
*
* Display expected and actual output text , trimmed to
* first and last characters at which differences occur
*/
int virtTestDifference ( FILE * stream ,
const char * expect ,
const char * actual )
{
const char * expectStart = expect ;
const char * expectEnd = expect + ( strlen ( expect ) - 1 ) ;
const char * actualStart = actual ;
const char * actualEnd = actual + ( strlen ( actual ) - 1 ) ;
2008-04-30 12:30:55 +00:00
const char * debug ;
2008-04-18 15:05:29 +00:00
2008-04-30 12:30:55 +00:00
if ( ( debug = getenv ( " DEBUG_TESTS " ) ) = = NULL )
2008-04-18 15:05:29 +00:00
return 0 ;
2008-04-30 12:30:55 +00:00
if ( STREQ ( debug , " " ) | |
STREQ ( debug , " 1 " ) ) {
/* Skip to first character where they differ */
while ( * expectStart & & * actualStart & &
* actualStart = = * expectStart ) {
actualStart + + ;
expectStart + + ;
}
2008-04-18 15:05:29 +00:00
2008-04-30 12:30:55 +00:00
/* Work backwards to last character where they differ */
while ( actualEnd > actualStart & &
expectEnd > expectStart & &
* actualEnd = = * expectEnd ) {
actualEnd - - ;
expectEnd - - ;
}
2008-04-18 15:05:29 +00:00
}
/* Show the trimmed differences */
fprintf ( stream , " \n Expect [ " ) ;
if ( ( expectEnd - expectStart + 1 ) & &
fwrite ( expectStart , ( expectEnd - expectStart + 1 ) , 1 , stream ) ! = 1 )
return - 1 ;
fprintf ( stream , " ] \n " ) ;
fprintf ( stream , " Actual [ " ) ;
if ( ( actualEnd - actualStart + 1 ) & &
fwrite ( actualStart , ( actualEnd - actualStart + 1 ) , 1 , stream ) ! = 1 )
return - 1 ;
fprintf ( stream , " ] \n " ) ;
/* Pad to line up with test name ... in virTestRun */
fprintf ( stream , " ... " ) ;
return 0 ;
}