home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / tools / ctestfw / ctest.c next >
Encoding:
C/C++ Source or Header  |  1999-08-16  |  12.5 KB  |  518 lines

  1. /*  
  2. *****************************************************************************************
  3. *                                                                                       *
  4. * COPYRIGHT:                                                                            *
  5. *   (C) Copyright Taligent, Inc.,  1996, 1997                                           *
  6. *   (C) Copyright International Business Machines Corporation,  1999                    *
  7. *   Licensed Material - Program-Property of IBM - All Rights Reserved.                  *
  8. *   US Government Users Restricted Rights - Use, duplication, or disclosure             *
  9. *   restricted by GSA ADP Schedule Contract with IBM Corp.                              *
  10. *                                                                                       *
  11. *****************************************************************************************
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <assert.h>
  17. #include <stdarg.h>
  18.  
  19. /* NOTES:
  20.    3/20/1999 srl - strncpy called w/o setting nulls at the end 
  21.  */
  22.  
  23. #define MAXTESTNAME 128
  24. #define MAXTESTS  512
  25. #define MAX_TEST_LOG 4096
  26.  
  27. struct TestNode
  28. {
  29.   char name[MAXTESTNAME];
  30.   void (*test)();
  31.   struct TestNode* sibling;
  32.   struct TestNode* child;
  33. };
  34.  
  35. typedef enum { RUNTESTS, SHOWTESTS } TestMode;
  36. #define TEST_SEPARATOR '/'
  37.  
  38. #include "ctest.h"
  39.  
  40. char ERROR_LOG[MAX_TEST_LOG][MAXTESTNAME];
  41.  
  42. static TestNode* addTestNode( TestNode *root, const char *name );
  43.  
  44. static TestNode* createTestNode();
  45.  
  46. static int strncmp_nullcheck( const char* s1,
  47.                   const char* s2,
  48.                   int n );
  49.  
  50. static void getNextLevel( const char* name,
  51.               int* nameLen,
  52.               const char** nextName );
  53.  
  54. static void iterateTestsWithLevel( const TestNode *root, int len, 
  55.                    const TestNode** list,
  56.                    TestMode mode);
  57. /* If we need to make the framework multi-thread safe
  58.    we need to pass around the following 3 vars
  59. */
  60.  
  61. static void help ( const char *argv0 );
  62.  
  63. static int ERRONEOUS_FUNCTION_COUNT = 0;
  64.  int ERROR_COUNT = 0;
  65. static int INDENT_LEVEL = 0;
  66.  int VERBOSITY = 0; /* be No-verbose by default */
  67.  int ERR_MSG =1; /*error messages will be displayed by default*/
  68. /*-------------------------------------------*/
  69.  
  70. /* strncmp that also makes sure there's a \0 at s2[0] */
  71. int strncmp_nullcheck( const char* s1,
  72.                const char* s2,
  73.                int n )
  74. {
  75.   if ( s2[n] != 0 )    return 3; /* null check fails */
  76.   else  return strncmp ( s1, s2, n );
  77. }
  78.  
  79. void getNextLevel( const char* name,
  80.            int* nameLen,
  81.            const char** nextName )
  82. {
  83.   /* Get the next component of the name */
  84.   *nextName = strchr(name, TEST_SEPARATOR);
  85.   
  86.   if( *nextName != 0 )
  87.     {
  88.       char n[255];
  89.       *nameLen = (*nextName) - name;
  90.       (*nextName)++; /* skip '/' */
  91.       strncpy(n, name, *nameLen);
  92.       n[*nameLen] = 0;
  93.       /*      printf("->%s-< [%d] -> [%s]\n", name, *nameLen, *nextName);*/
  94.     }
  95.   else    *nameLen = strlen(name);  
  96. }
  97.  
  98. TestNode *createTestNode( )
  99. {
  100.   TestNode *newNode;
  101.   
  102.   newNode = (TestNode*)malloc ( sizeof ( TestNode ) );
  103.   
  104.   newNode->name[0]  = '\0';
  105.   newNode->test = NULL;
  106.   newNode->sibling = NULL;
  107.   newNode->child = NULL;    
  108.   
  109.   return  newNode;
  110. }
  111.  
  112. void addTest ( TestNode** root,
  113.            TestFunctionPtr test,
  114.            const char* name )
  115. {
  116.   TestNode *newNode;
  117.   
  118.   /*if this is the first Test created*/
  119.   if (*root == NULL) *root = createTestNode();
  120.   
  121.   newNode = addTestNode( *root, name );
  122.   assert(newNode != 0 );
  123.   /*  printf("addTest: nreName = %s\n", newNode->name );*/
  124.   
  125.   newNode->test = test;
  126. }
  127.  
  128. /* non recursive insert function */
  129. TestNode *addTestNode ( TestNode *root, const char *name )
  130. {
  131.   const char* nextName;
  132.   TestNode *nextNode, *curNode;
  133.   int nameLen; /* length of current 'name' */
  134.   
  135.   /* remove leading slash */
  136.   if ( *name == TEST_SEPARATOR )  name++;    
  137.   
  138.   curNode = root;
  139.   
  140.   for(;;)
  141.     {
  142.       /* Start with the next child */
  143.       nextNode = curNode->child;
  144.       
  145.       getNextLevel ( name, &nameLen, &nextName );
  146.       
  147.       /*      printf("* %s\n", name );*/
  148.       
  149.       /* if nextNode is already null, then curNode has no children
  150.      -- add them */
  151.       if( nextNode == NULL )
  152.     {
  153.       /* Add all children of the node */
  154.       do
  155.         {
  156.           curNode->child = createTestNode ( );
  157.           
  158.           /* Get the next component of the name */
  159.           getNextLevel ( name, &nameLen, &nextName );
  160.           
  161.           /* update curName to have the next name segment */
  162.           strncpy ( curNode->child->name , name, nameLen );
  163.           curNode->child->name[nameLen] = 0;
  164.           /* printf("*** added %s\n", curNode->child->name );*/
  165.           curNode = curNode->child;
  166.           name = nextName;
  167.         }
  168.       while( name != NULL );
  169.       
  170.       return curNode;
  171.     }
  172.       
  173.       /* Search across for the name */
  174.       while (strncmp_nullcheck ( name, nextNode->name, nameLen) != 0 )
  175.     {
  176.       curNode = nextNode;
  177.       nextNode = nextNode -> sibling;
  178.       
  179.       if ( nextNode == NULL )
  180.         {
  181.           /* Did not find 'name' on this level. */
  182.           nextNode = createTestNode ( );
  183.           strncpy( nextNode->name, name, nameLen );
  184.           nextNode->name[nameLen] = 0;
  185.           curNode->sibling = nextNode;
  186.           break;
  187.         }
  188.     }
  189.       
  190.       /* nextNode matches 'name' */
  191.       
  192.       if (nextName == NULL) /* end of the line */
  193.     {
  194.       return nextNode;
  195.     }
  196.       
  197.       /* Loop again with the next item */
  198.       name = nextName;
  199.       curNode = nextNode;
  200.     }
  201. }
  202.  
  203. void iterateTestsWithLevel ( const TestNode* root,
  204.                  int len, 
  205.                  const TestNode** list,
  206.                  TestMode mode)
  207. {
  208.   int i;
  209.   int saveIndent;
  210.  
  211.   char pathToFunction[MAXTESTNAME] = "";
  212.   char separatorString[2] = { TEST_SEPARATOR, '\0'};
  213.  
  214.   if ( root == NULL )    return;
  215.  
  216.   list[len++] = root;       
  217.  
  218.   for ( i=0;i<(len-1);i++ )
  219.     {
  220.       strcat(pathToFunction, list[i]->name);
  221.       strcat(pathToFunction, separatorString);
  222.     }
  223.  
  224.   strcat(pathToFunction, list[i]->name);
  225.  
  226.   INDENT_LEVEL = len;
  227.   if ( (mode == RUNTESTS) && (root->test != NULL)) 
  228.     {
  229.       int myERROR_COUNT = ERROR_COUNT;
  230.       root->test();
  231.       if (myERROR_COUNT != ERROR_COUNT)
  232.     {
  233.  
  234.       log_info("---[%d ERRORS] ", ERROR_COUNT - myERROR_COUNT);
  235.       strcpy(ERROR_LOG[ERRONEOUS_FUNCTION_COUNT++], pathToFunction);
  236.     }
  237.       else log_info("---[OK] ");
  238.     }
  239.  
  240.  
  241.   /* we want these messages to be at 0 indent. so just push the indent level breifly. */
  242.   saveIndent = INDENT_LEVEL;
  243.   INDENT_LEVEL = 0;
  244.   log_info("%s%s%c\n", (list[i]->test||mode==SHOWTESTS)?"---":"",pathToFunction, list[i]->test?'\0':TEST_SEPARATOR );
  245.   INDENT_LEVEL = saveIndent;
  246.  
  247.   iterateTestsWithLevel ( root->child, len, list, mode );
  248.  
  249.   len--;
  250.  
  251.   if ( len != 0 ) /* DO NOT iterate over siblings of the root. */
  252.       iterateTestsWithLevel ( root->sibling, len, list, mode );
  253. }
  254.  
  255.  
  256.  
  257. void showTests ( const TestNode *root )
  258. {
  259.   /* make up one for them */
  260.   const TestNode *aList[MAXTESTS];
  261.  
  262.   if (root == NULL) log_err("TEST CAN'T BE FOUND!");
  263.   
  264.   iterateTestsWithLevel ( root, 0, aList, SHOWTESTS );
  265.   
  266. }
  267.  
  268. void runTests ( const TestNode *root )
  269. {
  270.   int i;
  271.   const TestNode *aList[MAXTESTS];
  272.   /* make up one for them */
  273.   
  274.  
  275.   if (root == NULL) log_err("TEST CAN'T BE FOUND!\n");
  276.  
  277.   ERRONEOUS_FUNCTION_COUNT = ERROR_COUNT = 0;  
  278.   iterateTestsWithLevel ( root, 0, aList, RUNTESTS );
  279.   
  280.   /*print out result summary*/
  281.   
  282.   if (ERROR_COUNT)
  283.     {
  284.       log_info("\nSUMMARY:\n******* [Total error count:\t%d]\n Errors in\n", ERROR_COUNT);
  285.       for (i=0;i < ERRONEOUS_FUNCTION_COUNT; i++) log_info("[%s]\n",ERROR_LOG[i]);
  286.     }
  287.   else 
  288.     {
  289.       log_info("\n[All tests passed successfully...]\n");
  290.     }
  291.  
  292. }
  293.  
  294. const TestNode* getTest(const TestNode* root, const char* name)
  295. {
  296.   const char* nextName;
  297.   TestNode *nextNode;
  298.   const TestNode* curNode;
  299.   int nameLen; /* length of current 'name' */
  300.   
  301.   if (root == NULL) log_err("TEST CAN'T BE FOUND!\n");
  302.   /* remove leading slash */
  303.   if ( *name == TEST_SEPARATOR )  name++;    
  304.   
  305.   curNode = root;
  306.   
  307.   for(;;)
  308.     {
  309.       /* Start with the next child */
  310.       nextNode = curNode->child;
  311.       
  312.       getNextLevel ( name, &nameLen, &nextName );
  313.       
  314.       /*      printf("* %s\n", name );*/
  315.       
  316.       /* if nextNode is already null, then curNode has no children
  317.      -- add them */
  318.       if( nextNode == NULL )
  319.     {
  320.       return NULL;
  321.     }
  322.       
  323.       /* Search across for the name */
  324.       while (strncmp_nullcheck ( name, nextNode->name, nameLen) != 0 )
  325.     {
  326.       curNode = nextNode;
  327.       nextNode = nextNode -> sibling;
  328.       
  329.       if ( nextNode == NULL )
  330.         {
  331.           /* Did not find 'name' on this level. */
  332.           return NULL;
  333.         }
  334.     }
  335.       
  336.       /* nextNode matches 'name' */
  337.       
  338.       if (nextName == NULL) /* end of the line */
  339.     {
  340.       return nextNode;
  341.     }
  342.       
  343.       /* Loop again with the next item */
  344.       name = nextName;
  345.       curNode = nextNode;
  346.     }
  347. }
  348.  
  349. void log_err(const char* pattern, ...)
  350. {
  351.   va_list ap;
  352.   if( ERR_MSG == FALSE){
  353.       ERROR_COUNT++;
  354.       return;
  355.   }
  356.   va_start(ap, pattern);
  357.   fprintf(stdout, "%-*s", INDENT_LEVEL," " );
  358.   vfprintf(stderr, pattern, ap);
  359.   va_end(ap);
  360.   
  361.   ERROR_COUNT++;
  362. }
  363.  
  364. void log_info(const char* pattern, ...)
  365. {
  366.   va_list ap;
  367.   
  368.   va_start(ap, pattern);
  369.   fprintf(stdout, "%-*s", INDENT_LEVEL," " );
  370.   vfprintf(stdout, pattern, ap);
  371.   va_end(ap);
  372. }
  373.  
  374. void log_verbose(const char* pattern, ...)
  375. {
  376.   va_list ap;
  377.   
  378.   if ( VERBOSITY == FALSE )
  379.     return;
  380.  
  381.   va_start(ap, pattern);
  382.   fprintf(stdout, "%-*s", INDENT_LEVEL," " );
  383.   vfprintf(stdout, pattern, ap);
  384.   va_end(ap);
  385. }
  386.  
  387.  
  388.  
  389.  
  390. int processArgs(const TestNode* root,
  391.              int argc,
  392.              const char** argv)
  393. {
  394. /**
  395.  * This main will parse the l, v, h, n, and path arguments
  396.  */
  397.   const TestNode*    toRun;
  398.   int                i;
  399.   int                doList = FALSE;
  400.   int                runAll = FALSE;
  401.   int                           subtreeOptionSeen = FALSE;
  402.  
  403.   int                           errorCount = 0;
  404.   
  405.   toRun = root;
  406.   VERBOSITY = FALSE;
  407.   ERR_MSG = TRUE;
  408.  
  409.   for( i=1; i<argc; i++)
  410.   {
  411.     if ( argv[i][0] == '/' )
  412.     {
  413.         printf("Selecting subtree '%s'\n", argv[i]);
  414.  
  415.         if ( argv[i][1] == 0 )
  416.             toRun = root;
  417.         else
  418.             toRun = getTest(root, argv[i]);
  419.  
  420.         if ( toRun == NULL )
  421.         {
  422.             printf("* Could not find any matching subtree\n");
  423.             return -1;
  424.         }
  425.  
  426.         if( doList == TRUE)
  427.           showTests(toRun);
  428.         else if( runAll == TRUE)
  429.           runTests(toRun);
  430.         else
  431.           runTests(toRun);
  432.  
  433.         errorCount += ERROR_COUNT;
  434.  
  435.         subtreeOptionSeen = TRUE;
  436.     }
  437.     else if (strcmp( argv[i], "-v" )==0 )
  438.     {
  439.         VERBOSITY = TRUE;
  440.     }
  441.     else if (strcmp( argv[i], "-verbose")==0 )
  442.     {
  443.         VERBOSITY = TRUE;
  444.     }
  445.     else if (strcmp( argv[i], "-l" )==0 )
  446.     {
  447.         doList = TRUE;
  448.     }
  449.     else if (strcmp( argv[i], "-all") ==0)
  450.     {
  451.         runAll = TRUE;
  452.     }
  453.     else if(strcmp( argv[i], "-a") == 0)
  454.     {
  455.         runAll = TRUE;
  456.     }
  457.     else if(strcmp( argv[i], "-n") == 0)
  458.     {
  459.         ERR_MSG = FALSE;
  460.     }
  461.     else if (strcmp( argv[i], "-no_err_msg") == 0)
  462.     {
  463.         ERR_MSG = FALSE;
  464.     }
  465.     else if (strcmp( argv[1], "-h" )==0 )
  466.     {
  467.         help( argv[0] );
  468.         return 0;
  469.     }
  470.     else
  471.     {
  472.         printf("* unknown option: %s\n", argv[i]);
  473.         help( argv[0] );
  474.         return -1;
  475.     }
  476.   }
  477.  
  478.   if( subtreeOptionSeen == FALSE) /* no other subtree given, run the default */
  479.     {
  480.       if( doList == TRUE)
  481.     showTests(toRun);
  482.       else if( runAll == TRUE)
  483.     runTests(toRun);
  484.       else
  485.     runTests(toRun);
  486.       
  487.       errorCount += ERROR_COUNT;
  488.     }
  489.   else
  490.     {
  491.       if( ( doList == FALSE ) && ( errorCount > 0 ) )
  492.     printf(" Total errors: %d\n", errorCount );
  493.     }
  494.  
  495.   return errorCount; /* total error count */
  496. }
  497.  
  498. /**
  499.  * Display program invocation arguments
  500.  */
  501.  
  502. void help ( const char *argv0 )
  503. {
  504.     printf("Usage: %s [ -l ] [ -v ] [ -verbose] [-a] [ -all] [-n] \n [ -no_err_msg] [ -h ] [ /path/to/test ]\n",
  505.             argv0);
  506.     printf("    -l To get a list of test names\n");
  507.     printf("    -all To run all the test\n");
  508.     printf("    -a To run all the test(same a -all)\n");
  509.     printf("    -verbose To turn ON verbosity\n");
  510.     printf("    -v To turn ON verbosity(same as -verbose)\n");
  511.     printf("    -h To print this message\n");
  512.     printf("    -n To turn OFF printing error messages\n");
  513.     printf("    -no_err_msg (same as -n) \n");
  514.     printf("    -[/subtest] To run a subtest \n");
  515.     printf("    eg: to run just the utility tests type: cintltest /tsutil) \n");
  516. }
  517.  
  518.