CUSTOM.C
//*--------------------------------------------------------------------------------- 
//| Custom Auto Test DLL 
//| 
//| Title:CUSTOM.C 
//| 
//| Purpose: 
//|This sample Auto Test DLL shows how an ODBC auto test may be written and 
//|subsequently run via the ODBC Test application.  To use this DLL: 
//|1) Compile the source code via the BUILD.EXE program 
//|CUSTOM.CThis shource file with test code 
//|CUSTOM.HInclude files with defines, macros, and prototypes 
//|CUSTOM.RCResource file for string tables 
//|(Note that .H and .RC files are optional in for an Auto Test) 
//|2) Start the ODBC Test application 
//|3) If you have not done so, choose Tools, Manage Test Sources and define 
//|a test source to run against 
//|4) Choose Tools, Manage Tests and add the CUSTOM.DLL created in step 1 
//|to the list of installed test DLLs 
//|5) Choose Tools, Run Tests and select "Custom Auto Test" and your Test Source 
//|from step #3 
//|For more details, please see the SDK documentation. 
//*--------------------------------------------------------------------------------- 
#include "autotest.h" 
#include "custom.h" 
 
 
//---------------------------------------------------------------------------------- 
//Defines and macros 
//---------------------------------------------------------------------------------- 
typedef SWORD (FAR PASCAL *TESTCASEFUNC)(HENV FAR *, HDBC FAR *, HSTMT FAR *, lpSERVERINFO); 
 
#define CHECKTEST(lps, exprc, actrc, func) \ 
{                                                  \ 
if(!CheckTest(lps, exprc, actrc, (LPSTR)func))  \ 
return TEST_ABORTED;                         \ 
} 
#define CHECKERRS(sErr)\ 
if(!sErr) szLogPrintf(lpSrvr, FALSE, "\t\tPassed\r\n\r\n"); \ 
else szLogPrintf(lpSrvr, FALSE, "\t\t%d errors\r\n\r\n", sErr); 
 
 
 
//---------------------------------------------------------------------------------- 
//Local function prototypes 
//---------------------------------------------------------------------------------- 
SWORD FAR PASCAL DoHelloWorld(HENV FAR * phenv, HDBC FAR * phdbc, 
HSTMT FAR * phstmt, lpSERVERINFO lpSrvr); 
SWORD FAR PASCAL DoDisplayInfoDesc(HENV FAR * phenv, HDBC FAR * phdbc, 
HSTMT FAR * phstmt, lpSERVERINFO lpSrvr); 
SWORD FAR PASCAL DoSimpleConnect(HENV FAR * phenv, HDBC FAR * phdbc, 
HSTMT FAR * phstmt, lpSERVERINFO lpSrvr); 
BOOL FAR PASCAL CheckTest(lpSERVERINFO lps, RETCODE exprc, RETCODE actrc, 
LPSTRszFuncName); 
 
 
// 
// This structure is declared to describe the test cases and descriptions 
//that this auto test supports.  Note that the strings are stored in 
//the resource fork, but could have been hard coded. 
// 
struct { 
UINTuiName;// Test case name 
UINTuiDesc;// Test case description 
TESTCASEFUNClpTestFunc;// Pointer to function to implement test 
} TestCases[] = { 
// szNameszDesclpTestFunc 
// ------------------------------------------------------------------- 
idsHelloWorld,idsHelloWorldDesc,DoHelloWorld, 
idsDisplayInfo,idsDisplayInfoDesc,DoDisplayInfoDesc, 
idsSimpleConnect,idsSimpleConnectDesc,DoSimpleConnect, 
}; 
 
 
 
//************************************************************************** 
//***************************  External Interfaces  ************************ 
//*  These functions are called by ODBC Test to gather run-time information 
//************************************************************************** 
 
 
//*--------------------------------------------------------------------------------- 
//| AutoTestName: 
//|This function is called to give the name of the auto test (which cannot 
//|exceed AUTO_MAX_TEST_NAME) as well as the number of test cases which 
//|are implemented in this test DLL. 
//| Parms: 
//|szNameThe name to be displayed 
//|pcbTestCasesPointer to count of test cases 
//| Returns: 
//|TRUE if successful (pcbTestCases set), FALSE for error 
//*--------------------------------------------------------------------------------- 
BOOL EXTFUN AutoTestName(LPSTR szName, UINT FAR * pcbTestCases) 
{ 
GetRCString(hLoadedInst, szName, AUTO_MAX_TEST_NAME, idsTestName); 
*pcbTestCases = NumItems(TestCases); 
 
   return TRUE; 
} 
 
 
//*--------------------------------------------------------------------------------- 
//| AutoTestDesc: 
//|This function is called by ODBC Test when a description of a specific 
//|test case is required.  The returned name must be no larger than 
//|AUTO_MAX_TESTCASE_NAME including the NULL terminator.  The returned 
//|description must be no larger than AUTO_MAX_TESTDESC_NAME including the 
//|NULL.  iTest will be 1-based index of the test required. 
//| 
//|Note that iTest will start at 1 and will go to the number of 
//|test cases as specified by the AutoTestName function. 
//| 
//| Parms: 
//|iTest1-based index of test case required 
//|szNameThe name of the test case 
//|szDescA description of the test case 
//| Returns: 
//|TRUE if successful, FALSE for error 
//*--------------------------------------------------------------------------------- 
BOOL EXTFUN AutoTestDesc(UWORD iTest, LPSTR szName, LPSTR szDesc) 
{ 
// Extra protection should AutoTestName return invalid pcbTestCases 
if(iTest > NumItems(TestCases)) 
return FALSE; 
 
// Use GetRCString to retrieve resource string directly into return 
//values 
GetRCString(hLoadedInst, szName,  
AUTO_MAX_TESTCASE_NAME, TestCases[(iTest-1)].uiName); 
GetRCString(hLoadedInst, szDesc,  
AUTO_MAX_TESTDESC_NAME, TestCases[(iTest-1)].uiDesc); 
 
   return TRUE; 
} 
  
  
//*--------------------------------------------------------------------------------- 
//| AutoTestFunc: 
//|This function is called to execute a test case selected by the user for 
//|execution.  The lpSrvr structure contains the information required for 
//|connected (as defined in the chosen Test Source), as well as other 
//|usefull information.  See the AUTOTEST.H file for the structure 
//|declaration. 
//| 
//|Use the GETBIT macro to determine which test should be executed. 
//| 
//| Parms: 
//|lpSrvrInformation required for running the test 
//| Returns: 
//|Nothing 
//*--------------------------------------------------------------------------------- 
void EXTFUN AutoTestFunc(lpSERVERINFO lpSrvr) 
{ 
HENV henv=NULL; 
HDBC hdbc=NULL; 
HSTMT hstmt0=NULL; 
intiDex; 
SWORDcErrCnt;// Count errors 
charszName[AUTO_MAX_TESTCASE_NAME+6];// Room for NULL and \r\n 
 
 
// Sets the error count to 0 
InitTest(lpSrvr); 
 
// Loop through the count of test cases looking for set bits via GETBIT. 
//When a bit is set, that test is to be run.  We've stored the 
//function address which will implement the test, so simply call it. 
for(iDex=1;  iDex<=NumItems(TestCases);  iDex++) 
if(GETBIT(lpSrvr->rglMask, iDex)) { 
// Print out title of test 
GetRCString(hLoadedInst, szName,  
AUTO_MAX_TESTCASE_NAME, TestCases[(iDex-1)].uiName); 
szLogPrintf(lpSrvr, FALSE, "%s:\r\n", (LPSTR)szName); 
 
// Call the test case and add errors 
cErrCnt =  
(*TestCases[(iDex-1)].lpTestFunc)(&henv, &hdbc, &hstmt0, lpSrvr); 
if(cErrCnt != TEST_ABORTED) 
lpSrvr->cErrors += cErrCnt; 
else 
goto abort; 
} 
return; 
 
 
// When a test must abort, the test case should call the AbortTest 
//macro which sets lpSrvr->cErrors to TEST_ABORTED. 
abort: 
return; 
} 
  
 
 
 
 
 
//************************************************************************** 
//*****************************  Test Cases  ******************************* 
//*  The following functions implement the tests 
//************************************************************************** 
 
