Authoring a test suite
Having installed cfix, we can now write a first test. The source code of a kernel mode unit test is identical to user mode tests, so we can use the same samples as supplied in the user mode tutorial (The only differences are that ULONGs are used rather than DWORDs and stdafx.h has been removed). A minimalistic test project could thus consist of the following code:
#include <cfix.h> /*++ Routine Description: Test routine -- do the actual testing. --*/ static void __stdcall Test1() { int a = 1; int b = 1; CFIX_ASSERT( a + b == 2 ); } CFIX_BEGIN_FIXTURE( MyMinimalisticFixture ) CFIX_FIXTURE_ENTRY( Test1 ) CFIX_END_FIXTURE()
But let us look at a more interesting example like the following:
// // Always include cfix.h! // #include <cfix.h> /*++ Routine Description: Setup Routine -- will be called at the very beginning of the testrun. If the setup routine fails, no testcase of this fixture will be executed. As WDK projects use __stdcall by default, there is usually no need to explicitly specify __stdcall on your routines. As the routine is referenced only by the fixture definition (see below), you may declare this routine as static. --*/ static void FixtureSetup() { CFIX_ASSERT( 0 != 1 ); } /*++ Routine Description: Teardown Routine -- will be called at the end of the testrun. --*/ static void FixtureTeardown() { CFIX_LOG( L"Tearing down..." ); } /*++ Routine Description: Test routine -- do the actual testing. --*/ static void Test1() { ULONG a = 1; ULONG b = 1; CFIX_ASSERT_EQUALS_ULONG( a, b ); CFIX_ASSERT( a + b == 2 ); // // Log a message -- printf-style formatting may be used. // CFIX_LOG( L"a=%d, b=%d", a, b ); } /*++ Routine Description: Another test routine -- one that will trigger a failed assertion. --*/ static void Test2() { ULONG a = 17; // // This one will fail. If run in the debugger, it will break here. // if run outside the debugger, the failure will be logged and the // testcase is aborted. // CFIX_ASSERT( a == 42 ); } /*++ Description: These lines define a test fixture. It is best to put this at the end of the file. 'MyFixture' is the name of the fixture. It must be unique across all fixtures of this driver. The same restrictions as for naming routines apply, i.e. no spaces, no special characters etc. The order of CFIX_FIXTURE_ENTRY, CFIX_FIXTURE_SETUP and CFIX_FIXTURE_TEARDOWN is irrelevant. For the current release, however, (1.1), the order of FIXTURE_ENTRYs defines the execution order. --*/ CFIX_BEGIN_FIXTURE( MyFixture ) // // Define Test1 and Test2 to be test routines. You can define any // number of test routines. // CFIX_FIXTURE_ENTRY( Test1 ) CFIX_FIXTURE_ENTRY( Test2 ) // // Define FixtureSetup to be a setup routine. At most one // CFIX_FIXTURE_SETUP line may be declared per fixture. If the // fixture does not require setup, omit this line. // CFIX_FIXTURE_SETUP( FixtureSetup ) // // Define FixtureTeardown to be a teardown routine. As with // setup routines, you can declare at most one such routine // per fixture. If the fixture does not require teardown, // omit this line. // CFIX_FIXTURE_TEARDOWN( FixtureTeardown ) CFIX_END_FIXTURE() CFIX_BEGIN_FIXTURE( MyOtherFixture ) // // You are free to reuse certain routines in another fixture if // it makes sense. // CFIX_FIXTURE_ENTRY( Test1 ) CFIX_END_FIXTURE()
As usual for WDK projects, we have to supply a SOURCES file. Assuming you have saved your test code to a file named test.c, the SOURCES file should look as follows:
INCLUDES=$(CFIX_HOME)\include;$(DDK_INC_PATH) MSC_WARNING_LEVEL=/W4 /WX /Wp64 # # It is essential that CFIX_KERNELMODE is defined here! # USER_C_FLAGS=/DCFIX_KERNELMODE # # Link against cfixkdrv.lib. # TARGETLIBS=\ $(CFIX_HOME)\bin\$(TARGET_DIRECTORY)\cfixkdrv.lib TARGETNAME=ktest TARGETPATH=bin\$(DDKBUILDENV) TARGETTYPE=DRIVER SOURCES=test.c
As the comments in the file suggest, two things are of importance. First you have to include /DCFIX_KERNELMODE in USER_C_FLAGS. If you forget to define CFIX_KERNELMODE, the cfix headers will assume you are building a user mode test project and will, for example, try to bring in windows.h -- which, of course, will be inappropriate for a kernel mode test.
Secondly, you have to link against cfixkdrv.lib. This library includes the stub routines for the cfix API. Moreover, this library includes an implementation of DriverEntry, which will turn your test project into a full-fledged driver.
One file is still missing -- the export definition file. Create a file named ktest.def (assuming that you used TARGETNAME=ktest) and add a single line:
EXPORTS
That's it. Open a WDK command promot with the a build environment of choice and create the test driver by running build.exe. This will result in bin\chk\i386\ktest.sys to be created.