/*************************************************************************** * * Module Name: btree.test.c * ============ * * Function: BTREE TEST PROGRAM * ========= * * Description: * ============ * -see main routine * Libraries * ---------- * stdio.h * btree.c (--> btree.h) * btree.test.h * btree.prt.h * ******************************************************************************/ static char btree_tests[] = "@(#)btree.test.c 1.1 7/16/86"; /***************************************************************************** * INCLUDES and TEST PROGRAM PARAMETERS *****************************************************************************/ #include #include "btree.c" #include "btree.test.h" #include "btree.prt.h" /* Number of key values to be used */ #define MAXKEYS 1500 /* Values used by flag table (below) */ #define IN_TREE 1 #define NOT_IN_TREE 0 /* Seed for random number generator */ static int seed; /* This array will contain boolean values - if flag[i]=NOT_IN_TREE then key i is currently not in the tree if flag[i]=IN_TREE then key i is currently in the tree. */ static int flag[MAXKEYS]; static int keytotal; BTREE tree; /* Tree to be used */ /****************************************************************************** * MAIN TEST PROGRAM ******************************************************************************/ /* ** MAIN TEST PROGRAM ** ================= ** ** Purpose: Test the B-tree routines ** ** Parameters: argv[1] = "" or a seed for the random tests ** ** Returns: A continuous set of diagnostic messages is sent to stdout ** This continues until the tests are successfully completed or ** until the first error occurs ** ** Description: There are 3 sets of tests performed ** (1) Random tests - a large number of random inserts, deletes ** and searches is performed. ** (2) All keys are inserted into the tree in ascending order ** then deleted in ascending order. ** (3) All keys are inserted into the tree in descending order ** then deleted in descending order. ** For the purposes of this test a limited range of keys is used ** - these are numbered 0 to MAXKEYS-1 (where MAXKEYS is #defined ** above) and a function getkey() returns the actual key value of ** a given key number - currently keys are integers so ** getkey(i) = i. */ main(argc,argv) int argc; char *argv[]; { int statuscode; int randomtest(), ascendingtest(), descendingtest(); /* First thing to do is to check for a seed parameter */ if (argc != 0) sscanf(argv[1],"%d",&seed); else seed = 0; srandom(seed); /* Random test */ statuscode = randomtest(); if (statuscode != SUCCESS) error(statuscode); /* Ascending test */ statuscode = ascendingtest(); if (statuscode != SUCCESS) error(statuscode); /* Descending test */ statuscode = descendingtest(); if (statuscode != SUCCESS) error(statuscode); /* Given message to say that it all worked */ printf("\n\n----> TESTS SUCCEEDED <----\n\n\n"); exit(1); } /**************************************************************************** * RANDOM INSERT/DELETE/SEARCH TEST ****************************************************************************/ /* Number of inserts + deletes + searches for random tests. */ #define PASSES 2000 /* Number of actions available to random test and the codes associated with them. */ #define ACTIONS 3 #define SEARCH 0 #define INSERT 1 #define DELETE 2 /* ** RANDOMTEST ** ========== ** Purpose: Perform the random tests ** ** Parameters: None ** ** Returns: Diagnostic messages are continuously fed to stdout ** and upon completion/error a success/error code is returned ** SUCCESS: Everything went okay ** others : see routines testsearch(), ** testinsert(), ** testdelete(). ** ** Description: For a given number of iterations (PASSES), generate a random ** key number and randomly select an insert, a delete or a search ** to do on the key corresponding to the key number. */ int randomtest() { int keynumber; int pass, status; int randrange(); /* Set up tree for new test */ inittree(); /* Send start-of-test-banner */ printf("**************** RANDOM TESTS *****************\n\n"); /* Now repeat the following process PASSES times: 1) Generate a random key value 2) Generate a random number to determine what action to perform on that key 3) Perform the action and check the resulting tree. */ for (pass=1; pass=0; --i) { status = testinsert(i); if (status != SUCCESS) return(status); } /* Delete keys in order */ for (i=MAXKEYS-1; i>=0; --i) { status = testdelete(i); if (status != SUCCESS) return(status); } return SUCCESS; } /***************************************************************************** * TREE INITIALISATION *****************************************************************************/ /* ** INITTREE ** ======== ** ** Purpose: Set up tree & lookup tables ready for a new test ** ** Parameters: none. ** ** Returns: none. ** ** Description: trivial. */ inittree() { int i; tree = (BTREE)NULL; for (i=0; it_active; /* If not at a leaf, check whether this node is at least 1/2 full - which is a prerequisite of all non-root nodes */ if ((keys_in_nodet_dat[0].key, lowkey)<=0) || (KeyCmp(tree->t_dat[keys_in_node-1].key, highkey)>=0)) return WRONG_KEY_IN_NODE; /* If all's okay so far, go into the guts of the test - a recursive consistency check of all nodes below here */ for (i=0; i<=keys_in_node; i++) { /* Establish 3 quantities: lo = lower bound on t_dat[i] and keys under t_ptr[i] hi = upper bound on values in t_ptr[i] upper = upper bound on t_dat[i] */ if (i==0) lo = lowkey; else lo = tree->t_dat[i-1].key; if (i==keys_in_node) hi = highkey; else { hi = tree->t_dat[i].key; /* The quantity 'upper' is only needed here (where it_dat[i+1].key; /* Now check that t_dat[i] lies between 'lo' and 'upper' */ if ((KeyCmp(tree->t_dat[i].key,lo)<=0) || (KeyCmp(tree->t_dat[i].key,upper)>=0)) return KEYS_NOT_IN_ORDER; } /* Do consistency check of subtree t_ptr[i] */ status = performcheck(tree->t_ptr[i],thisdepth,lo,hi); /* If a check of the subtree gave an error then bail out now */ if (status != SUCCESS) break; } return status; } /************************************************************************* * VARIOUS MISCELLANEOUS ROUTINES *************************************************************************/ /* ** GETKEY ** ====== ** ** Purpose: Routine to translate a key number into a key value ** ** Parameters: keynumber = number of key to be obtained ** ** Returns: Returns a key value ** ** Description: This routine is key dependent - it just returns a key value ** coresponding to a key number. ** Note that the routine must return keys with key values ** -1 ... MAXKEYS - where the 2 extremes are used in consistency ** checks for bounds on the key values in a tree. */ KEY getkey(keynumber) int keynumber; { return keynumber; } /* ** PRINTKEY ** ======== ** ** Purpose: Routine to print a key value ** ** Parameters: key = key value to be printed ** ** Returns: None ** ** Description: Mind-numbingly simple */ printkey(key) KEY key; { printf("%d\t",key); } /* ** ERROR ** ===== ** ** Purpose: Routine to convert an error number into an error message ** ** Parameters: errno = error number ** ** Returns: none. ** ** Description: Nothing particularly taxing about this one */ error(errno) int errno; { printf("\n"); switch (errno) { case FOUND_NON_EXISTANT_KEY: printf("!!! SEARCH found a key which should be in the tree\n"); break; case NOT_FOUND_EXISTING_KEY: printf("!!! SEARCH failed to find a key which should be in the tree\n"); break; case FOUND_WRONG_KEY: printf("!!! SEARCH located the wrong key\n"); break; case INSERTED_EXISTING_KEY: printf("!!! INSERT inserted a key into the tree when it was already there\n"); break; case CANNOT_INSERT_KEY: printf("!!! INSERT claimed that a key was already in the tree when it wasn't\n"); break; case DELETED_NON_EXISTANT_KEY: printf("!!! DELETE managed to delete a key which wasn't in the tree"); break; case CANNOT_DELETE_KEY: printf("!!! DELETE claimed that a key wasn't in the tree when it was\n"); break; case TREE_CORRUPTED_ERROR: printf("!!! TREE CORRUPTED\n"); break; case NODE_NOT_HALF_FULL: printf("!!! CONSISTENCY ERROR - a node was found to be less than half full\n"); break; case WRONG_KEY_IN_NODE: printf("!!! CONSISTENCY ERROR - a key was found in the wrong node\n"); break; case TREE_DEPTH_INCONSISTENT: printf("!!! CONSISTENCY ERROR - the tree is not of constant depth\n"); break; case KEYS_NOT_IN_ORDER: printf("!!! CONSISTENCY ERROR - the keys within a node are not in ascending order\n"); break; case KEY_TOTAL_MISMATCH: printf("!!! CONSISTENCY ERROR - the total number of keys in the tree is wrong\n"); break; } printf("\nThe tree is :-\n"); ShowTree(tree,0); printf("\n\n ----> TEST ABORTED <----\n\n\n"); exit(0); }