/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the files COPYING and Copyright.html. COPYING can be found at the root * * of the source code distribution tree; Copyright.html can be found at the * * root level of an installed copy of the electronic HDF5 document set and * * is linked from the top-level documents page. It can also be found at * * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* $Id$ */ /* * FILE * ttsafe.c - HDF5 threadsafe testing framework main file. * * REMARKS * General test wrapper for HDF5 library thread safety test programs * * DESIGN * Each test function should be implemented as function having no * parameters and returning void (i.e. no return value). They should be put * into the list of InitTest() calls in main() below. Functions which depend * on other functionality should be placed below the InitTest() call for the * base functionality testing. * Each test module should include ttsafe.h and define a unique set of * names for test files they create. * * BUGS/LIMITATIONS * * EXPORTED ROUTINES/VARIABLES: * Two variables are exported: num_errs, and Verbosity. */ #if defined __MWERKS__ #include #endif #include #include "ttsafe.h" #ifndef H5_HAVE_THREADSAFE int main(void) { printf("Test skipped because THREADSAFE not enabled\n"); return 0; } #else #define MAXNUMOFTESTS 50 #define HDF5_TEST_MASTER #define MAX_NUM_NAME 1000 #define NAME_OFFSET 6 /* offset for "name" */ /* Internal Variables */ static int Index = 0; /* Global variables */ int num_errs = 0; int Verbosity; /* ANY new test needs to have a prototype in tproto.h */ struct TestStruct { int NumErrors; char Description[64]; int SkipFlag; char Name[16]; void (*Call)(void); void (*Cleanup)(void); } Test[MAXNUMOFTESTS]; static void InitTest(const char *TheName, void (*TheCall) (void), void (*Cleanup) (void), const char *TheDescr); static void usage(void); static void InitTest(const char *TheName, void (*TheCall) (void), void (*Cleanup) (void), const char *TheDescr) { if (Index >= MAXNUMOFTESTS) { print_func("Uh-oh, too many tests added, increase MAXNUMOFTEST!\n"); exit(-1); } HDstrcpy(Test[Index].Description, TheDescr); HDstrcpy(Test[Index].Name, TheName); Test[Index].Call = TheCall; Test[Index].Cleanup = Cleanup; Test[Index].NumErrors = -1; Test[Index].SkipFlag = 0; Index++; } static void usage(void) { int i; print_func("Usage: ttsafe [-v[erbose] (l[ow]|m[edium]|h[igh]|0-10)] \n"); print_func(" [-[e]x[clude] name+] \n"); print_func(" [-o[nly] name+] \n"); print_func(" [-b[egin] name] \n"); print_func(" [-s[ummary]] \n"); print_func(" [-c[leanoff]] \n"); print_func(" [-n[ocaching]] \n"); print_func(" [-h[elp]] \n"); print_func("\n\n"); print_func("verbose controls the amount of information displayed\n"); print_func("exclude to exclude tests by name\n"); print_func("only to name tests which should be run\n"); print_func("begin start at the name of the test givin\n"); print_func("summary prints a summary of test results at the end\n"); print_func("cleanoff does not delete *.hdf files after execution of tests\n"); print_func("nocaching do not turn on low-level DD caching\n"); print_func("help print out this information\n"); print_func("\n\n"); print_func("This program currently tests the following: \n\n"); print_func("%16s %s\n", "Name", "Description"); print_func("%16s %s\n", "----", "-----------"); for (i = 0; i < Index; i++) print_func("%16s %s\n", Test[i].Name, Test[i].Description); print_func("\n\n"); } /* * This routine is designed to provide equivalent functionality to 'printf' * and allow easy replacement for environments which don't have stdin/stdout * available. (i.e. Windows & the Mac) */ int print_func(const char *format, ...) { va_list arglist; int ret_value; va_start(arglist, format); ret_value = vprintf(format, arglist); va_end(arglist); return ret_value; } char *gen_name(int value) { char *temp; int i, length; length = num_digits(MAX_NUM_NAME - 1); temp = (char *)malloc((NAME_OFFSET + length + 1) * sizeof(char)); temp = strcpy(temp, "attrib"); temp[NAME_OFFSET + length] = '\0'; for (i = length - 1; i >= 0; i--) { temp[NAME_OFFSET + i] = (char)((int)'0' + value % 10); value = value / 10; } return temp; } /* pre-condition: num must be a non-negative number */ int num_digits(int num) { int i; if (num == 0) return 1; for (i = 0; num > 0; i++) num = num / 10; return i; } int main(int argc, char *argv[]) { int CLLoop; /* Command Line Loop */ int Loop, Loop1, Summary = 0, CleanUp = 1, Cache = 1; unsigned major, minor, release; #if defined __MWERKS__ argc = ccommand(&argv); #endif #if !(defined MAC || defined __MWERKS__ || defined SYMANTEC_C) /* Un-buffer the stdout and stderr */ setbuf(stderr, NULL); setbuf(stdout, NULL); #endif /* * Turn off automatic error reporting since we do it ourselves. * Besides, half the functions this test calls are private, so * automatic error reporting wouldn't do much good since it's * triggered at the API layer. */ H5Eset_auto (NULL, NULL); /* Tests are generally arranged from least to most complexity... */ InitTest("dcreate", tts_dcreate, cleanup_dcreate, "multi-dataset creation"); InitTest("error", tts_error, cleanup_error, "per-thread error stacks"); InitTest("cancel", tts_cancel, cleanup_cancel, "thread cancellation safety test"); InitTest("acreate", tts_acreate, cleanup_acreate, "multi-attribute creation"); Verbosity = 4; /* Default Verbosity is Low */ H5get_libversion(&major, &minor, &release); print_func("\nFor help use: ttsafe -help\n"); print_func("Linked with hdf5 version %u.%u release %u\n", (unsigned)major, (unsigned)minor, (unsigned)release); for (CLLoop = 1; CLLoop < argc; CLLoop++) { if (argc > CLLoop + 1 && (HDstrcmp(argv[CLLoop], "-verbose") == 0 || HDstrcmp(argv[CLLoop], "-v") == 0)) { if (argv[CLLoop + 1][0] == 'l') Verbosity = 4; else if (argv[CLLoop + 1][0] == 'm') Verbosity = 6; else if (argv[CLLoop + 1][0] == 'h') Verbosity = 10; else Verbosity = atoi(argv[CLLoop + 1]); } /* end if */ if (argc > CLLoop && (HDstrcmp(argv[CLLoop], "-summary") == 0 || HDstrcmp(argv[CLLoop], "-s") == 0)) Summary = 1; if (argc > CLLoop && (HDstrcmp(argv[CLLoop], "-help") == 0 || HDstrcmp(argv[CLLoop], "-h") == 0)) { usage(); exit(0); } if (argc > CLLoop && (HDstrcmp(argv[CLLoop], "-cleanoff") == 0 || HDstrcmp(argv[CLLoop], "-c") == 0)) CleanUp = 0; if (argc > CLLoop && (HDstrcmp(argv[CLLoop], "-nocache") == 0 || HDstrcmp(argv[CLLoop], "-n") == 0)) { Cache = 0; print_func("Cache = %d\n", Cache); } if (argc > CLLoop + 1 && (HDstrcmp(argv[CLLoop], "-exclude") == 0 || HDstrcmp(argv[CLLoop], "-x") == 0)) for (Loop = CLLoop + 1; Loop < argc && argv[Loop][0] != '-'; Loop++) for (Loop1 = 0; Loop1 < Index; Loop1++) if (HDstrcmp(argv[Loop], Test[Loop1].Name) == 0) Test[Loop1].SkipFlag = 1; if (argc > CLLoop + 1 && (HDstrcmp(argv[CLLoop], "-begin") == 0 || HDstrcmp(argv[CLLoop], "-b") == 0)) for (Loop = CLLoop + 1; Loop < argc && argv[Loop][0] != '-'; Loop++) for (Loop1 = 0; Loop1 < Index; Loop1++) { if (HDstrcmp(argv[Loop], Test[Loop1].Name) != 0) Test[Loop1].SkipFlag = 1; if (HDstrcmp(argv[Loop], Test[Loop1].Name) == 0) Loop1 = Index; } if (argc > CLLoop + 1 && (HDstrcmp(argv[CLLoop], "-only") == 0 || HDstrcmp(argv[CLLoop], "-o") == 0)) { for (Loop = 0; Loop < Index; Loop++) Test[Loop].SkipFlag = 1; for (Loop = CLLoop + 1; Loop < argc && argv[Loop][0] != '-'; Loop++) for (Loop1 = 0; Loop1 < Index; Loop1++) if (HDstrcmp(argv[Loop], Test[Loop1].Name) == 0) Test[Loop1].SkipFlag = 0; } } /* end for */ #ifdef NOT_YET if (Cache) /* turn on caching, unless we were instucted not to */ Hcache(CACHE_ALL_FILES, TRUE); #endif /* NOT_YET */ for (Loop = 0; Loop < Index; Loop++) if (Test[Loop].SkipFlag) { MESSAGE(2, ("Skipping -- %s \n", Test[Loop].Description)); } else { MESSAGE(2, ("Testing -- %s (%s) \n", Test[Loop].Description, Test[Loop].Name)); MESSAGE(5, ("===============================================\n")); Test[Loop].NumErrors = num_errs; Test[Loop].Call(); Test[Loop].NumErrors = num_errs - Test[Loop].NumErrors; MESSAGE(5, ("===============================================\n")); MESSAGE(5, ("There were %d errors detected.\n\n", (int)Test[Loop].NumErrors)); } MESSAGE(2, ("\n\n")) if (num_errs) print_func("!!! %d Error(s) were detected !!!\n\n", (int) num_errs); else print_func("All tests were successful. \n\n"); if (Summary) { print_func("Summary of Test Results:\n"); print_func("Name of Test Errors Description of Test\n"); print_func("---------------- ------ --------------------------------------\n"); for (Loop = 0; Loop < Index; Loop++) { if (Test[Loop].NumErrors == -1) print_func("%16s %6s %s\n", Test[Loop].Name, "N/A", Test[Loop].Description); else print_func("%16s %6d %s\n", Test[Loop].Name, (int)Test[Loop].NumErrors, Test[Loop].Description); } print_func("\n\n"); } if (CleanUp && !getenv("HDF5_NOCLEANUP")) { MESSAGE(2, ("\nCleaning Up temp files...\n\n")); /* call individual cleanup routines in each source module */ for (Loop = 0; Loop < Index; Loop++) if (!Test[Loop].SkipFlag && Test[Loop].Cleanup!=NULL) Test[Loop].Cleanup(); } return num_errs; } /* end main() */ #endif /*H5_HAVE_THREADSAFE*/