/* Copyright (c) 2024 PTC Inc. and/or Its Subsidiary Companies. All Rights Reserved. */ /*--------------------------------------------------------------------*\ Pro/TOOLKIT includes \*--------------------------------------------------------------------*/ #include "ProToolkit.h" #include "ProArray.h" /*--------------------------------------------------------------------*\ C System includes \*--------------------------------------------------------------------*/ #include <time.h> #include <string.h> #include <stdlib.h> /*--------------------------------------------------------------------*\ Application includes \*--------------------------------------------------------------------*/ #include "TestError.h" #include "PTApplsUnicodeUtils.h" #include "UtilString.h" /*--------------------------------------------------------------------*\ Application macros \*--------------------------------------------------------------------*/ #define MAX_STAT_SIZE 38 /*--------------------------------------------------------------------*\ Application data types \*--------------------------------------------------------------------*/ typedef struct { int num; ProError status; char call[MAX_STAT_SIZE]; }TestStatistic; typedef struct { char function_name[40]; ProError permited_err_code; } PermitedErrors; /*--------------------------------------------------------------------*\ Application global/external data \*--------------------------------------------------------------------*/ static FILE *errlog_fp=NULL; static char errlog_name[PRO_PATH_SIZE]={'\0'}; TestStatistic *statistic = NULL; char trail_name[PRO_PATH_SIZE] = ""; /* The name of currently running trail file */ static PermitedErrors permited_errors[] = { {"ProMenuProcess", PRO_TK_E_FOUND}, {"ProModelitemNameGet", PRO_TK_E_NOT_FOUND}, {"ProSelect", PRO_TK_PICK_ABOVE}, {"ProSelect", PRO_TK_USER_ABORT}, {"ProSolidDisplay", PRO_TK_E_FOUND}, {"ProGraphicsColorSet", PRO_TK_NO_CHANGE}, {"ProLinestyleSet", PRO_TK_NO_CHANGE} }; /*====================================================================*\ Function : ProTestStatisticCmp() Purpose : compare two files by version \*====================================================================*/ int ProTestStatisticCmp(TestStatistic *st1, TestStatistic *st2) { int call_result; call_result = strncmp (st1->call, st2->call, MAX_STAT_SIZE); if (call_result == 0) { call_result = st1->status - st2->status; } return (call_result); } /*====================================================================*\ FUNCTION : ProTestStatisticWrite() PURPOSE : Write the specified params to the statistic file. \*====================================================================*/ int ProTestStatisticWrite (char *call, char *from, ProError status) { int i, line_num, line_found = 0; TestStatistic line; ProArraySizeGet ((ProArray)statistic, &line_num); if (errlog_fp == NULL) return (0); for (i = 0; i < line_num; i++) { if (strncmp (statistic[i].call, call, MAX_STAT_SIZE)==0) { if (statistic[i].status == status) { statistic[i].num++; line_found = 1; break; } } } if (!line_found) { ProUtilstrncpy (line.call, (const char *)call, MAX_STAT_SIZE); if (strlen (call) >= MAX_STAT_SIZE) { line.call[MAX_STAT_SIZE-4] = '\0'; ProUtilstrcat (line.call, ".."); } line.status = status; line.num = 1; ProArrayObjectAdd ((ProArray*)&statistic, PRO_VALUE_UNUSED, 1, &line); if (line_num > 1) { qsort(statistic, line_num+1, sizeof(TestStatistic), (int (*)(const void *, const void *)) ProTestStatisticCmp); } } return (1); } /*====================================================================*\ FUNCTION : TEST_CALL_REPORT PURPOSE : report a Pro/TOOLKIT function call, and status, if status expression false call = name of Pro/TOOLKIT function from = name of function calling the Pro/Toolkit function status = status returned by Pro/Toolkit function error = BOOLEAN expression whether status is reportable \*====================================================================*/ void ProTestCallReport(const char *call, const char *from, ProError status,int error) { int i, mode; char str[100], *p_ch, line[100]; if (error) { ProUtilstrcpy(line, call); p_ch = strchr(line, '('); if (p_ch != NULL) *p_ch = '\0'; for (i=0; i<sizeof(permited_errors)/sizeof(permited_errors[0]); i++) { if ((status == permited_errors[i].permited_err_code) && (strcmp(permited_errors[i].function_name, line) == 0)) error = 0; } } mode = ProTestRunmodeGet(); switch (mode) { case TEST_RUN_MODE_STAT: ProTestStatisticWrite ((char *)call, (char *)from, status); break; case TEST_RUN_MODE_CRASH: case TEST_RUN_MODE_REPORT: ProTKSprintf(str,"%-37s %-37.37s% -d\n", call, from, status); ProTestErrlogWrite(str); if(mode == TEST_RUN_MODE_CRASH && error) { ProTKPrintf("\n*** CRASHING Pro/TOOLKIT TEST ***\n"); ProTKPrintf(" Function : %s\n", call); ProTKPrintf(" Calling function : %s\n", from); ProTKPrintf(" Status : %d\n", status); TEST_CRASH() } break; case TEST_RUN_MODE_CRASH_REP: if (error) { /* Report only potential crashes in crash mode*/ ProTKSprintf(str,"%-37s %-37.37s% -d\n", call, from, status); ProTestErrlogWrite(str); } } } /*====================================================================*\ FUNCTION : ProTestErrlogOpen() PURPOSE : Open the Error Log file \*====================================================================*/ int ProTestErrlogOpen( char *regtest_name, /* Reg test name */ char *proe_vsn, /* Pro/E version */ char *build) /* Pro/E build */ { int runmode, path_size; char *dot, *p_env, log_dir[PRO_PATH_SIZE]; time_t t; char *default_regtest_name = (char *)"regtest"; ProError status; /*--------------------------------------------------------------------*\ Don't open it if the run mode is "silent" \*--------------------------------------------------------------------*/ runmode = ProTestRunmodeGet(); if(runmode == TEST_RUN_MODE_SILENT) return(0); /*--------------------------------------------------------------------*\ Find the directory in which to put the logfile \*--------------------------------------------------------------------*/ p_env = getenv("PROTOOL_LOG_DIR"); if ( p_env == NULL ) log_dir[0] = '\0'; else { ProUtilstrcpy(log_dir, (const char *)p_env); path_size = strlen(log_dir); if ( log_dir[path_size - 1] != '/') { log_dir[path_size] = '/'; log_dir[path_size + 1] = '\0'; } } ProTKPrintf(" Logfile dir : %s\n", log_dir); /*--------------------------------------------------------------------*\ Make the name "<regtest>.log" and open the file for write. \*--------------------------------------------------------------------*/ p_env = getenv( "PROTOOL_LOG_FILE" ); if ( p_env != NULL ) regtest_name = p_env; if( regtest_name == NULL ) regtest_name = default_regtest_name; if ( ! strcmp( regtest_name, "stderr" ) ) { ProUtilstrcpy( errlog_name, (const char *)regtest_name ); errlog_fp = stderr; } else if ( ! strcmp( regtest_name, "stdout" ) ) { ProUtilstrcpy( errlog_name, (const char *)regtest_name ); errlog_fp = stdout; } else { dot = strchr(regtest_name, '.'); if(dot != NULL) *dot = '\0'; ProUtilstrcpy(errlog_name, (const char *)regtest_name); ProUtilstrcat(errlog_name, ".log"); ProUtilstrcat(log_dir, (const char *)errlog_name); ProUtilstrcpy(errlog_name, (const char *)log_dir); errlog_fp = PTApplsUnicodeFopen(errlog_name,"a"); } /*--------------------------------------------------------------------*\ Write a header \*--------------------------------------------------------------------*/ t = time(NULL); ProTKFprintf(errlog_fp, "# Pro/TOOLKIT Regression Test Log\n"); fflush(errlog_fp); ProTKFprintf(errlog_fp, "#--------------------------------\n"); fflush(errlog_fp); ProTKFprintf(errlog_fp, "# Pro/ENGINEER version : %s\n", proe_vsn); fflush(errlog_fp); ProTKFprintf(errlog_fp, "# Pro/ENGINEER build : %s\n", build); fflush(errlog_fp); ProTKFprintf(errlog_fp, "# Started at : %s", ctime(&t)); fflush(errlog_fp); if( strlen( trail_name ) ) { ProTKFprintf(errlog_fp, "# Trail file name : %s\n", trail_name ); fflush(errlog_fp); } ProTKFprintf(errlog_fp, "#\n" ); fflush(errlog_fp); ProTKFprintf(errlog_fp, "# Pro/TOOLKIT Function Called From Status\n#\n"); fflush(errlog_fp); if (runmode == TEST_RUN_MODE_STAT) { if (statistic == NULL) { status = ProArrayAlloc (0, sizeof (TestStatistic), 10, (ProArray*)&statistic); } } return(0); } /*====================================================================*\ FUNCTION : ProTestErrlogReopen() PURPOSE : To reopen an ongoing error log file \*====================================================================*/ int ProTestErrlogReopen() { if ( strlen( errlog_name ) > 0 ) { if ( ! strcmp( errlog_name, "stderr" ) ) errlog_fp = stderr; else if ( ! strcmp( errlog_name, "stdout" ) ) errlog_fp = stdout; else errlog_fp = PTApplsUnicodeFopen(errlog_name,"a"); } return(0); } /*====================================================================*\ FUNCTION : ProTestErrlogClose() PURPOSE : Flush and close the error log file. \*====================================================================*/ int ProTestErrlogClose() { int num, i; if(errlog_fp != NULL) { if (statistic != NULL) { ProArraySizeGet ((ProArray)statistic, &num); for (i = 0; i < num; i++) { ProTKFprintf (errlog_fp, "%-37s% -20s% -6d% -6d\n", statistic[i].call, "internal()", statistic[i].status, statistic[i].num); } ProArrayFree ((ProArray*)&statistic); } fflush(errlog_fp); if ( strcmp( errlog_name, "stderr" ) && strcmp( errlog_name, "stdout" ) ) { fclose(errlog_fp); errlog_fp = NULL; } } return(0); } /*====================================================================*\ FUNCTION : ProTestErrlogWrite() PURPOSE : Write the specified string to the error log file. \*====================================================================*/ int ProTestErrlogWrite( char *str) { if(errlog_fp == NULL) return(0); ProTKFprintf(errlog_fp, "%s", str); fflush(errlog_fp); ProTestErrlogClose(); ProTestErrlogReopen(); return(0); } /*====================================================================*\ FUNCTION : ProUtilCommandLineParse() PURPOSE : Parse the specified command line setting global params \*====================================================================*/ int ProUtilCommandLineParse( int argc, char *argv[] ) { char *p; int i; for( i=1; i<argc; i++ ) { if( strstr( argv[i], "+trail:" ) ) { p = strchr( argv[i], ':' ); ProUtilstrcpy( trail_name, (const char *)(p+1) ); } } return PRO_TK_NO_ERROR; }