diff options
Diffstat (limited to 'public/unitlib')
| -rw-r--r-- | public/unitlib/unitlib.h | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/public/unitlib/unitlib.h b/public/unitlib/unitlib.h new file mode 100644 index 0000000..c27817d --- /dev/null +++ b/public/unitlib/unitlib.h @@ -0,0 +1,270 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef UNITLIB_H +#define UNITLIB_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier1/interface.h" +#include "appframework/IAppSystem.h" + + +//----------------------------------------------------------------------------- +// Usage model for the UnitTest library +// +// The general methodology here is that clients are expected to create unit +// test DLLs that statically link to the unit test DLL and which implement +// tests of various libraries. The unit test application will dynamically +// load all DLLs in a directory, which causes them to install their test cases +// into the unit test system. The application then runs through all tests and +// executes them all, displaying the results. +// +// *** NOTE: The test suites are compiled in both debug and release builds, +// even though it's expected to only be useful in debug builds. This is because +// I couldn't come up with a good way of disabling the code in release builds. +// (The only options I could come up with would still compile in the functions, +// just not install them into the unit test library, or would make it so that +// you couldn't step through the unit test code). +// +// Even though this is the case, there's no reason not to add test cases +// directly into your shipping DLLs, as long as you surround the code with +// #ifdef _DEBUG. To error check a project to make sure it's not compiling +// in unit tests in Release build, just don't link in unitlib.lib in Release. +// You can of course also put your test suites into separate DLLs. +// +// All tests inherit from the ITestCase interface. There are two major kinds +// of tests; the first is a single test case meant to run a piece of +// code and check its results match expected values using the Assert macros. +// The second kind is a test suite which is simply a list of other tests. +// +// The following classes and macros are used to easily create unit test cases +// and suites: +// +// Use DEFINE_TESTSUITE to define a particular test suite, and DEFINE_TESTCASE +// to add as many test cases as you like to that test suite, as follows: +// +// DEFINE_TESTSUITE( VectorTestSuite ) +// +// DEFINE_TESTCASE( VectorAdditionTest, VectorTestSuite ) +// { +// .. test code here .. +// } +// +// Note that the definition of the test suite can occur in a different file +// as the test case. A link error will occur if the test suite to which a +// test case is added has not been defined. +// +// To create a test case that is not part of a suite, use... +// +// DEFINE_TESTCASE_NOSUITE( VectorAdditionTest ) +// { +// .. test code here .. +// } +// +// You can also create a suite which is a child of another suite using +// +// DEFINE_SUBSUITE( VectorTestSuite, MathTestSuite ) +// +//----------------------------------------------------------------------------- + + + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- + +#ifdef UNITLIB_DLL_EXPORT +#define UNITLIB_INTERFACE DLL_EXPORT +#define UNITLIB_CLASS_INTERFACE DLL_CLASS_EXPORT +#define UNITLIB_GLOBAL_INTERFACE DLL_GLOBAL_EXPORT +#else +#define UNITLIB_INTERFACE DLL_IMPORT +#define UNITLIB_CLASS_INTERFACE DLL_CLASS_IMPORT +#define UNITLIB_GLOBAL_INTERFACE DLL_GLOBAL_IMPORT +#endif + + +//----------------------------------------------------------------------------- +// All unit test libraries can be asked for a unit test +// AppSystem to perform connection +//----------------------------------------------------------------------------- +#define UNITTEST_INTERFACE_VERSION "UnitTestV001" + + +//----------------------------------------------------------------------------- +// +// NOTE: All classes and interfaces below you shouldn't use directly. +// Use the DEFINE_TESTSUITE and DEFINE_TESTCASE macros instead. +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Test case + suite interface +//----------------------------------------------------------------------------- +class ITestCase +{ +public: + // This returns the test name + virtual char const* GetName() = 0; + + // This runs the test + virtual void RunTest() = 0; +}; + +class ITestSuite : public ITestCase +{ +public: + // Add a test to the suite... + virtual void AddTest( ITestCase* pTest ) = 0; +}; + + + +//----------------------------------------------------------------------------- +// This is the main function exported by the unit test library used by +// unit test DLLs to install their test cases into a list to be run +//----------------------------------------------------------------------------- +UNITLIB_INTERFACE void UnitTestInstallTestCase( ITestCase* pTest ); + + +//----------------------------------------------------------------------------- +// These are the methods used by the unit test running program to run all tests +//----------------------------------------------------------------------------- +UNITLIB_INTERFACE int UnitTestCount(); +UNITLIB_INTERFACE ITestCase* GetUnitTest( int i ); + + +//----------------------------------------------------------------------------- +// Helper for unit test DLLs to expose IAppSystems +//----------------------------------------------------------------------------- +#define USE_UNITTEST_APPSYSTEM( _className ) \ + static _className s_UnitTest ## _className; \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR( _className, IAppSystem, UNITTEST_INTERFACE_VERSION, s_UnitTest ## _className ); + + +//----------------------------------------------------------------------------- +// Base class for test cases +//----------------------------------------------------------------------------- +class UNITLIB_CLASS_INTERFACE CTestCase : public ITestCase +{ +public: + CTestCase( char const* pName, ITestSuite* pParent = 0 ); + ~CTestCase(); + + // Returns the test name + char const* GetName(); + +private: + char* m_pName; +}; + + +//----------------------------------------------------------------------------- +// Test suite class +//----------------------------------------------------------------------------- +class UNITLIB_CLASS_INTERFACE CTestSuite : public ITestSuite +{ +public: + CTestSuite( char const* pName, ITestSuite* pParent = 0 ); + ~CTestSuite(); + + // This runs the test + void RunTest(); + + // Add a test to the suite... + void AddTest( ITestCase* pTest ); + + // Returns the test name + char const* GetName(); + +protected: + int m_TestCount; + ITestCase** m_ppTestCases; + char* m_pName; +}; + +#define TESTSUITE_CLASS( _suite ) \ + class CTS ## _suite : public CTestSuite \ + { \ + public: \ + CTS ## _suite(); \ + }; + +#define TESTSUITE_ACCESSOR( _suite ) \ + CTS ## _suite* GetTS ## _suite() \ + { \ + static CTS ## _suite s_TS ## _suite; \ + return &s_TS ## _suite; \ + } + +#define FWD_DECLARE_TESTSUITE( _suite ) \ + class CTS ## _suite; \ + CTS ## _suite* GetTS ## _suite(); + +#define DEFINE_TESTSUITE( _suite ) \ + TESTSUITE_CLASS( _suite ) \ + TESTSUITE_ACCESSOR( _suite ) \ + CTS ## _suite::CTS ## _suite() : CTestSuite( #_suite ) {} + +#define DEFINE_SUBSUITE( _suite, _parent ) \ + TESTSUITE_CLASS( _suite ) \ + TESTSUITE_ACCESSOR( _suite ) \ + FWD_DECLARE_TESTSUITE( _parent ) \ + CTS ## _suite::CTS ## _suite() : CTestSuite( #_suite, GetTS ## _parent() ) {} + +#define TESTCASE_CLASS( _case ) \ + class CTC ## _case : public CTestCase \ + { \ + public: \ + CTC ## _case (); \ + void RunTest(); \ + }; + +#define DEFINE_TESTCASE_NOSUITE( _case ) \ + TESTCASE_CLASS( _case ) \ + CTC ## _case::CTC ## _case () : CTestCase( #_case ) {} \ + \ + CTC ## _case s_TC ## _case; \ + \ + void CTC ## _case ::RunTest() + +#define DEFINE_TESTCASE( _case, _suite ) \ + TESTCASE_CLASS( _case ) \ + FWD_DECLARE_TESTSUITE( _suite ) \ + CTC ## _case::CTC ## _case () : CTestCase( #_case, GetTS ## _suite() ) {} \ + \ + CTC ## _case s_TC ## _case; \ + \ + void CTC ## _case ::RunTest() + + +#define _Shipping_AssertMsg( _exp, _msg, _executeExp, _bFatal ) \ + do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __TFILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage(_msg); \ + _executeExp; \ + if ( ret == SPEW_DEBUGGER) \ + { \ + if ( !ShouldUseNewAssertDialog() || DoNewAssertDialog( __TFILE__, __LINE__, _msg ) ) \ + DebuggerBreak(); \ + if ( _bFatal ) \ + _ExitOnFatalAssert( __TFILE__, __LINE__ ); \ + } \ + } \ + } while (0) + +#define Shipping_Assert( _exp ) _Shipping_AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) + + +#endif // UNITLIB_H |