2005-10-24 23:26:25 +08:00
/** \file fish_tests.c
2005-09-20 21:26:39 +08:00
Various bug and feature tests . Compiled and run by make test .
*/
# include "config.h"
2006-02-28 21:17:16 +08:00
2005-09-20 21:26:39 +08:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <string.h>
# include <unistd.h>
# include <errno.h>
# include <unistd.h>
# include <termios.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
2012-01-28 03:43:45 +08:00
# include <stdarg.h>
# include <assert.h>
# include <algorithm>
2005-09-20 21:26:39 +08:00
# ifdef HAVE_GETOPT_H
# include <getopt.h>
# endif
# include <signal.h>
# include <locale.h>
# include <dirent.h>
2007-09-24 04:59:18 +08:00
# include <time.h>
2005-09-20 21:26:39 +08:00
2006-02-28 21:17:16 +08:00
# include "fallback.h"
2005-09-20 21:26:39 +08:00
# include "util.h"
2006-02-28 21:17:16 +08:00
2005-09-20 21:26:39 +08:00
# include "common.h"
# include "proc.h"
# include "reader.h"
# include "builtin.h"
# include "function.h"
2012-01-28 03:43:45 +08:00
# include "autoload.h"
2005-09-20 21:26:39 +08:00
# include "complete.h"
# include "wutil.h"
# include "env.h"
# include "expand.h"
# include "parser.h"
# include "tokenizer.h"
2005-10-27 20:20:03 +08:00
# include "output.h"
# include "exec.h"
# include "event.h"
2007-05-11 03:11:28 +08:00
# include "path.h"
# include "halloc.h"
2006-02-12 19:20:30 +08:00
# include "halloc_util.h"
2005-09-20 21:26:39 +08:00
2007-09-24 04:59:18 +08:00
/**
The number of tests to run
*/
# define ESCAPE_TEST_COUNT 1000000
/**
The average length of strings to unescape
*/
# define ESCAPE_TEST_LENGTH 100
/**
The higest character number of character to try and escape
*/
# define ESCAPE_TEST_CHAR 4000
2005-10-24 23:26:25 +08:00
/**
Number of laps to run performance testing loop
*/
2005-09-20 21:26:39 +08:00
# define LAPS 50
2006-06-20 08:50:10 +08:00
/**
The result of one of the test passes
*/
# define NUM_ANS L"-7 99999999 1234567 deadbeef DEADBEEFDEADBEEF"
2005-10-24 23:26:25 +08:00
/**
Number of encountered errors
*/
2005-09-20 21:26:39 +08:00
static int err_count = 0 ;
2005-10-24 23:26:25 +08:00
/**
Print formatted output
*/
2011-12-27 11:18:46 +08:00
static void say ( const wchar_t * blah , . . . )
2005-09-20 21:26:39 +08:00
{
va_list va ;
va_start ( va , blah ) ;
vwprintf ( blah , va ) ;
2011-12-27 11:18:46 +08:00
va_end ( va ) ;
2005-09-20 21:26:39 +08:00
wprintf ( L " \n " ) ;
}
2005-10-24 23:26:25 +08:00
/**
Print formatted error string
*/
2011-12-27 11:18:46 +08:00
static void err ( const wchar_t * blah , . . . )
2005-09-20 21:26:39 +08:00
{
va_list va ;
va_start ( va , blah ) ;
err_count + + ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
wprintf ( L " Error: " ) ;
vwprintf ( blah , va ) ;
2011-12-27 11:18:46 +08:00
va_end ( va ) ;
2005-09-20 21:26:39 +08:00
wprintf ( L " \n " ) ;
}
2005-10-24 23:26:25 +08:00
/**
Test stack functionality
*/
2005-09-20 21:26:39 +08:00
static int stack_test ( int elements )
{
2006-08-01 00:55:11 +08:00
long i ;
2005-09-20 21:26:39 +08:00
int res = 1 ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
array_list_t s ;
2011-12-27 11:18:46 +08:00
al_init ( & s ) ;
2005-09-20 21:26:39 +08:00
for ( i = 0 ; i < elements ; i + + )
{
2006-08-01 00:55:11 +08:00
long foo ;
2005-09-20 21:26:39 +08:00
2006-08-01 00:55:11 +08:00
al_push_long ( & s , i ) ;
al_push_long ( & s , i ) ;
2011-12-27 11:18:46 +08:00
2006-08-01 00:55:11 +08:00
if ( ( foo = al_pop_long ( & s ) ) ! = i )
2005-09-20 21:26:39 +08:00
{
err ( L " Unexpected data " ) ;
2011-12-27 11:18:46 +08:00
res = 0 ;
2005-09-20 21:26:39 +08:00
break ;
}
}
for ( i = 0 ; i < elements ; i + + )
{
2006-08-01 00:55:11 +08:00
long foo ;
2011-12-27 11:18:46 +08:00
2006-08-01 00:55:11 +08:00
if ( ( foo = al_pop_long ( & s ) ) ! = ( elements - i - 1 ) )
2005-09-20 21:26:39 +08:00
{
err ( L " Unexpected data " ) ;
res = 0 ;
break ;
2011-12-27 11:18:46 +08:00
}
2005-09-20 21:26:39 +08:00
}
al_destroy ( & s ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
return res ;
}
2005-10-24 23:26:25 +08:00
/**
Hash function for pointers
*/
2006-07-19 01:27:02 +08:00
static int hash_func ( void * data )
2005-09-20 21:26:39 +08:00
{
/* srand( (int)data );
return rand ( ) ;
*/
2006-10-22 06:59:00 +08:00
int foo = ( int ) ( long ) data ;
2011-12-27 11:18:46 +08:00
return 127 * ( ( foo ^ 0xefc7e214 ) ) ^ ( foo < < 11 ) ;
2005-09-20 21:26:39 +08:00
}
2005-10-24 23:26:25 +08:00
/**
Pointer hash comparison function
*/
2006-07-19 01:27:02 +08:00
static int compare_func ( void * key1 , void * key2 )
2005-09-20 21:26:39 +08:00
{
return key1 = = key2 ;
}
2005-10-24 23:26:25 +08:00
/**
Hashtable test
*/
2006-10-22 06:59:00 +08:00
static int hash_test ( long elements )
2005-09-20 21:26:39 +08:00
{
2006-10-22 06:59:00 +08:00
long i ;
2005-09-20 21:26:39 +08:00
int res = 1 ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
hash_table_t h ;
hash_init ( & h , hash_func , compare_func ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
for ( i = 1 ; i < elements + 1 ; i + + )
{
2011-12-27 11:18:46 +08:00
hash_put ( & h , ( void * ) i , ( void * ) ( 100l - i ) ) ;
2005-09-20 21:26:39 +08:00
}
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
for ( i = 1 ; i < elements + 1 ; i + + )
{
2006-10-22 06:59:00 +08:00
if ( ( long ) hash_get ( & h , ( void * ) i ) ! = ( 100l - i ) )
2005-09-20 21:26:39 +08:00
{
err ( L " Key %d gave data %d, expected data %d " ,
2011-12-27 11:18:46 +08:00
i ,
2006-10-22 06:59:00 +08:00
( long ) hash_get ( & h , ( void * ) i ) ,
100l - i ) ;
2005-09-20 21:26:39 +08:00
res = 0 ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
break ;
}
}
if ( hash_get_count ( & h ) ! = elements )
{
err ( L " Table holds %d elements, should hold %d elements " ,
hash_get_count ( & h ) ,
elements ) ;
res = 0 ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
}
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
for ( i = 1 ; i < elements + 1 ; i + = 2 )
{
hash_remove ( & h , ( void * ) i , 0 , 0 ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
}
if ( hash_get_count ( & h ) ! = ( ( elements ) / 2 ) )
{
err ( L " Table contains %d elements, should contain %d elements " ,
hash_get_count ( & h ) ,
elements / 2 ) ;
res = 0 ;
}
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
for ( i = 1 ; i < elements + 1 ; i + + )
{
2006-10-22 06:59:00 +08:00
if ( hash_contains ( & h , ( void * ) i ) ! = ( i + 1l ) % 2l )
2005-09-20 21:26:39 +08:00
{
if ( i % 2 )
err ( L " Key %d remains, should be deleted " ,
i ) ;
else
err ( L " Key %d does not exist " ,
i ) ;
res = 0 ;
break ;
}
}
hash_destroy ( & h ) ;
return res ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
}
2005-10-24 23:26:25 +08:00
/**
Arraylist test
*/
2006-05-19 22:10:23 +08:00
static void al_test ( int sz )
2005-09-20 21:26:39 +08:00
{
2011-12-27 11:18:46 +08:00
long i ;
2005-09-20 21:26:39 +08:00
array_list_t l ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
al_init ( & l ) ;
2011-12-27 11:18:46 +08:00
2006-08-01 00:55:11 +08:00
al_set_long ( & l , 1 , 7L ) ;
al_set_long ( & l , sz , 7L ) ;
2011-12-27 11:18:46 +08:00
2006-08-01 00:31:19 +08:00
if ( al_get_count ( & l ) ! = maxi ( sz + 1 , 2 ) )
2005-09-20 21:26:39 +08:00
err ( L " Wrong number of elements in array list " ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
for ( i = 0 ; i < al_get_count ( & l ) ; i + + )
{
2006-08-01 00:55:11 +08:00
long val = al_get_long ( & l , i ) ;
2005-09-20 21:26:39 +08:00
if ( ( i = = 1 ) | | ( i = = sz ) )
{
if ( val ! = 7 )
err ( L " Canary changed to %d at index %d " , val , i ) ;
}
else
{
if ( val ! = 0 )
err ( L " False canary %d found at index %d " , val , i ) ;
}
}
}
2005-10-24 23:26:25 +08:00
/**
Stringbuffer test
*/
2005-09-20 21:26:39 +08:00
static void sb_test ( )
{
string_buffer_t b ;
int res ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
sb_init ( & b ) ;
2011-12-27 11:18:46 +08:00
2006-02-12 19:20:30 +08:00
if ( ( res = sb_printf ( & b , L " %ls%s " , L " Testing " , " string_buffer_t " ) ) = = - 1 )
2005-09-20 21:26:39 +08:00
{
err ( L " Error %d while testing stringbuffers " , res ) ;
}
2011-12-27 11:18:46 +08:00
if ( ( res = sb_printf ( & b , L " %ls " , L " functionality " ) ) = = - 1 )
2005-09-20 21:26:39 +08:00
{
err ( L " Error %d while testing stringbuffers " , res ) ;
}
2006-02-12 19:20:30 +08:00
2005-09-20 21:26:39 +08:00
say ( ( wchar_t * ) b . buff ) ;
2006-02-12 19:20:30 +08:00
sb_clear ( & b ) ;
sb_printf ( & b , L " %d %u %o %x %llX " , - 7 , 99999999 , 01234567 , 0xdeadbeef , 0xdeadbeefdeadbeefll ) ;
if ( wcscmp ( ( wchar_t * ) b . buff , NUM_ANS ) ! = 0 )
{
err ( L " numerical formating is broken, '%ls' != '%ls' " , ( wchar_t * ) b . buff , NUM_ANS ) ;
}
else
2011-12-27 11:18:46 +08:00
say ( L " numerical formating works " ) ;
2006-02-12 19:20:30 +08:00
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
}
2005-10-24 23:26:25 +08:00
/**
Performs all tests of the util library
*/
2005-09-20 21:26:39 +08:00
static void test_util ( )
{
int i ;
say ( L " Testing utility library " ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
for ( i = 0 ; i < 18 ; i + + )
{
long t1 , t2 ;
stack_test ( 1 < < i ) ;
t1 = get_time ( ) ;
hash_test ( 1 < < i ) ;
t2 = get_time ( ) ;
if ( i > 8 )
say ( L " Hashtable uses %f microseconds per element at size %d " ,
( ( double ) ( t2 - t1 ) ) / ( 1 < < i ) ,
1 < < i ) ;
al_test ( 1 < < i ) ;
}
sb_test ( ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
/*
int i ;
for ( i = 2 ; i < 10000000 ; i * = 2 )
{
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
printf ( " %d " , i ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
t1 = get_time ( ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
if ( ! hash_test ( i ) )
exit ( 0 ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
t2 = get_time ( ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
printf ( " %d \n " , ( t2 - t1 ) / i ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
}
2011-12-27 11:18:46 +08:00
*/
2005-09-20 21:26:39 +08:00
}
2007-09-24 04:59:18 +08:00
/**
Test the escaping / unescaping code by escaping / unescaping random
strings and verifying that the original string comes back .
*/
static void test_escape ( )
{
int i ;
string_buffer_t sb ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
say ( L " Testing escaping and unescaping " ) ;
sb_init ( & sb ) ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
for ( i = 0 ; i < ESCAPE_TEST_COUNT ; i + + )
{
wchar_t * o , * e , * u ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
sb_clear ( & sb ) ;
while ( rand ( ) % ESCAPE_TEST_LENGTH )
{
sb_append_char ( & sb , ( rand ( ) % ESCAPE_TEST_CHAR ) + 1 ) ;
}
o = ( wchar_t * ) sb . buff ;
e = escape ( o , 1 ) ;
u = unescape ( e , 0 ) ;
if ( ! o | | ! e | | ! u )
{
err ( L " Escaping cycle of string %ls produced null pointer on %ls " , o , e ? L " unescaping " : L " escaping " ) ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
}
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
if ( wcscmp ( o , u ) )
{
err ( L " Escaping cycle of string %ls produced different string %ls " , o , u ) ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
}
free ( e ) ;
free ( u ) ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
}
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
}
/**
Test wide / narrow conversion by creating random strings and
verifying that the original string comes back thorugh double
conversion .
*/
static void test_convert ( )
{
2011-12-27 11:18:46 +08:00
/* char o[] =
2007-09-24 04:59:18 +08:00
{
- 17 , - 128 , - 121 , - 68 , 0
}
;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
wchar_t * w = str2wcs ( o ) ;
char * n = wcs2str ( w ) ;
int i ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
for ( i = 0 ; o [ i ] ; i + + )
{
bitprint ( o [ i ] ) ; ;
//wprintf(L"%d ", o[i]);
}
wprintf ( L " \n " ) ;
for ( i = 0 ; w [ i ] ; i + + )
{
wbitprint ( w [ i ] ) ; ;
//wprintf(L"%d ", w[i]);
}
wprintf ( L " \n " ) ;
for ( i = 0 ; n [ i ] ; i + + )
{
bitprint ( n [ i ] ) ; ;
//wprintf(L"%d ", n[i]);
}
wprintf ( L " \n " ) ;
return ;
*/
int i ;
buffer_t sb ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
say ( L " Testing wide/narrow string conversion " ) ;
b_init ( & sb ) ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
for ( i = 0 ; i < ESCAPE_TEST_COUNT ; i + + )
{
wchar_t * w ;
char * o , * n ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
char c ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
sb . used = 0 ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
while ( rand ( ) % ESCAPE_TEST_LENGTH )
{
c = rand ( ) ;
b_append ( & sb , & c , 1 ) ;
}
c = 0 ;
b_append ( & sb , & c , 1 ) ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
o = ( char * ) sb . buff ;
w = str2wcs ( o ) ;
n = wcs2str ( w ) ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
if ( ! o | | ! w | | ! n )
{
2011-12-27 11:18:46 +08:00
err ( L " Line %d - Conversion cycle of string %s produced null pointer on %s " , __LINE__ , o , w ? L " str2wcs " : L " wcs2str " ) ;
2007-09-24 04:59:18 +08:00
}
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
if ( strcmp ( o , n ) )
{
2011-12-27 11:18:46 +08:00
err ( L " Line %d - %d: Conversion cycle of string %s produced different string %s " , __LINE__ , i , o , n ) ;
2007-09-24 04:59:18 +08:00
}
free ( w ) ;
free ( n ) ;
2011-12-27 11:18:46 +08:00
2007-09-24 04:59:18 +08:00
}
}
2005-10-24 23:26:25 +08:00
/**
Test the tokenizer
*/
2005-09-20 21:26:39 +08:00
static void test_tok ( )
{
tokenizer t ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
say ( L " Testing tokenizer " ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
say ( L " Testing invalid input " ) ;
tok_init ( & t , 0 , 0 ) ;
if ( tok_last_type ( & t ) ! = TOK_ERROR )
{
err ( L " Invalid input to tokenizer was undetected " ) ;
}
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
say ( L " Testing use of broken tokenizer " ) ;
if ( ! tok_has_next ( & t ) )
{
err ( L " tok_has_next() should return 1 once on broken tokenizer " ) ;
}
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
tok_next ( & t ) ;
if ( tok_last_type ( & t ) ! = TOK_ERROR )
{
err ( L " Invalid input to tokenizer was undetected " ) ;
}
/*
This should crash if there is a bug . No reliable way to detect otherwise .
*/
say ( L " Test destruction of broken tokenizer " ) ;
tok_destroy ( & t ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
{
2011-12-27 11:18:46 +08:00
const wchar_t * str = L " string <redirection 2>&1 'nested \" quoted \" '(string containing subshells ){and,brackets}$as[$well (as variable arrays)] " ;
const int types [ ] =
2005-09-20 21:26:39 +08:00
{
TOK_STRING , TOK_REDIRECT_IN , TOK_STRING , TOK_REDIRECT_FD , TOK_STRING , TOK_STRING , TOK_END
}
;
2011-12-27 11:18:46 +08:00
size_t i ;
2005-09-20 21:26:39 +08:00
say ( L " Test correct tokenization " ) ;
for ( i = 0 , tok_init ( & t , str , 0 ) ; i < ( sizeof ( types ) / sizeof ( int ) ) ; i + + , tok_next ( & t ) )
{
if ( types [ i ] ! = tok_last_type ( & t ) )
{
err ( L " Tokenization error: " ) ;
2011-12-27 11:18:46 +08:00
wprintf ( L " Token number %d of string \n '%ls' \n , expected token type %ls, got token '%ls' of type %ls \n " ,
2005-09-20 21:26:39 +08:00
i + 1 ,
str ,
tok_get_desc ( types [ i ] ) ,
tok_last ( & t ) ,
tok_get_desc ( tok_last_type ( & t ) ) ) ;
}
}
}
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
}
2005-10-24 23:26:25 +08:00
/**
Test the parser
*/
2005-09-20 21:26:39 +08:00
static void test_parser ( )
{
say ( L " Testing parser " ) ;
2011-12-27 11:18:46 +08:00
2012-01-28 03:43:45 +08:00
parser_t parser ( PARSER_TYPE_GENERAL ) ;
2005-09-20 21:26:39 +08:00
say ( L " Testing null input to parser " ) ;
2012-01-28 03:43:45 +08:00
if ( ! parser . test ( 0 , 0 , 0 , 0 ) )
2005-09-20 21:26:39 +08:00
{
2012-01-28 03:43:45 +08:00
err ( L " Null input to parser.test undetected " ) ;
2005-09-20 21:26:39 +08:00
}
say ( L " Testing block nesting " ) ;
2012-01-28 03:43:45 +08:00
if ( ! parser . test ( L " if; end " , 0 , 0 , 0 ) )
2005-09-20 21:26:39 +08:00
{
2011-12-27 11:18:46 +08:00
err ( L " Incomplete if statement undetected " ) ;
2005-09-20 21:26:39 +08:00
}
2012-01-28 03:43:45 +08:00
if ( ! parser . test ( L " if test; echo " , 0 , 0 , 0 ) )
2005-09-20 21:26:39 +08:00
{
2011-12-27 11:18:46 +08:00
err ( L " Missing end undetected " ) ;
2005-09-20 21:26:39 +08:00
}
2012-01-28 03:43:45 +08:00
if ( ! parser . test ( L " if test; end; end " , 0 , 0 , 0 ) )
2005-09-20 21:26:39 +08:00
{
2011-12-27 11:18:46 +08:00
err ( L " Unbalanced end undetected " ) ;
2005-09-20 21:26:39 +08:00
}
say ( L " Testing detection of invalid use of builtin commands " ) ;
2012-01-28 03:43:45 +08:00
if ( ! parser . test ( L " case foo " , 0 , 0 , 0 ) )
2005-09-20 21:26:39 +08:00
{
2011-12-27 11:18:46 +08:00
err ( L " 'case' command outside of block context undetected " ) ;
2005-09-20 21:26:39 +08:00
}
2012-01-28 03:43:45 +08:00
if ( ! parser . test ( L " switch ggg; if true; case foo;end;end " , 0 , 0 , 0 ) )
2005-09-20 21:26:39 +08:00
{
2011-12-27 11:18:46 +08:00
err ( L " 'case' command outside of switch block context undetected " ) ;
2005-09-20 21:26:39 +08:00
}
2012-01-28 03:43:45 +08:00
if ( ! parser . test ( L " else " , 0 , 0 , 0 ) )
2005-09-20 21:26:39 +08:00
{
2011-12-27 11:18:46 +08:00
err ( L " 'else' command outside of conditional block context undetected " ) ;
2005-09-20 21:26:39 +08:00
}
2012-01-28 03:43:45 +08:00
if ( ! parser . test ( L " break " , 0 , 0 , 0 ) )
2005-09-20 21:26:39 +08:00
{
2011-12-27 11:18:46 +08:00
err ( L " 'break' command outside of loop block context undetected " ) ;
2005-09-20 21:26:39 +08:00
}
2012-01-28 03:43:45 +08:00
if ( ! parser . test ( L " exec ls|less " , 0 , 0 , 0 ) | | ! parser . test ( L " echo|return " , 0 , 0 , 0 ) )
2005-09-20 21:26:39 +08:00
{
2011-12-27 11:18:46 +08:00
err ( L " Invalid pipe command undetected " ) ;
}
2005-09-20 21:26:39 +08:00
say ( L " Testing basic evaluation " ) ;
2012-01-28 03:43:45 +08:00
#if 0
/* This fails now since the parser takes a wcstring&, and NULL converts to wchar_t * converts to wcstring which crashes (thanks C++) */
if ( ! parser . eval ( 0 , 0 , TOP ) )
2005-09-20 21:26:39 +08:00
{
err ( L " Null input when evaluating undetected " ) ;
2012-01-28 03:43:45 +08:00
}
# endif
if ( ! parser . eval ( L " ls " , 0 , WHILE ) )
2005-09-20 21:26:39 +08:00
{
err ( L " Invalid block mode when evaluating undetected " ) ;
2012-01-28 03:43:45 +08:00
}
}
class test_lru_t : public lru_cache_t < lru_node_t > {
public :
test_lru_t ( ) : lru_cache_t < lru_node_t > ( 16 ) { }
std : : vector < lru_node_t * > evicted_nodes ;
virtual void node_was_evicted ( lru_node_t * node ) {
assert ( find ( evicted_nodes . begin ( ) , evicted_nodes . end ( ) , node ) = = evicted_nodes . end ( ) ) ;
evicted_nodes . push_back ( node ) ;
}
} ;
static void test_lru ( void ) {
say ( L " Testing LRU cache " ) ;
test_lru_t cache ;
std : : vector < lru_node_t * > expected_evicted ;
size_t total_nodes = 20 ;
for ( size_t i = 0 ; i < total_nodes ; i + + ) {
assert ( cache . size ( ) = = std : : min ( i , ( size_t ) 16 ) ) ;
lru_node_t * node = new lru_node_t ( format_val ( i ) ) ;
if ( i < 4 ) expected_evicted . push_back ( node ) ;
// Adding the node the first time should work, and subsequent times should fail
assert ( cache . add_node ( node ) ) ;
assert ( ! cache . add_node ( node ) ) ;
}
assert ( cache . evicted_nodes = = expected_evicted ) ;
cache . evict_all_nodes ( ) ;
assert ( cache . evicted_nodes . size ( ) = = total_nodes ) ;
while ( ! cache . evicted_nodes . empty ( ) ) {
lru_node_t * node = cache . evicted_nodes . back ( ) ;
cache . evicted_nodes . pop_back ( ) ;
delete node ;
}
2005-09-20 21:26:39 +08:00
}
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
/**
2005-12-07 23:57:17 +08:00
Perform parameter expansion and test if the output equals the zero - terminated parameter list supplied .
2005-09-20 21:26:39 +08:00
\ param in the string to expand
\ param flags the flags to send to expand_string
*/
static int expand_test ( const wchar_t * in , int flags , . . . )
{
2011-12-27 11:18:46 +08:00
array_list_t out ;
2005-09-20 21:26:39 +08:00
va_list va ;
int i = 0 ;
int res = 1 ;
wchar_t * arg ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
al_init ( & out ) ;
2006-10-22 06:59:00 +08:00
if ( expand_string ( 0 , wcsdup ( in ) , & out , flags ) )
{
2011-12-27 11:18:46 +08:00
2006-10-22 06:59:00 +08:00
}
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
va_start ( va , flags ) ;
2011-12-27 11:18:46 +08:00
while ( ( arg = va_arg ( va , wchar_t * ) ) ! = 0 )
2005-09-20 21:26:39 +08:00
{
if ( al_get_count ( & out ) = = i )
{
res = 0 ;
break ;
}
2011-12-27 11:18:46 +08:00
if ( wcscmp ( ( wchar_t * ) al_get ( & out , i ) , arg ) ! = 0 )
2005-09-20 21:26:39 +08:00
{
res = 0 ;
break ;
}
2011-12-27 11:18:46 +08:00
i + + ;
2005-09-20 21:26:39 +08:00
}
va_end ( va ) ;
2011-12-27 11:18:46 +08:00
2006-07-19 01:27:02 +08:00
al_foreach ( & out , & free ) ;
2005-09-20 21:26:39 +08:00
return res ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
}
2005-10-24 23:26:25 +08:00
/**
2005-12-07 23:57:17 +08:00
Test globbing and other parameter expansion
2005-10-24 23:26:25 +08:00
*/
2005-09-20 21:26:39 +08:00
static void test_expand ( )
{
2005-12-07 23:57:17 +08:00
say ( L " Testing parameter expansion " ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
if ( ! expand_test ( L " foo " , 0 , L " foo " , 0 ) )
{
err ( L " Strings do not expand to themselves " ) ;
}
if ( ! expand_test ( L " a{b,c,d}e " , 0 , L " abe " , L " ace " , L " ade " , 0 ) )
{
2005-12-07 23:57:17 +08:00
err ( L " Bracket expansion is broken " ) ;
2005-09-20 21:26:39 +08:00
}
if ( ! expand_test ( L " a* " , EXPAND_SKIP_WILDCARDS , L " a* " , 0 ) )
{
2005-12-07 23:57:17 +08:00
err ( L " Cannot skip wildcard expansion " ) ;
2005-09-20 21:26:39 +08:00
}
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
}
2008-01-14 00:47:47 +08:00
/**
Test path functions
*/
2007-05-11 03:11:28 +08:00
static void test_path ( )
{
say ( L " Testing path functions " ) ;
void * context = halloc ( 0 , 0 ) ;
2011-12-27 11:18:46 +08:00
2007-05-11 03:11:28 +08:00
wchar_t * can = path_make_canonical ( context , L " //foo//////bar/ " ) ;
2011-12-27 11:18:46 +08:00
2007-05-11 03:11:28 +08:00
if ( wcscmp ( can , L " /foo/bar " ) )
{
err ( L " Bug in canonical PATH code " ) ;
}
2011-12-27 11:18:46 +08:00
2007-05-11 03:11:28 +08:00
halloc_free ( context ) ;
2011-12-27 11:18:46 +08:00
2007-05-11 03:11:28 +08:00
}
2005-10-24 23:26:25 +08:00
/**
Test speed of completion calculations
*/
2005-09-20 21:26:39 +08:00
void perf_complete ( )
{
wchar_t c ;
array_list_t out ;
long long t1 , t2 ;
int matches = 0 ;
double t ;
wchar_t str [ 3 ] =
{
2011-12-27 11:18:46 +08:00
0 , 0 , 0
2005-09-20 21:26:39 +08:00
}
;
int i ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
say ( L " Testing completion performance " ) ;
al_init ( & out ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
reader_push ( L " " ) ;
say ( L " Here we go " ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
t1 = get_time ( ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
for ( c = L ' a ' ; c < = L ' z ' ; c + + )
{
str [ 0 ] = c ;
reader_set_buffer ( str , 0 ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
complete ( str , & out ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
matches + = al_get_count ( & out ) ;
2011-12-27 11:18:46 +08:00
2006-07-19 01:27:02 +08:00
al_foreach ( & out , & free ) ;
2005-09-20 21:26:39 +08:00
al_truncate ( & out , 0 ) ;
}
t2 = get_time ( ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
t = ( double ) ( t2 - t1 ) / ( 1000000 * 26 ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
say ( L " One letter command completion took %f seconds per completion, %f microseconds/match " , t , ( double ) ( t2 - t1 ) / matches ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
matches = 0 ;
t1 = get_time ( ) ;
for ( i = 0 ; i < LAPS ; i + + )
{
str [ 0 ] = ' a ' + ( rand ( ) % 26 ) ;
str [ 1 ] = ' a ' + ( rand ( ) % 26 ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
reader_set_buffer ( str , 0 ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
complete ( str , & out ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
matches + = al_get_count ( & out ) ;
2011-12-27 11:18:46 +08:00
2006-07-19 01:27:02 +08:00
al_foreach ( & out , & free ) ;
2005-09-20 21:26:39 +08:00
al_truncate ( & out , 0 ) ;
}
t2 = get_time ( ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
t = ( double ) ( t2 - t1 ) / ( 1000000 * LAPS ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
say ( L " Two letter command completion took %f seconds per completion, %f microseconds/match " , t , ( double ) ( t2 - t1 ) / matches ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
al_destroy ( & out ) ;
reader_pop ( ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
}
2007-05-11 03:11:28 +08:00
2005-10-24 23:26:25 +08:00
/**
2011-12-27 11:18:46 +08:00
Main test
2005-10-24 23:26:25 +08:00
*/
2005-09-20 21:26:39 +08:00
int main ( int argc , char * * argv )
{
2007-09-24 04:59:18 +08:00
setlocale ( LC_ALL , " " ) ;
srand ( time ( 0 ) ) ;
2005-09-20 21:26:39 +08:00
2005-10-12 18:44:37 +08:00
program_name = L " (ignore) " ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
say ( L " Testing low-level functionality " ) ;
2005-10-12 18:44:37 +08:00
say ( L " Lines beginning with '(ignore):' are not errors, they are warning messages \n generated by the fish parser library when given broken input, and can be \n ignored. All actual errors begin with 'Error:'. " ) ;
2012-01-06 05:58:48 +08:00
set_main_thread ( ) ;
2011-12-27 11:18:46 +08:00
proc_init ( ) ;
2006-02-12 19:20:30 +08:00
halloc_util_init ( ) ;
2011-12-27 11:18:46 +08:00
event_init ( ) ;
2005-09-20 21:26:39 +08:00
function_init ( ) ;
builtin_init ( ) ;
reader_init ( ) ;
2005-10-03 21:09:37 +08:00
env_init ( ) ;
2005-10-06 18:39:01 +08:00
2005-09-20 21:26:39 +08:00
test_util ( ) ;
2007-09-24 04:59:18 +08:00
test_escape ( ) ;
test_convert ( ) ;
2005-09-20 21:26:39 +08:00
test_tok ( ) ;
test_parser ( ) ;
2012-01-28 03:43:45 +08:00
test_lru ( ) ;
2005-09-20 21:26:39 +08:00
test_expand ( ) ;
2007-05-11 03:11:28 +08:00
test_path ( ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
say ( L " Encountered %d errors in low-level tests " , err_count ) ;
/*
Skip performance tests for now , since they seem to hang when running from inside make ( ? )
*/
// say( L"Testing performance" );
// perf_complete();
2011-12-27 11:18:46 +08:00
2005-10-03 21:09:37 +08:00
env_destroy ( ) ;
2011-12-27 11:18:46 +08:00
reader_destroy ( ) ;
2005-09-20 21:26:39 +08:00
builtin_destroy ( ) ;
wutil_destroy ( ) ;
2005-10-06 06:37:08 +08:00
event_destroy ( ) ;
2005-10-14 19:40:33 +08:00
proc_destroy ( ) ;
2006-02-12 19:20:30 +08:00
halloc_util_destroy ( ) ;
2011-12-27 11:18:46 +08:00
2005-09-20 21:26:39 +08:00
}