//*--------------------------------------------------------------------------------- 
//| DoHelloWord: 
//|This is a simple test which uses the szLogPrintf and szMessageBox 
//|functions defined in GATORTST.DLL. 
//| 
//|Note that this test also simulates an error by returning a count 
//|of 1.  This value is then totaled by ODBC Test and displayed as 
//|part of the grand total. 
//| 
//| Returns: 
//|Number of Errors or TEST_ABORTED 
//*--------------------------------------------------------------------------------- 
SWORD FAR PASCAL DoHelloWorld(HENV FAR * phenv, HDBC FAR * phdbc, 
HSTMT FAR * phstmt, lpSERVERINFO lpSrvr) 
{ 
SWORDsErr=1;// Pretend there was 1 error 
 
// The szMessageBox function will display a formatted message via the 
//Windows MessageBox function.  This function should not be used 
//for standard testing since a good test will run unattended. 
szMessageBox(lpSrvr->hwnd,  
MB_ICONINFORMATION | MB_OK, 
"Hello World", 
"This is a sample message."); 
 
// The szLogPrintf function is preferred for output operations.  It will 
//format your string using wvsprintf (which has a limit of 2000 characters) 
//and log the result both to the output window and to a file per 
//user instructions. 
szLogPrintf(lpSrvr, FALSE, "\tHello World!!\r\n"); 
 
 
// check for errors 
CHECKERRS(sErr); 
 
 
return sErr; 
} 
 
 
//*--------------------------------------------------------------------------------- 
//| DoDisplayInfoDesc: 
//|This test case will use the szLogPrintf function to dump the contents 
//|of the lpSrvr structure. 
//| 
//| Returns: 
//|Number of Errors or TEST_ABORTED 
//*--------------------------------------------------------------------------------- 
SWORD FAR PASCAL DoDisplayInfoDesc(HENV FAR * phenv, HDBC FAR * phdbc, 
HSTMT FAR * phstmt, lpSERVERINFO lpSrvr) 
{ 
SWORDsErr=0; 
 
#ifndef WIN32 
#define szAddress "%04X:%04X\r\n" 
#else 
#define szAddress "%08X\r\n" 
#endif 
 
// The hwnd parameter is the window of style "edit" which is used for output. 
//The szLogFile parameter is used for file logging of output. 
szLogPrintf(lpSrvr, FALSE, 
"\thwnd:\t\t\t\t\t\t\t%04X\r\n", lpSrvr->hwnd); 
szLogPrintf(lpSrvr, FALSE, 
"\tszLogFile:\t\t\t\t%s\r\n", (LPSTR)lpSrvr->szLogFile); 
 
// Print out address information.  Note that szAddress is conditionaly compiled 
//to handle 16 and 32-bit.  It will be concatenated to the format string 
//by the compiler to create a file platform correct string. 
szLogPrintf(lpSrvr, FALSE, 
"\thenv:\t\t\t\t\t\t\t" szAddress,  
#ifndef WIN32 
HIWORD(lpSrvr->henv), LOWORD(lpSrvr->henv)); 
#else 
lpSrvr->henv); 
#endif 
szLogPrintf(lpSrvr, FALSE, 
"\thdbc:\t\t\t\t\t\t\t" szAddress,  
#ifndef WIN32 
HIWORD(lpSrvr->hdbc), LOWORD(lpSrvr->hdbc)); 
#else 
lpSrvr->hdbc); 
#endif 
szLogPrintf(lpSrvr, FALSE, 
"\thstmt:\t\t\t\t\t\t\t" szAddress,  
#ifndef WIN32 
HIWORD(lpSrvr->hstmt), LOWORD(lpSrvr->hstmt)); 
#else 
lpSrvr->hstmt); 
#endif 
 
 
// The following are defined via the Tools, Manage Test Sources dialog in 
//the ODBC Test application. 
szLogPrintf(lpSrvr, FALSE, 
"\tszSource:\t\t\t\t\t%s\r\n", (LPSTR)lpSrvr->szSource); 
szLogPrintf(lpSrvr, FALSE, 
"\tszValidServer0:\t\t\t\t\t\t%s\r\n", (LPSTR)lpSrvr->szValidServer0); 
szLogPrintf(lpSrvr, FALSE, 
"\tszValidLogin0:\t\t\t\t\t\t%s\r\n", (LPSTR)lpSrvr->szValidLogin0); 
szLogPrintf(lpSrvr, FALSE, 
"\tszValidPassword0:\t\t\t%s\r\n", (LPSTR)lpSrvr->szValidPassword0); 
szLogPrintf(lpSrvr, FALSE, 
"\tszKeywords:\t\t\t%s\r\n", (LPSTR)lpSrvr->szKeywords); 
 
