mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-03-22 13:19:40 +01:00
Add loader tests.
This commit is contained in:
parent
dc41559c79
commit
7e24188759
@ -368,6 +368,7 @@ BuildScripts = [
|
||||
if getattr(builder.options, 'enable_tests', False):
|
||||
BuildScripts += [
|
||||
'core/sourcehook/test/AMBuilder',
|
||||
'loader/test/AMBuilder',
|
||||
]
|
||||
|
||||
if builder.backend == 'amb2':
|
||||
|
15
README.md
15
README.md
@ -55,3 +55,18 @@ General documentation: <https://wiki.alliedmods.net/Category:Metamod:Source_Docu
|
||||
Detouring with SourceHook: <https://wiki.alliedmods.net/SourceHook_Development>
|
||||
|
||||
Development: <https://wiki.alliedmods.net/Category:Metamod:Source_Development>
|
||||
|
||||
|
||||
Unit testing:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
python ../configure.py --sdks episode1 --enable-tests
|
||||
ambuild
|
||||
```
|
||||
|
||||
To test the loader code on Windows:
|
||||
```
|
||||
loader/test/test_loader/windows-x86/test_loader.exe
|
||||
loader/test/test_loader/windows-x86_64/test_loader.exe
|
||||
```
|
||||
|
@ -4,6 +4,8 @@ import os
|
||||
for cxx in MMS.all_targets:
|
||||
name = 'test_sourcehook'
|
||||
binary = MMS.Program(cxx, name)
|
||||
if binary.compiler.target.platform == 'windows':
|
||||
continue
|
||||
if binary.compiler.target.arch == 'x86_64' and binary.compiler.target.platform == 'linux':
|
||||
continue
|
||||
|
||||
@ -12,6 +14,7 @@ for cxx in MMS.all_targets:
|
||||
]
|
||||
|
||||
binary.compiler.cxxincludes += [
|
||||
os.path.join(builder.sourcePath, 'core'),
|
||||
os.path.join(builder.sourcePath, 'core', 'sourcehook'),
|
||||
]
|
||||
if binary.compiler.version >= 'gcc-4.9':
|
||||
|
0
core/sourcehook/test/version.rc
Normal file
0
core/sourcehook/test/version.rc
Normal file
35
loader/test/AMBuilder
Normal file
35
loader/test/AMBuilder
Normal file
@ -0,0 +1,35 @@
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
import os
|
||||
|
||||
for cxx in MMS.all_targets:
|
||||
name = 'test_loader'
|
||||
binary = MMS.Program(cxx, name)
|
||||
|
||||
if binary.compiler.target.platform == 'windows' and binary.compiler.target.arch == 'x86_64':
|
||||
binary.compiler.defines += ['WIN64']
|
||||
|
||||
# TODO: hack - something makes it try and compile with /SUBSYSTEM:WINDOWS which then causes it to complain that WinMain is missing
|
||||
if binary.compiler.target.platform == 'windows':
|
||||
binary.compiler.linkflags = ['Advapi32.lib', 'kernel32.lib', 'shell32.lib']
|
||||
|
||||
binary.compiler.cxxincludes += [
|
||||
os.path.join(builder.sourcePath, 'core'),
|
||||
os.path.join(builder.sourcePath, 'core', 'sourcehook'),
|
||||
os.path.join(builder.sourcePath, 'loader'),
|
||||
]
|
||||
|
||||
if binary.compiler.version >= 'gcc-4.9':
|
||||
binary.compiler.cxxflags += ['-fno-devirtualize']
|
||||
if binary.compiler.version >= 'clang-2.9' or binary.compiler.version >= 'apple-clang-3.0':
|
||||
binary.compiler.cxxflags += ['-Wno-null-dereference']
|
||||
|
||||
binary.sources += [
|
||||
'main.cpp',
|
||||
'../gamedll.cpp',
|
||||
'../loader.cpp',
|
||||
'../serverplugin.cpp',
|
||||
'../utility.cpp',
|
||||
'testdeterminebackends1.cpp',
|
||||
]
|
||||
|
||||
builder.Add(binary)
|
44
loader/test/main.cpp
Normal file
44
loader/test/main.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
using namespace std;
|
||||
bool g_Verbose;
|
||||
|
||||
#define DECL_TEST(x) bool Test##x(std::string &error);
|
||||
|
||||
#define DO_TEST(x) \
|
||||
error.clear(); \
|
||||
if (Test##x(error)) \
|
||||
{ \
|
||||
++passed; \
|
||||
cout << "Test" << #x << " passed" << endl; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
++failed; \
|
||||
cout << "Test" << #x << " FAILED: " << error << endl; \
|
||||
} \
|
||||
|
||||
|
||||
DECL_TEST(DetermineBackendS1);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
std::string error;
|
||||
|
||||
g_Verbose = argc > 1 && strcmp(argv[1], "-v") == 0;
|
||||
|
||||
int passed = 0, failed = 0;
|
||||
|
||||
DO_TEST(DetermineBackendS1);
|
||||
|
||||
cout << endl << "----" << endl << "Passed: " << passed << endl << "Failed: " << failed << endl;
|
||||
cout << "Total: " << passed + failed << endl;
|
||||
|
||||
if (failed)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
222
loader/test/testdeterminebackends1.cpp
Normal file
222
loader/test/testdeterminebackends1.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif // _WIN32
|
||||
#include "loader.h"
|
||||
#include "utility.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
bool g_64Bit = true;
|
||||
#else
|
||||
bool g_64Bit = false;
|
||||
#endif
|
||||
|
||||
struct GameAttributes
|
||||
{
|
||||
// none of these will really be PLATFORM_MAX_PATH but they're paths, so make them long enough
|
||||
char gamePath[PLATFORM_MAX_PATH];
|
||||
char gameDirectory[PLATFORM_MAX_PATH];
|
||||
char binPath[PLATFORM_MAX_PATH];
|
||||
MetamodBackend expectedBackend;
|
||||
bool is64Bit;
|
||||
};
|
||||
|
||||
std::string GetSteamInstallationPath()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
char pathBuffer[512];
|
||||
HKEY hKey;
|
||||
ULONG statusCode;
|
||||
DWORD bufferSize = sizeof(pathBuffer);
|
||||
|
||||
LONG result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432Node\\Valve\\Steam", 0, KEY_READ, &hKey);
|
||||
|
||||
// if it's not find, try the 32-bit path
|
||||
if (result == ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Valve\\Steam", 0, KEY_READ, &hKey);
|
||||
}
|
||||
|
||||
statusCode = RegQueryValueExA(hKey, "InstallPath", 0, NULL, (LPBYTE)pathBuffer, &bufferSize);
|
||||
|
||||
if (statusCode == ERROR_SUCCESS)
|
||||
{
|
||||
return pathBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Error: RegQueryValueExA returned " << statusCode << std::endl;
|
||||
|
||||
return "";
|
||||
}
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TestDetermineBackendS1(std::string &error)
|
||||
{
|
||||
std::string steamInstallationPath = GetSteamInstallationPath();
|
||||
std::map<std::string, GameAttributes> games;
|
||||
char errorBuffer[128];
|
||||
char currentDirectoryBuffer[PLATFORM_MAX_PATH];
|
||||
char directoryBuffer[PLATFORM_MAX_PATH];
|
||||
void *serverLib = nullptr;
|
||||
void *engineLib = nullptr;
|
||||
QueryValveInterface serverQvi;
|
||||
QueryValveInterface engineQvi;
|
||||
|
||||
if (steamInstallationPath == "")
|
||||
{
|
||||
std::cout << "Warning: exiting early as Steam installation not found" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: when C++20 is supported, use designated initialisers
|
||||
games["Black Mesa"] = {
|
||||
/*.gamePath = */"steamapps\\common\\Black Mesa\\",
|
||||
/*.gameDirectory = */"bms",
|
||||
/*.binPath = */"bin",
|
||||
/*.expectedBackend = */MMBackend_BMS,
|
||||
/*.is64Bit = */false
|
||||
};
|
||||
games["Bloody Good Time"] = {
|
||||
/*.gamePath = */"steamapps\\common\\Bloody Good Time\\",
|
||||
/*.gameDirectory = */"pm",
|
||||
/*.binPath = */"bin",
|
||||
/*.expectedBackend = */MMBackend_BloodyGoodTime,
|
||||
/*.is64Bit = */false
|
||||
};
|
||||
games["Bloody Good Time Dedicated Server"] = {
|
||||
/*.gamePath = */"steamapps\\common\\Bloody Good Time Dedicated Server\\",
|
||||
/*.gameDirectory = */"pm",
|
||||
/*.binPath = */"bin",
|
||||
/*.expectedBackend = */MMBackend_BloodyGoodTime,
|
||||
/*.is64Bit = */false
|
||||
};
|
||||
games["Counter-Strike: Source"] = {
|
||||
/*.gamePath = */"steamapps\\common\\Counter-Strike Source\\",
|
||||
/*.gameDirectory = */"cstrike",
|
||||
/*.binPath = */"bin\\x64",
|
||||
/*.expectedBackend = */MMBackend_CSS,
|
||||
/*.is64Bit = */true
|
||||
};
|
||||
games["Counter-Strike: Global Offensive"] = {
|
||||
/*.gamePath = */"steamapps\\common\\Counter-Strike Global Offensive\\",
|
||||
/*.gameDirectory = */"csgo",
|
||||
/*.binPath = */"bin",
|
||||
/*.expectedBackend = */MMBackend_CSGO,
|
||||
/*.is64Bit = */false
|
||||
};
|
||||
games["Half-Life 2: Deathmatch"] = {
|
||||
/*.gamePath = */"steamapps\\common\\Half-Life 2 Deathmatch\\",
|
||||
/*.gameDirectory = */"hl2mp",
|
||||
/*.binPath = */"bin\\x64",
|
||||
/*.expectedBackend = */MMBackend_HL2DM,
|
||||
/*.is64Bit = */true
|
||||
};
|
||||
games["Military Conflict: Vietnam"] = {
|
||||
/*.gamePath = */"steamapps\\common\\Military Conflict - Vietnam\\",
|
||||
/*.gameDirectory = */"vietnam",
|
||||
/*.binPath = */"bin\\win64",
|
||||
/*.expectedBackend = */MMBackend_MCV,
|
||||
/*.is64Bit = */true
|
||||
};
|
||||
games["Portal 2"] = {
|
||||
/*.gamePath = */"steamapps\\common\\Portal 2\\",
|
||||
/*.gameDirectory = */"portal2",
|
||||
/*.binPath = */"bin",
|
||||
/*.expectedBackend = */MMBackend_Portal2,
|
||||
/*.is64Bit = */false
|
||||
};
|
||||
// TODO: skip for now as sourcetest is still 32-bit but the engine is 64-bit
|
||||
// games["Source SDK Base 2013 Multiplayer"] = {
|
||||
// /*.gamePath = */"steamapps\\common\\Source SDK Base 2013 Multiplayer\\",
|
||||
// /*.gameDirectory = */"sourcetest",
|
||||
// /*.binPath = */"bin",
|
||||
// /*.expectedBackend = */MMBackend_HL2DM,
|
||||
// /*.is64Bit = */true
|
||||
// };
|
||||
games["Team Fortress 2"] = {
|
||||
/*.gamePath = */"steamapps\\common\\Team Fortress 2\\",
|
||||
/*.gameDirectory = */"tf",
|
||||
/*.binPath = */"bin\\x64",
|
||||
/*.expectedBackend = */MMBackend_TF2,
|
||||
/*.is64Bit = */true
|
||||
};
|
||||
|
||||
GetCurrentDirectory(PLATFORM_MAX_PATH, currentDirectoryBuffer);
|
||||
|
||||
for (const auto& [gameName, gameAttributes] : games)
|
||||
{
|
||||
std::cout << "Checking " << gameName << std::endl;
|
||||
|
||||
if (gameAttributes.is64Bit && !g_64Bit)
|
||||
{
|
||||
std::cout << "Skipping in 32-bit build" << std::endl << std::endl;
|
||||
continue;
|
||||
}
|
||||
else if (!gameAttributes.is64Bit && g_64Bit)
|
||||
{
|
||||
std::cout << "Skipping in 64-bit build" << std::endl << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
sprintf(directoryBuffer, "%s\\%s\\%s\\", steamInstallationPath.c_str(), gameAttributes.gamePath, gameAttributes.binPath);
|
||||
SetCurrentDirectory(directoryBuffer);
|
||||
|
||||
// get the server library
|
||||
sprintf(directoryBuffer, "%s\\%s\\%s\\%s\\server.dll", steamInstallationPath.c_str(), gameAttributes.gamePath, gameAttributes.gameDirectory, gameAttributes.binPath);
|
||||
serverLib = mm_LoadLibrary(directoryBuffer, errorBuffer, 128);
|
||||
|
||||
if (serverLib == nullptr)
|
||||
{
|
||||
std::cout << "Error: mm_LoadLibrary server library " << errorBuffer << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the engine library
|
||||
sprintf(directoryBuffer, "%s\\%s\\%s\\engine.dll", steamInstallationPath.c_str(), gameAttributes.gamePath, gameAttributes.binPath);
|
||||
engineLib = mm_LoadLibrary(directoryBuffer, errorBuffer, 128);
|
||||
|
||||
if (engineLib == nullptr)
|
||||
{
|
||||
std::cout << "Error: mm_LoadLibrary engine library " << errorBuffer << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
serverQvi = (QueryValveInterface)mm_GetLibAddress(serverLib, "CreateInterface");
|
||||
|
||||
if (serverQvi == nullptr)
|
||||
{
|
||||
std::cout << "Error: Failed to find CreateInterface in server" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
engineQvi = (QueryValveInterface)mm_GetLibAddress(engineLib, "CreateInterface");
|
||||
|
||||
if (engineQvi == nullptr)
|
||||
{
|
||||
std::cout << "Error: Failed to find CreateInterface in engine" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
MetamodBackend actualBackend = mm_DetermineBackendS1(engineQvi, serverQvi, gameAttributes.gameDirectory);
|
||||
|
||||
if (actualBackend != gameAttributes.expectedBackend)
|
||||
{
|
||||
std::cout << "Got MetamodBackend " << actualBackend << " instead of expected " << gameAttributes.expectedBackend << std::endl << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Got MetamodBackend " << gameAttributes.expectedBackend << std::endl << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrentDirectory(currentDirectoryBuffer);
|
||||
|
||||
return true;
|
||||
}
|
0
loader/test/version.rc
Normal file
0
loader/test/version.rc
Normal file
@ -615,7 +615,7 @@ void *mm_FindPattern(const void *libPtr, const char *pattern, size_t len)
|
||||
while (ptr < end)
|
||||
{
|
||||
found = true;
|
||||
for (register size_t i = 0; i < len; i++)
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user