For nearly everyone who has written tux based tests for Windows CE, the tux function table is a big ugly mystery that most try to ignore as much as possible.  This short(?) article will attempt to explain some of the details of that structure.

 

MSDN documents the function table with this short paragraph:

A Tux test DLL module uses the function table to export the test cases for the module to Tux. A test DLL module typically creates a static array of FUNCTION_TABLE_ENTRY structures, filling in each of the fields with relevant information. Each structure in the function table represents a single test or group of tests in the test DLL module.

 

If you use the wizard in platform builder to create a tux dll, it will create a function table that looks something like this:

 

BEGIN_FTE

    FTH(0, "Sample test cases")

    FTE(1,      "Sample test", 1, 0, TestProc)

END_FTE

 

That looks simple enough…until you scroll up a few lines to see exactly what the FTE and FTH macros do.  If/when you do this, you’ll see this...mess:

 

#ifdef __DEFINE_FTE__

#undef BEGIN_FTE

#undef FTE

#undef FTH

#undef END_FTE

#define BEGIN_FTE FUNCTION_TABLE_ENTRY g_lpFTE[] = {

#define FTH(a, b) { TEXT(b), a, 0, 0, NULL },

#define FTE(a, b, c, d, e) { TEXT(b), a, d, c, e },

#define END_FTE { NULL, 0, 0, 0, NULL } };

#else // __DEFINE_FTE__

#ifdef __GLOBALS_CPP__

#define BEGIN_FTE

#else // __GLOBALS_CPP__

#define BEGIN_FTE extern FUNCTION_TABLE_ENTRY g_lpFTE[];

#endif // __GLOBALS_CPP__

#define FTH(a, b)

#define FTE(a, b, c, d, e) TESTPROCAPI e(UINT, TPPARAM, LPFUNCTION_TABLE_ENTRY);

#define END_FTE

#endif // __DEFINE_FTE__

 

 

This block of “code”, believe it or not, was written to make it easier to create a function table entry for a tux module.  It creates a pointer to a global FTE (g_lpFTE), which can be helpful, but it also flips some parameters around, which in my opinion, is confusing. 


 

Before I attempt to decipher the above, let’s see how tux.h defines the function table structure:

 

typedef struct _FUNCTION_TABLE_ENTRY {

   LPCTSTR  lpDescription; // description of test

   UINT     uDepth;        // depth of item in tree hierarchy

   DWORD    dwUserData;    // user defined data that will be passed to TestProc at runtime

   DWORD    dwUniqueID;    // uniquely identifies the test - used in loading/saving scripts

   TESTPROC lpTestProc;    // pointer to TestProc function to be called for this test

} FUNCTION_TABLE_ENTRY, *LPFUNCTION_TABLE_ENTRY;

 

 

Aaah – this is much more decipherable.  The function table consists of 5 entries which describe and identify the test, as well as provide a pointer to the test to execute.

 

Two pieces of information regarding the function table not in the above code block are that a NULL lpTestProc is valid (I’ll explain why in a moment), and that when tux parses an array of function tables, it expects the final entry to contain all NULL’s.

 

If we go back to the original block:

 

BEGIN_FTE

    FTH(0, "Sample test cases")

    FTE(1,      "Sample test", 1, 0, TestProc)

END_FTE

 

then expand the macros, we’ll see this:

 

FUNCTION_TABLE_ENTRY g_lpFTE[] =

{

    { L"Sample test cases", 0, 0, 0, 0 },

    { L"Sample Test",       1, 0, 0, TestProc },

    { 0,                    0, 0, 0, 0 }

};

 

Let’s break it down.

 

We’ve declared an array of FUNTION_TABLE_ENTRY structures.  The first structure is setup as:

lpDescription = “Sample Test Cases”

uDepth = 0

dwUserData = 0

dwUniqueId = 1

lpTestProc = 0

 

A null lpTestProc address means that this is just an organizational entry.  You will (nearly?) always want to use a null lpTestProc when using a depth of 0 (the macros do this for you).

 

The following structure is identical to the first except for having uDepth set to 1, and providing the address of the TestProc function as the lpTestProc parameter.  The unique id is used to both for test identification, and with the ‘–x’ parameter to tux to run specific test cases.

 

The final structure is all 0’s to inform tux that there are no more function table’s in the array.

 

If you don’t care about any of the above, and really just want the answer to “What do those macros do” question, here’s the key:

 

BEGIN_FTEDeclares an array of function tables.  Literally expands to FUNCTION_TABLE_ENTRY g_lpFTE[] =

 

FTH – Function table “Header” – an entry with a NULL lpTestProc parameter.  For example:  FTH(0, "Sample test cases") expands to { L"Sample test cases", 0, 0, 0, 0 },

Note that the wide char identifier is automatically added to the string

 

FTE – Function table “Entry” – an entry containing a unique ID and TestProc to run.  It can optionally contain additional data to pass to the test.  For example, FTE(1, "Sample test", 1, 0, TestProc) expands to L"Sample Test",       1, 0, 0, TestProc },

 

END_FTE – Ends the array of function tables.  This macro expands to { 0,                    0, 0, 0, 0 } }; (a null array followed by a closing bracket for the overall structure.

 

Do you have to use the macros?  Nope.  You can create your own array, or even create your own macros.  The macros created in the wizard are there to (hopefully) make things easier.  YMMV.

 

I think I covered everything to do with these macros, but if you have any questions, please feel free to ask.  Also feel free to request further explanations on anything to do with writing tests using tux.

 

This article is (or will be) cross posted on news:microsoft.public.windowsce.testtools and http://blogs.msdn.com/alanpa/