// The following elements describe the run-time environment 
szLogPrintf(lpSrvr, FALSE, 
"\tcErrors:\t\t\t\t\t\t%d\r\n", (LPSTR)lpSrvr->cErrors); 
szLogPrintf(lpSrvr, FALSE, 
"\tfDebug:\t\t\t\t\t\t%d\r\n", (LPSTR)lpSrvr->fDebug); 
szLogPrintf(lpSrvr, FALSE, 
"\tfScreen:\t\t\t\t\t\t%d\r\n", (LPSTR)lpSrvr->fScreen); 
szLogPrintf(lpSrvr, FALSE, 
"\tfLog:\t\t\t\t\t\t\t\t%d\r\n", (LPSTR)lpSrvr->fLog); 
szLogPrintf(lpSrvr, FALSE, 
"\tfIsolate:\t\t\t\t\t\t%d\r\n", (LPSTR)lpSrvr->fIsolate); 
szLogPrintf(lpSrvr, FALSE, 
"\tvCursorLib:\t\t\t\t%lu\r\n", (LPSTR)lpSrvr->vCursorLib); 
szLogPrintf(lpSrvr, FALSE, 
"\thLoadedInst:\t\t\t%04X\r\n", (LPSTR)lpSrvr->hLoadedInst); 
 
// check for errors 
CHECKERRS(sErr); 
 
return sErr; 
} 
 
 
//*--------------------------------------------------------------------------------- 
//| DoSimpleConnect: 
//|This test case will use the information in SERVERINFO to make a connection 
//|to the chosen test source. 
//| 
//| Returns: 
//|Number of Errors or TEST_ABORTED 
//*--------------------------------------------------------------------------------- 
SWORD FAR PASCAL DoSimpleConnect(HENV FAR * phenv, HDBC FAR * phdbc, 
HSTMT FAR * phstmt, lpSERVERINFO lpSrvr) 
{ 
RETCODErc; 
SWORDsErr=0; 
 
// This test will assume that the ODBC handles passed in 
//are NULL.  One could have this function do a connection 
//and pass the handles to other test functions. 
rc = SQLAllocEnv(phenv); 
CHECKTEST(lpSrvr, SQL_SUCCESS, rc, "SQLAllocEnv"); 
 
rc = SQLAllocConnect(*phenv, phdbc); 
CHECKTEST(lpSrvr, SQL_SUCCESS, rc, "SQLAllocConnect"); 
 
rc = SQLConnect(*phdbc, lpSrvr->szValidServer0, SQL_NTS, 
lpSrvr->szValidLogin0, SQL_NTS, 
lpSrvr->szValidPassword0, SQL_NTS); 
CHECKTEST(lpSrvr, 
(RETCODE)((rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) 
? rc : SQL_SUCCESS), 
rc, "SQLConnect"); 
 
rc = SQLAllocStmt(*phdbc, phstmt); 
CHECKTEST(lpSrvr, SQL_SUCCESS, rc, "SQLAllocStmt"); 
 
rc = SQLFreeStmt(*phstmt, SQL_DROP); 
CHECKTEST(lpSrvr, SQL_SUCCESS, rc, "SQLFreeStmt"); 
 
rc = SQLDisconnect(*phdbc); 
CHECKTEST(lpSrvr, SQL_SUCCESS, rc, "SQLDisconnect"); 
 
rc = SQLFreeConnect(*phdbc); 
CHECKTEST(lpSrvr, SQL_SUCCESS, rc, "SQLFreeConnect"); 
 
rc = SQLFreeEnv(*phenv); 
CHECKTEST(lpSrvr, SQL_SUCCESS, rc, "SQLFreeEnv"); 
 
 
// check for errors 
CHECKERRS(sErr); 
 
 
return sErr; 
} 
 
  
  
  
 
 
 
 
 
//************************************************************************** 
//*************************  Utility Functions  **************************** 
//*  This section contains internal utility functions 
//************************************************************************** 
 
 
 
 
//*--------------------------------------------------------------------------------- 
//| CheckTest: 
//|This function will do a simple comparison of return codes and issue 
//|erros on failure.  Use the CHECKTEST macro to invoke. 
//| 
//| Returns: 
//|TRUE if the codes match, FALSE on error 
//*--------------------------------------------------------------------------------- 
BOOL FAR PASCAL CheckTest(lpSERVERINFO lps, RETCODE exprc, RETCODE actrc, 
LPSTRszFuncName) 
{ 
if(exprc != actrc) { 
szLogPrintf(lps, FALSE, "\t%s failed:\r\n", (LPSTR)szFuncName); 
szLogPrintf(lps, FALSE, "\t\tExpected: %d\r\n", exprc); 
szLogPrintf(lps, FALSE, "\t\tActual:   %d\r\n", actrc); 
return FALSE; 
} 
else 
return TRUE; 
}