254 lines
9.8 KiB
C++
254 lines
9.8 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//
|
|
//=============================================================================//
|
|
|
|
#ifndef UNITLIB_H
|
|
#define UNITLIB_H
|
|
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "appframework/IAppSystem.h"
|
|
#include "tier0/platform.h"
|
|
#include "tier1/interface.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
|