diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 45977dfa..6977112b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Build tests +name: Build on: push: diff --git a/unittests/tier0test/tier0test.cpp b/unittests/tier0test/tier0test.cpp new file mode 100644 index 00000000..1ce6edd6 --- /dev/null +++ b/unittests/tier0test/tier0test.cpp @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for testing of tier0 libraries +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "appframework/IAppSystem.h" + +//----------------------------------------------------------------------------- +// Used to connect/disconnect the DLL +//----------------------------------------------------------------------------- +class CTier0TestAppSystem : public CTier0AppSystem< IAppSystem > +{ + typedef CTier0AppSystem< IAppSystem > BaseClass; + +public: + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + return true; + } + + virtual InitReturnVal_t Init() + { + return INIT_OK; + } + + virtual void Shutdown() + { + BaseClass::Shutdown(); + } +}; + +USE_UNITTEST_APPSYSTEM( CTier0TestAppSystem ) diff --git a/unittests/tier0test/wscript b/unittests/tier0test/wscript new file mode 100755 index 00000000..7d72c07c --- /dev/null +++ b/unittests/tier0test/wscript @@ -0,0 +1,39 @@ +#! /usr/bin/env python +# encoding: utf-8 + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'tier0test' + +def options(opt): + return + +def configure(conf): + conf.define('TIER1TEST_EXPORTS', 1) + +def build(bld): + source = ['tier0test.cpp'] + includes = ['../../public', '../../public/tier0'] + defines = [] + libs = ['tier0','tier1','unitlib'] + + if bld.env.DEST_OS != 'win32': + libs += [ 'DL', 'LOG' ] + else: + libs += ['USER32', 'SHELL32'] + + install_path = bld.env.TESTDIR + bld.shlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) diff --git a/unittests/tier1test/commandbuffertest.cpp b/unittests/tier1test/commandbuffertest.cpp index e51d6472..52120acf 100644 --- a/unittests/tier1test/commandbuffertest.cpp +++ b/unittests/tier1test/commandbuffertest.cpp @@ -6,7 +6,7 @@ //=============================================================================// #include "unitlib/unitlib.h" -#include "tier1/commandbuffer.h" +#include "tier1/CommandBuffer.h" #include "tier1/strtools.h" @@ -139,20 +139,24 @@ DEFINE_TESTCASE( CommandBufferTestTiming, CommandBufferTestSuite ) buffer.BeginProcessingCommands( 1 ); argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 3 ); Shipping_Assert( !Q_stricmp( argv[0], "test_command" ) ); Shipping_Assert( !Q_stricmp( argv[1], "test_arg1" ) ); Shipping_Assert( !Q_stricmp( argv[2], "test_arg2" ) ); argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); Shipping_Assert( !Q_stricmp( argv[0], "test_command3" ) ); argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); buffer.EndProcessingCommands( ); } + { buffer.BeginProcessingCommands( 1 ); diff --git a/unittests/tier1test/processtest.cpp b/unittests/tier1test/processtest.cpp deleted file mode 100644 index e83d7dc8..00000000 --- a/unittests/tier1test/processtest.cpp +++ /dev/null @@ -1,52 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Unit test program for processes -// -// $NoKeywords: $ -//=============================================================================// - -#include "unitlib/unitlib.h" -#include "vstdlib/iprocessutils.h" -#include "tier1/strtools.h" -#include "tier1/tier1.h" -#include "tier0/dbg.h" - - -DEFINE_TESTSUITE( ProcessTestSuite ) - -DEFINE_TESTCASE( ProcessTestSimple, ProcessTestSuite ) -{ - Msg( "Simple process test...\n" ); - - ProcessHandle_t hProcess = g_pProcessUtils->StartProcess( "unittests\\testprocess.exe -delay 1.0", true ); - g_pProcessUtils->WaitUntilProcessCompletes( hProcess ); - int nLen = g_pProcessUtils->GetProcessOutputSize( hProcess ); - char *pBuf = (char*)_alloca( nLen ); - g_pProcessUtils->GetProcessOutput( hProcess, pBuf, nLen ); - g_pProcessUtils->CloseProcess( hProcess ); - Shipping_Assert( !Q_stricmp( pBuf, "Test Finished!\n" ) ); -} - - -DEFINE_TESTCASE( ProcessTestBufferOverflow, ProcessTestSuite ) -{ - Msg( "Buffer overflow process test...\n" ); - - ProcessHandle_t hProcess = g_pProcessUtils->StartProcess( "unittests\\testprocess.exe -delay 1.0 -extrabytes 32768", true ); - g_pProcessUtils->WaitUntilProcessCompletes( hProcess ); - int nLen = g_pProcessUtils->GetProcessOutputSize( hProcess ); - Shipping_Assert( nLen == 32768 + 16 ); - char *pBuf = (char*)_alloca( nLen ); - g_pProcessUtils->GetProcessOutput( hProcess, pBuf, nLen ); - g_pProcessUtils->CloseProcess( hProcess ); - Shipping_Assert( !Q_strnicmp( pBuf, "Test Finished!\n", 15 ) ); - - int nEndExtraBytes = 32768; - char *pTest = pBuf + 15; - while( --nEndExtraBytes >= 0 ) - { - Shipping_Assert( *pTest == (( nEndExtraBytes % 10 ) + '0') ); - ++pTest; - } -} - diff --git a/unittests/tier1test/utlstringtest.cpp b/unittests/tier1test/utlstringtest.cpp index c0fe8729..11d630aa 100644 --- a/unittests/tier1test/utlstringtest.cpp +++ b/unittests/tier1test/utlstringtest.cpp @@ -180,20 +180,20 @@ static void FormatTests() static void FileNameAPITests() { - CUtlString path( "c:\\source2\\game\\source2\\somefile.ext" ); + CUtlString path( "/source2/game/source2/somefile.ext" ); CUtlString absPath = path.AbsPath(); Shipping_Assert( absPath == path ); CUtlString file = path.UnqualifiedFilename(); Shipping_Assert( !V_stricmp( file.Get(), "somefile.ext" ) ); CUtlString dir = path.DirName(); - Shipping_Assert( !V_stricmp( dir.Get(), "c:\\source2\\game\\source2" ) ); + Shipping_Assert( !V_stricmp( dir.Get(), "/source2/game/source2" ) ); dir = dir.DirName(); - Shipping_Assert( !V_stricmp( dir.Get(), "c:\\source2\\game" ) ); + Shipping_Assert( !V_stricmp( dir.Get(), "/source2/game" ) ); CUtlString baseName = path.StripExtension(); - Shipping_Assert( !V_stricmp( baseName.Get(), "c:\\source2\\game\\source2\\somefile" ) ); + Shipping_Assert( !V_stricmp( baseName.Get(), "/source2/game/source2/somefile" ) ); dir = path.StripFilename(); - Shipping_Assert( !V_stricmp( dir.Get(), "c:\\source2\\game\\source2" ) ); + Shipping_Assert( !V_stricmp( dir.Get(), "/source2/game/source2" ) ); file = path.GetBaseFilename(); Shipping_Assert( !V_stricmp( file.Get(), "somefile" ) ); @@ -201,7 +201,7 @@ static void FileNameAPITests() Shipping_Assert( !V_stricmp( ext.Get(), "ext" ) ); absPath = path.PathJoin( dir.Get(), file.Get() ); - Shipping_Assert( !V_stricmp( absPath.Get(), "c:\\source2\\game\\source2\\somefile" ) ); + Shipping_Assert( !V_stricmp( absPath.Get(), "/source2/game/source2/somefile" ) ); } DEFINE_TESTCASE( UtlStringTest, UtlStringTestSuite ) @@ -221,4 +221,4 @@ DEFINE_TESTCASE( UtlStringTest, UtlStringTestSuite ) FormatTests(); FileNameAPITests(); -} \ No newline at end of file +} diff --git a/unittests/tier1test/wscript b/unittests/tier1test/wscript new file mode 100755 index 00000000..ba69010a --- /dev/null +++ b/unittests/tier1test/wscript @@ -0,0 +1,39 @@ +#! /usr/bin/env python +# encoding: utf-8 + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'tier1test' + +def options(opt): + return + +def configure(conf): + conf.define('TIER1TEST_EXPORTS', 1) + +def build(bld): + source = ['commandbuffertest.cpp', 'utlstringtest.cpp', 'tier1test.cpp'] + includes = ['../../public', '../../public/tier0'] + defines = [] + libs = ['tier0', 'tier1', 'mathlib', 'unitlib'] + + if bld.env.DEST_OS != 'win32': + libs += [ 'DL', 'LOG' ] + else: + libs += ['USER32', 'SHELL32'] + + install_path = bld.env.TESTDIR + bld.shlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) diff --git a/unittests/tier2test/wscript b/unittests/tier2test/wscript new file mode 100755 index 00000000..9e38338c --- /dev/null +++ b/unittests/tier2test/wscript @@ -0,0 +1,39 @@ +#! /usr/bin/env python +# encoding: utf-8 + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'tier2test' + +def options(opt): + return + +def configure(conf): + conf.define('TIER2TEST_EXPORTS', 1) + +def build(bld): + source = ['tier2test.cpp'] + includes = ['../../public', '../../public/tier0'] + defines = [] + libs = ['tier0', 'tier1','tier2', 'mathlib', 'unitlib'] + + if bld.env.DEST_OS != 'win32': + libs += [ 'DL', 'LOG' ] + else: + libs += ['USER32', 'SHELL32'] + + install_path = bld.env.TESTDIR + bld.shlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) diff --git a/unittests/tier3test/wscript b/unittests/tier3test/wscript new file mode 100755 index 00000000..1d134a57 --- /dev/null +++ b/unittests/tier3test/wscript @@ -0,0 +1,39 @@ +#! /usr/bin/env python +# encoding: utf-8 + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'tier3test' + +def options(opt): + return + +def configure(conf): + conf.define('TIER3TEST_EXPORTS', 1) + +def build(bld): + source = ['tier3test.cpp'] + includes = ['../../public', '../../public/tier0'] + defines = [] + libs = ['tier0', 'tier1','tier2', 'tier3', 'mathlib', 'unitlib'] + + if bld.env.DEST_OS != 'win32': + libs += [ 'DL', 'LOG' ] + else: + libs += ['USER32', 'SHELL32'] + + install_path = bld.env.TESTDIR + bld.shlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) diff --git a/utils/unittest/unittest.cpp b/utils/unittest/unittest.cpp index 31b71016..a3de234b 100644 --- a/utils/unittest/unittest.cpp +++ b/utils/unittest/unittest.cpp @@ -6,33 +6,40 @@ //=============================================================================// #include "unitlib/unitlib.h" -#include "appframework/iappsystemgroup.h" -#include "appframework/appframework.h" +#include "appframework/IAppSystemGroup.h" +#include "appframework/AppFramework.h" #include "tier0/dbg.h" #include -#include #include "vstdlib/iprocessutils.h" #include "tier1/interface.h" #include "vstdlib/cvar.h" +#if defined(POSIX) +#include +#elif defined(WIN32) #pragma warning (disable:4100) +#include +#endif + +static int g_TestResult = 0; SpewRetval_t UnitTestSpew( SpewType_t type, char const *pMsg ) { switch( type ) { - case SPEW_WARNING: + case SPEW_WARNING: printf( "UnitTest Warning:\n" ); break; - case SPEW_ASSERT: + case SPEW_ASSERT: printf( "UnitTest Assert:\n" ); + g_TestResult = 1; break; - case SPEW_ERROR: + case SPEW_ERROR: printf( "UnitTest Error:\n" ); + g_TestResult = 1; break; } printf( "%s", pMsg ); - OutputDebugString( pMsg ); if ( Sys_IsDebuggerPresent() ) return ( type == SPEW_ASSERT || type == SPEW_ERROR ) ? SPEW_DEBUGGER : SPEW_CONTINUE; @@ -69,7 +76,7 @@ bool CUnitTestApp::Create() // FIXME: This list of dlls should come from the unittests themselves AppSystemInfo_t appSystems[] = { - { "vstdlib.dll", PROCESS_UTILS_INTERFACE_VERSION }, +// { "vstdlib.so", PROCESS_UTILS_INTERFACE_VERSION }, { "", "" } // Required to terminate the list }; @@ -84,12 +91,16 @@ bool CUnitTestApp::Create() // or giving test DLLs special extensions, or statically linking the test DLLs // to this program. +#ifdef WIN32 WIN32_FIND_DATA findFileData; - HANDLE hFind= FindFirstFile("*.dll", &findFileData); + HANDLE hFind= FindFirstFile("tests/*.dll", &findFileData); while (hFind != INVALID_HANDLE_VALUE) { - CSysModule* hLib = Sys_LoadModule(findFileData.cFileName); + static char path[2048]; + snprintf(path, sizeof(path), "tests/%s", findFileData.cFileName); + + CSysModule* hLib = Sys_LoadModule(path); if ( hLib ) { CreateInterfaceFn factory = Sys_GetFactory( hLib ); @@ -107,6 +118,40 @@ bool CUnitTestApp::Create() if (!FindNextFile( hFind, &findFileData )) break; } +#elif POSIX + DIR *d; + struct dirent *dir; + d = opendir("tests"); + if (d) + { + while ((dir = readdir(d)) != NULL) + { + int len = strlen(dir->d_name); + if( len > 2 && strcmp(dir->d_name+len-3, ".so") == 0) + { + static char path[2048]; + snprintf(path, sizeof(path), "tests/%s", dir->d_name); + CSysModule* hLib = Sys_LoadModule(path); + if ( hLib ) + { + CreateInterfaceFn factory = Sys_GetFactory( hLib ); + if ( factory && factory( UNITTEST_INTERFACE_VERSION, NULL ) ) + { + AppModule_t module = LoadModule( factory ); + AddSystem( module, UNITTEST_INTERFACE_VERSION ); + } + else + { + Sys_UnloadModule( hLib ); + } + } + } + } + closedir(d); + } +#else +#error "Implement me!" +#endif return true; } @@ -121,7 +166,7 @@ void CUnitTestApp::Destroy() //----------------------------------------------------------------------------- int CUnitTestApp::Main() { - printf( "Valve Software - unittest.exe (%s)\n", __DATE__ ); + printf( "Valve Software - unittest (%s)\n", __DATE__ ); int nTestCount = UnitTestCount(); for ( int i = 0; i < nTestCount; ++i ) @@ -131,5 +176,5 @@ int CUnitTestApp::Main() pTestCase->RunTest(); } - return 0; + return g_TestResult; } diff --git a/utils/unittest/wscript b/utils/unittest/wscript new file mode 100755 index 00000000..24d4c3c1 --- /dev/null +++ b/utils/unittest/wscript @@ -0,0 +1,40 @@ +#! /usr/bin/env python +# encoding: utf-8 + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'unittest' + +def options(opt): + # stub + return + +def configure(conf): + conf.define('PROTECTED_THINGS_DISABLE',1) + +def build(bld): + source = ['unittest.cpp'] + includes = ['../../public'] + defines = [] + libs = ['tier0', 'appframework', 'tier1', 'tier2','tier3', 'vstdlib', 'unitlib'] + + if bld.env.DEST_OS != 'win32': + libs += [ 'DL', 'LOG' ] + else: + libs += ['USER32', 'SHELL32'] + + install_path = bld.env.BINDIR + bld( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx cxxprogram', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) diff --git a/wscript b/wscript index ed37ba9d..f6d5d114 100644 --- a/wscript +++ b/wscript @@ -77,6 +77,23 @@ projects={ 'vtf', 'unicode' ], + 'tests': [ + 'appframework', + 'tier0', + 'tier1', + 'tier2', + 'tier3', + 'unitlib', + 'mathlib', + 'vstdlib', + 'filesystem', + 'vpklib', + 'unittests/tier0test', + 'unittests/tier1test', + 'unittests/tier2test', + 'unittests/tier3test', + 'utils/unittest' + ], 'dedicated': [ 'appframework', 'bitmap', @@ -136,6 +153,7 @@ def get_taskgen_count(self): def define_platform(conf): conf.env.DEDICATED = conf.options.DEDICATED + conf.env.TESTS = conf.options.TESTS conf.env.TOGLES = conf.options.TOGLES conf.env.GL = conf.options.GL conf.env.OPUS = conf.options.OPUS @@ -211,6 +229,9 @@ def options(opt): grp.add_option('-d', '--dedicated', action = 'store_true', dest = 'DEDICATED', default = False, help = 'build dedicated server [default: %default]') + grp.add_option('--tests', action = 'store_true', dest = 'TESTS', default = False, + help = 'build unit tests [default: %default]') + grp.add_option('-D', '--debug-engine', action = 'store_true', dest = 'DEBUG_ENGINE', default = False, help = 'build with -DDEBUG [default: %default]') @@ -494,6 +515,7 @@ def configure(conf): # indicate if we are packaging for Linux/BSD if conf.env.DEST_OS != 'android': conf.env.LIBDIR = conf.env.PREFIX+'/bin/' + conf.env.TESTDIR = conf.env.PREFIX+'/tests/' conf.env.BINDIR = conf.env.PREFIX else: conf.env.LIBDIR = conf.env.BINDIR = conf.env.PREFIX @@ -502,7 +524,9 @@ def configure(conf): conf.env.CC.insert(0, 'ccache') conf.env.CXX.insert(0, 'ccache') - if conf.options.DEDICATED: + if conf.options.TESTS: + conf.add_subproject(projects['tests']) + elif conf.options.DEDICATED: conf.add_subproject(projects['dedicated']) else: conf.add_subproject(projects['game']) @@ -517,7 +541,9 @@ def build(bld): if bld.env.OPUS or bld.env.DEST_OS == 'android': projects['game'] += ['engine/voice_codecs/opus'] - if bld.env.DEDICATED: + if bld.env.TESTS: + bld.add_subproject(projects['tests']) + elif bld.env.DEDICATED: bld.add_subproject(projects['dedicated']) else: if bld.env.TOGLES: