summaryrefslogtreecommitdiff
path: root/test/testframe.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/testframe.c')
-rw-r--r--test/testframe.c629
1 files changed, 629 insertions, 0 deletions
diff --git a/test/testframe.c b/test/testframe.c
new file mode 100644
index 0000000..21f9ea3
--- /dev/null
+++ b/test/testframe.c
@@ -0,0 +1,629 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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 COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Tuesday, January 6, 2004
+ *
+ * Purpose: Provides support functions for the testing framework.
+ *
+ */
+
+#include "testhdf5.h"
+
+/*
+ * Definitions for the testing structure.
+ */
+#define MAXTESTNAME 16
+#define MAXTESTDESC 64
+
+typedef struct TestStruct {
+ int NumErrors;
+ char Description[MAXTESTDESC];
+ int SkipFlag;
+ char Name[MAXTESTNAME];
+ void (*Call)(void);
+ void (*Cleanup)(void);
+ const void *Parameters;
+} TestStruct;
+
+
+/*
+ * Variables used by testing framework.
+ */
+static int num_errs = 0; /* Total number of errors during testing */
+int TestVerbosity = VERBO_DEF; /* Default Verbosity is Low */
+static int Summary = 0; /* Show test summary. Default is no. */
+static int CleanUp = 1; /* Do cleanup or not. Default is yes. */
+static int TestExpress = -1; /* Do TestExpress or not. -1 means not set yet. */
+static TestStruct *Test = NULL; /* Array of tests */
+static unsigned TestAlloc = 0; /* Size of the Test array */
+static unsigned Index = 0;
+static const void *Test_parameters = NULL;
+static const char *TestProgName = NULL;
+static void (*TestPrivateUsage)(void) = NULL;
+static int (*TestPrivateParser)(int ac, char *av[]) = NULL;
+
+
+/*
+ * Setup a test function and add it to the list of tests.
+ * It must have no parameters and returns void.
+ * TheName--short test name.
+ * If the name starts with '-', do not run it by default.
+ * TheCall--the test routine.
+ * Cleanup--the cleanup routine for the test.
+ * TheDescr--Long description of the test.
+ * Parameters--pointer to extra parameters. Use NULL if none used.
+ * Since only the pointer is copied, the contents should not change.
+ * Return: Void
+ * exit EXIT_FAILURE if error is encountered.
+ */
+void
+AddTest(const char *TheName, void (*TheCall) (void), void (*Cleanup) (void), const char *TheDescr, const void *Parameters)
+{
+ /* Sanity checking */
+ if (HDstrlen(TheDescr) >= MAXTESTDESC) {
+ printf("Test description ('%s') too long, increase MAXTESTDESC(%d).\n",
+ TheDescr, MAXTESTDESC);
+ exit(EXIT_FAILURE);
+ } /* end if */
+ if (HDstrlen(TheName) >= MAXTESTNAME) {
+ printf("Test name too long, increase MAXTESTNAME(%d).\n",
+ MAXTESTNAME);
+ exit(EXIT_FAILURE);
+ } /* end if */
+
+ /* Check for increasing the Test array size */
+ if(Index >= TestAlloc) {
+ TestStruct *newTest = Test; /* New array of tests */
+ unsigned newAlloc = MAX(1, TestAlloc * 2); /* New array size */
+
+ /* Reallocate array */
+ if(NULL == (newTest = (TestStruct *)HDrealloc(Test, newAlloc * sizeof(TestStruct)))) {
+ printf("Out of memory for tests, Index = %u, TestAlloc = %u, newAlloc = %u\n", Index, TestAlloc, newAlloc);
+ exit(EXIT_FAILURE);
+ } /* end if */
+
+ /* Update info */
+ Test = newTest;
+ TestAlloc = newAlloc;
+ } /* end if */
+
+ /* Set up test function */
+ HDstrcpy(Test[Index].Description, TheDescr);
+ if(*TheName != '-') {
+ HDstrcpy(Test[Index].Name, TheName);
+ Test[Index].SkipFlag = 0;
+ }
+ else { /* skip test by default */
+ HDstrcpy(Test[Index].Name, TheName+1);
+ Test[Index].SkipFlag = 1;
+ }
+ Test[Index].Call = TheCall;
+ Test[Index].Cleanup = Cleanup;
+ Test[Index].NumErrors = -1;
+ Test[Index].Parameters = Parameters;
+
+ /* Increment test count */
+ Index++;
+}
+
+
+/*
+ * Initialize testing framework
+ *
+ * ProgName: Name of test program.
+ * private_usage: Optional routine provided by test program to print the
+ * private portion of usage page. Default to NULL which means none is
+ * provided.
+ * private_parser: Optional routine provided by test program to parse the
+ * private options. Default to NULL which means none is provided.
+ *
+ * Modifications:
+ * Albert Cheng 2004/08/17
+ * Added the ProgName, private_usage and private_parser arguments.
+ */
+void TestInit(const char *ProgName, void (*private_usage)(void), int (*private_parser)(int ac, char *av[]))
+{
+ /*
+ * 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_auto2(H5E_DEFAULT, NULL, NULL);
+
+ /*
+ * Record the program name and private routines if provided.
+ */
+ TestProgName = ProgName;
+ if (NULL != private_usage)
+ TestPrivateUsage = private_usage;
+ if (NULL != private_parser)
+ TestPrivateParser = private_parser;
+}
+
+
+/*
+ * Print test usage.
+ * First print the common test options, then the extra options if provided.
+ *
+ * Modification:
+ * 2004/08/18 Albert Cheng. Add TestPrivateUsage feature.
+ */
+void TestUsage(void)
+{
+ unsigned i;
+
+ print_func("Usage: %s [-v[erbose] (l[ow]|m[edium]|h[igh]|0-9)] %s\n",
+ TestProgName, (TestPrivateUsage ? "<extra options>" : ""));
+ 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(" [-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("help print out this information\n");
+ if (TestPrivateUsage){
+ print_func("\nExtra options\n");
+ TestPrivateUsage();
+ }
+ 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");
+}
+
+
+/*
+ * Print test info.
+ */
+void TestInfo(const char *ProgName)
+{
+ unsigned major, minor, release;
+
+ H5get_libversion(&major, &minor, &release);
+
+ print_func("\nFor help use: %s -help\n",ProgName);
+ print_func("Linked with hdf5 version %u.%u release %u\n", major, minor, release);
+}
+
+
+/*
+ * Parse command line information.
+ * argc, argv: the usual command line argument count and strings
+ *
+ * Return: Void
+ * exit EXIT_FAILURE if error is encountered.
+ *
+ * Modification:
+ * 2004/08/18 Albert Cheng. Add extra_parse feature.
+ */
+void TestParseCmdLine(int argc, char *argv[])
+{
+ hbool_t skipped_all = FALSE;
+ int ret_code;
+
+ while (argv++, --argc > 0){
+ if ((HDstrcmp(*argv, "-verbose") == 0) ||
+ (HDstrcmp(*argv, "-v") == 0)) {
+ if (argc > 0){
+ --argc; ++argv;
+ ParseTestVerbosity(*argv);
+ }else{
+ TestUsage();
+ exit(EXIT_FAILURE);
+ }
+ }
+ else if (((HDstrcmp(*argv, "-exclude") == 0) ||
+ (HDstrcmp(*argv, "-x") == 0))) {
+ if (argc > 0){
+ --argc; ++argv;
+ SetTest(*argv, SKIPTEST);
+ }else{
+ TestUsage();
+ exit(EXIT_FAILURE);
+ }
+ }
+ else if (((HDstrcmp(*argv, "-begin") == 0) ||
+ (HDstrcmp(*argv, "-b") == 0))) {
+ if (argc > 0){
+ --argc; ++argv;
+ SetTest(*argv, BEGINTEST);
+ }else{
+ TestUsage();
+ exit(EXIT_FAILURE);
+ }
+ }
+ else if (((HDstrcmp(*argv, "-only") == 0) ||
+ (HDstrcmp(*argv, "-o") == 0))) {
+ if(argc > 0) {
+ unsigned Loop;
+
+ --argc; ++argv;
+
+ /* Skip all tests, then activate only one. */
+ if(!skipped_all) {
+ for(Loop = 0; Loop < Index; Loop++)
+ Test[Loop].SkipFlag = 1;
+ skipped_all = TRUE;
+ } /* end if */
+ SetTest(*argv, ONLYTEST);
+ } /* end if */
+ else {
+ TestUsage();
+ exit(EXIT_FAILURE);
+ }
+ }
+ else if ((HDstrcmp(*argv, "-summary") == 0) || (HDstrcmp(*argv, "-s") == 0))
+ Summary = 1;
+ else if ((HDstrcmp(*argv, "-help") == 0) || (HDstrcmp(*argv, "-h") == 0)) {
+ TestUsage();
+ exit(EXIT_SUCCESS);
+ }
+ else if ((HDstrcmp(*argv, "-cleanoff") == 0) || (HDstrcmp(*argv, "-c") == 0))
+ SetTestNoCleanup();
+ else {
+ /* non-standard option. Break out. */
+ break;
+ }
+
+ }
+
+ /* Call extra parsing function if provided. */
+ if (NULL != TestPrivateParser){
+ ret_code=TestPrivateParser(argc+1, argv-1);
+ if (ret_code != 0)
+ exit(EXIT_FAILURE);
+ }
+}
+
+
+/*
+ * Perform Tests.
+ */
+void PerformTests(void)
+{
+ unsigned Loop;
+
+ for (Loop = 0; Loop < Index; Loop++)
+ if (Test[Loop].SkipFlag) {
+ MESSAGE(2, ("Skipping -- %s (%s) \n", Test[Loop].Description, Test[Loop].Name));
+ } else {
+ MESSAGE(2, ("Testing -- %s (%s) \n", Test[Loop].Description, Test[Loop].Name));
+ MESSAGE(5, ("===============================================\n"));
+ Test[Loop].NumErrors = num_errs;
+ Test_parameters = Test[Loop].Parameters;
+ ALARM_ON;
+ Test[Loop].Call();
+ ALARM_OFF;
+ Test[Loop].NumErrors = num_errs - Test[Loop].NumErrors;
+ MESSAGE(5, ("===============================================\n"));
+ MESSAGE(5, ("There were %d errors detected.\n\n", (int)Test[Loop].NumErrors));
+ }
+
+ Test_parameters = NULL; /* clear it. */
+ 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");
+}
+
+
+/*
+ * Display test summary.
+ */
+void TestSummary(void)
+{
+ unsigned Loop;
+
+ 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");
+}
+
+
+/*
+ * Cleanup files from testing
+ */
+void TestCleanup(void)
+{
+ unsigned Loop;
+
+ 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();
+}
+
+
+/*
+ * Shutdown the test infrastructure
+ */
+void TestShutdown(void)
+{
+ if(Test)
+ HDfree(Test);
+}
+
+
+/*
+ * Retrieve the verbosity level for the testing framework
+ */
+H5_ATTR_PURE int GetTestVerbosity(void)
+{
+ return(TestVerbosity);
+}
+
+/*
+ * Set the verbosity level for the testing framework.
+ * Return previous verbosity level.
+ */
+int SetTestVerbosity(int newval)
+{
+ int oldval;
+
+ oldval = TestVerbosity;
+ TestVerbosity = newval;
+ return(oldval);
+}
+
+/*
+ * Retrieve the TestExpress mode for the testing framework
+ Values:
+ 0: Exhaustive run
+ Tests should take as long as necessary
+ 1: Full run. Default if HDF5TestExpress is not defined
+ Tests should take no more than 30 minutes
+ 2: Quick run
+ Tests should take no more than 10 minutes
+ 3: Smoke test. Default if HDF5TestExpress is set to a value other than 0-3
+ Tests should take less than 1 minute
+
+ Design:
+ If the environment variable $HDF5TestExpress is defined,
+ then test programs should skip some tests so that they
+ complete sooner.
+
+ Terms:
+ A "test" is a single executable, even if it contains multiple
+ sub-tests.
+ The standard system for test times is a Linux machine running in
+ NFS space (to catch tests that involve a great deal of disk I/O).
+
+ Implementation:
+ I think this can be easily implemented in the test library (libh5test.a)
+ so that all tests can just call it to check the status of $HDF5TestExpress.
+ */
+int GetTestExpress(void)
+{
+ char * env_val;
+
+ /* set it here for now. Should be done in something like h5test_init(). */
+ if(TestExpress==-1)
+ {
+ env_val = getenv("HDF5TestExpress");
+
+ if(env_val == NULL)
+ SetTestExpress(1);
+ else if(strcmp(env_val, "0") == 0)
+ SetTestExpress(0);
+ else if(strcmp(env_val, "1") == 0)
+ SetTestExpress(1);
+ else if(strcmp(env_val, "2") == 0)
+ SetTestExpress(2);
+ else
+ SetTestExpress(3);
+ }
+
+ return(TestExpress);
+}
+
+/*
+ * Set the TestExpress mode for the testing framework.
+ * Return previous TestExpress mode.
+ * Values: non-zero means TestExpress mode is on, 0 means off.
+ */
+int SetTestExpress(int newval)
+{
+ int oldval;
+
+ oldval = TestExpress;
+ TestExpress = newval;
+ return(oldval);
+}
+
+/*
+ * Retrieve Summary request value.
+ * 0 means no summary, 1 means yes.
+ */
+H5_ATTR_PURE int GetTestSummary(void)
+{
+ return(Summary);
+}
+
+/*
+ * Retrieve Cleanup request value.
+ * 0 means no Cleanup, 1 means yes.
+ */
+H5_ATTR_PURE int GetTestCleanup(void)
+{
+ return(CleanUp);
+}
+
+/*
+ * Set cleanup to no.
+ * Return previous cleanup value.
+ */
+int SetTestNoCleanup(void)
+{
+ int oldval;
+
+ oldval = CleanUp;
+ CleanUp = 0;
+ return(oldval);
+}
+
+/*
+ * Parse an argument string for verbosity level and set it.
+ */
+void ParseTestVerbosity(char *argv)
+{
+ if (*argv == 'l')
+ SetTestVerbosity(VERBO_LO);
+ else if (*argv == 'm')
+ SetTestVerbosity(VERBO_MED);
+ else if (*argv == 'h')
+ SetTestVerbosity(VERBO_HI);
+ else
+ SetTestVerbosity(atoi(argv));
+}
+
+
+/*
+ * Retrieve the number of testing errors for the testing framework
+ */
+H5_ATTR_PURE int GetTestNumErrs(void)
+{
+ return(num_errs);
+}
+
+
+/*
+ * Increment the number of testing errors
+ */
+void IncTestNumErrs(void)
+{
+ num_errs++;
+}
+
+
+/*
+ * Retrieve the current Test Parameters pointer.
+ */
+H5_ATTR_PURE const void *GetTestParameters(void)
+{
+ return(Test_parameters);
+}
+
+
+/*
+ * This routine is designed to provide equivalent functionality to 'printf'
+ * and also increment the error count for the testing framework.
+ */
+int
+TestErrPrintf(const char *format, ...)
+{
+ va_list arglist;
+ int ret_value;
+
+ /* Increment the error count */
+ num_errs++;
+
+ /* Print the requested information */
+ va_start(arglist, format);
+ ret_value = vprintf(format, arglist);
+ va_end(arglist);
+
+ /* Return the length of the string produced (like printf() does) */
+ return ret_value;
+}
+
+
+/*
+ * Set (control) which test will be tested.
+ * SKIPTEST: skip this test
+ * ONLYTEST: do only this test
+ * BEGINETEST: skip all tests before this test
+ *
+ */
+void SetTest(const char *testname, int action)
+{
+ unsigned Loop;
+
+ switch (action){
+ case SKIPTEST:
+ for (Loop = 0; Loop < Index; Loop++)
+ if (HDstrcmp(testname, Test[Loop].Name) == 0){
+ Test[Loop].SkipFlag = 1;
+ break;
+ }
+ break;
+ case BEGINTEST:
+ for (Loop = 0; Loop < Index; Loop++) {
+ if (HDstrcmp(testname, Test[Loop].Name) != 0)
+ Test[Loop].SkipFlag = 1;
+ else{
+ /* Found it. Set it to run. Done. */
+ Test[Loop].SkipFlag = 0;
+ break;
+ }
+ }
+ break;
+ case ONLYTEST:
+ for (Loop = 0; Loop < Index; Loop++) {
+ if (HDstrcmp(testname, Test[Loop].Name) == 0) {
+ /* Found it. Set it to run. Break to skip the rest. */
+ Test[Loop].SkipFlag = 0;
+ break;
+ }
+ }
+ break;
+ default:
+ /* error */
+ printf("*** ERROR: Unknown action (%d) for SetTest\n", action);
+ break;
+ }
+}
+
+
+/*
+ * Enable alarm on test execution, configurable by environment variable
+ */
+void TestAlarmOn(void)
+{
+ char * env_val = HDgetenv("HDF5_ALARM_SECONDS"); /* Alarm environment */
+ unsigned long alarm_sec = H5_ALARM_SEC; /* Number of seconds before alarm goes off */
+
+ /* Get the alarm value from the environment variable, if set */
+ if(env_val != NULL)
+ alarm_sec = (unsigned)HDstrtoul(env_val, (char **)NULL, 10);
+
+ /* Set the number of seconds before alarm goes off */
+ HDalarm((unsigned)alarm_sec);
+}
+