mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 13:47:57 +03:00

Some checks failed
Build macOS / build_macos (push) Has been cancelled
Build Android / build_android (apk) (push) Has been cancelled
Build Android / build_android (libretro) (push) Has been cancelled
Build Linux ARM32 / build_linux_arm32 (push) Has been cancelled
Build Linux ARM64 / build_linux_arm64 (push) Has been cancelled
Build Windows Psf / build_windows_psf (off, x86_64, Visual Studio 16 2019, installer64.nsi, x64) (push) Has been cancelled
Build Windows Psf / build_windows_psf (on, x86_64, Visual Studio 16 2019, installer64.nsi, x64) (push) Has been cancelled
Build Windows / build_windows (x86_32, Visual Studio 16 2019, installer32.nsi, win32_msvc2019, Win32) (push) Has been cancelled
Build Windows / build_windows (x86_64, Visual Studio 16 2019, installer64.nsi, win64_msvc2019_64, x64) (push) Has been cancelled
Check Format / run_clangformat (push) Has been cancelled
Build iOS / build_ios (push) Has been cancelled
Build JavaScript / build_js (push) Has been cancelled
Build Linux / build_linux (push) Has been cancelled
327 lines
8.4 KiB
C++
327 lines
8.4 KiB
C++
#include "PS2VM.h"
|
|
#include "DefaultAppConfig.h"
|
|
#include "filesystem_def.h"
|
|
#include "StdStream.h"
|
|
#include "StdStreamUtils.h"
|
|
#include "iop/IopBios.h"
|
|
#include "JUnitTestReportWriter.h"
|
|
#include "gs/GSH_Null.h"
|
|
#ifdef _WIN32
|
|
#include "gs/GSH_OpenGLWin32/GSH_OpenGLWin32.h"
|
|
#include "gs/GSH_Direct3D9/GSH_Direct3D9.h"
|
|
#endif
|
|
|
|
#define GS_HANDLER_NAME_NULL "null"
|
|
#define GS_HANDLER_NAME_OGL "ogl"
|
|
#define GS_HANDLER_NAME_D3D9 "d3d9"
|
|
|
|
#define DEFAULT_GS_HANDLER_NAME GS_HANDLER_NAME_NULL
|
|
|
|
static std::set<std::string> g_validGsHandlersNames =
|
|
{
|
|
GS_HANDLER_NAME_NULL,
|
|
#ifdef _WIN32
|
|
GS_HANDLER_NAME_OGL,
|
|
GS_HANDLER_NAME_D3D9,
|
|
#endif
|
|
};
|
|
|
|
#ifdef _WIN32
|
|
|
|
class CTestWindow : public Framework::Win32::CWindow, public CSingleton<CTestWindow>
|
|
{
|
|
public:
|
|
CTestWindow()
|
|
{
|
|
Create(0, Framework::Win32::CDefaultWndClass::GetName(), _T(""), WS_OVERLAPPED, Framework::Win32::CRect(0, 0, 100, 100), NULL, NULL);
|
|
SetClassPtr();
|
|
}
|
|
};
|
|
|
|
#endif
|
|
|
|
CGSHandler::FactoryFunction GetGsHandlerFactoryFunction(const std::string& gsHandlerName)
|
|
{
|
|
if(gsHandlerName == GS_HANDLER_NAME_NULL)
|
|
{
|
|
return CGSH_Null::GetFactoryFunction();
|
|
}
|
|
#ifdef _WIN32
|
|
else if(gsHandlerName == GS_HANDLER_NAME_OGL)
|
|
{
|
|
return CGSH_OpenGLWin32::GetFactoryFunction(&CTestWindow::GetInstance());
|
|
}
|
|
else if(gsHandlerName == GS_HANDLER_NAME_D3D9)
|
|
{
|
|
return CGSH_Direct3D9::GetFactoryFunction(&CTestWindow::GetInstance());
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
throw std::runtime_error("Unknown GS handler name.");
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> ReadLines(Framework::CStream& inputStream)
|
|
{
|
|
std::vector<std::string> lines;
|
|
lines.push_back(inputStream.ReadLine());
|
|
while(!inputStream.IsEOF())
|
|
{
|
|
lines.push_back(inputStream.ReadLine());
|
|
}
|
|
return lines;
|
|
}
|
|
|
|
TESTRESULT GetTestResult(const fs::path& testFilePath)
|
|
{
|
|
TESTRESULT result;
|
|
result.succeeded = false;
|
|
try
|
|
{
|
|
auto resultFilePath = testFilePath;
|
|
resultFilePath.replace_extension(".result");
|
|
auto expectedFilePath = testFilePath;
|
|
expectedFilePath.replace_extension(".expected");
|
|
auto resultStream = Framework::CreateInputStdStream(resultFilePath.string());
|
|
auto expectedStream = Framework::CreateInputStdStream(expectedFilePath.string());
|
|
|
|
auto resultLines = ReadLines(resultStream);
|
|
auto expectedLines = ReadLines(expectedStream);
|
|
|
|
if(resultLines.size() != expectedLines.size()) return result;
|
|
|
|
for(unsigned int i = 0; i < resultLines.size(); i++)
|
|
{
|
|
if(resultLines[i] != expectedLines[i])
|
|
{
|
|
LINEDIFF lineDiff;
|
|
lineDiff.expected = expectedLines[i];
|
|
lineDiff.result = resultLines[i];
|
|
result.lineDiffs.push_back(lineDiff);
|
|
}
|
|
}
|
|
|
|
result.succeeded = result.lineDiffs.empty();
|
|
return result;
|
|
}
|
|
catch(...)
|
|
{
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void ExecuteEeTest(const fs::path& testFilePath, const std::string& gsHandlerName)
|
|
{
|
|
auto resultFilePath = testFilePath;
|
|
resultFilePath.replace_extension(".result");
|
|
auto resultStream = new Framework::CStdStream(resultFilePath.string().c_str(), "wb");
|
|
|
|
bool executionOver = false;
|
|
|
|
//Setup virtual machine
|
|
CPS2VM virtualMachine;
|
|
virtualMachine.Initialize();
|
|
virtualMachine.CreateGSHandler(GetGsHandlerFactoryFunction(gsHandlerName));
|
|
auto connection = virtualMachine.m_ee->m_os->OnRequestExit.Connect(
|
|
[&executionOver]() {
|
|
executionOver = true;
|
|
});
|
|
virtualMachine.m_ee->m_os->BootFromFile(testFilePath);
|
|
{
|
|
auto iopOs = dynamic_cast<CIopBios*>(virtualMachine.m_iop->m_bios.get());
|
|
iopOs->GetIoman()->SetFileStream(Iop::CIoman::FID_STDOUT, resultStream);
|
|
}
|
|
virtualMachine.Resume();
|
|
|
|
while(!executionOver)
|
|
{
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
}
|
|
|
|
virtualMachine.Pause();
|
|
virtualMachine.DestroyGSHandler();
|
|
virtualMachine.Destroy();
|
|
}
|
|
|
|
void ExecuteIopTest(const fs::path& testFilePath)
|
|
{
|
|
//Read in the module data
|
|
std::vector<uint8> moduleData;
|
|
{
|
|
auto moduleStream = Framework::CreateInputStdStream(testFilePath.native());
|
|
auto length = moduleStream.GetLength();
|
|
moduleData.resize(length);
|
|
moduleStream.Read(moduleData.data(), length);
|
|
}
|
|
|
|
auto resultFilePath = testFilePath;
|
|
resultFilePath.replace_extension(".result");
|
|
auto resultStream = new Framework::CStdStream(resultFilePath.string().c_str(), "wb");
|
|
|
|
bool executionOver = false;
|
|
CIopBios::ModuleStartedEvent::Connection connection;
|
|
//Setup virtual machine
|
|
CPS2VM virtualMachine;
|
|
virtualMachine.Initialize();
|
|
virtualMachine.CreateGSHandler(CGSH_Null::GetFactoryFunction());
|
|
{
|
|
auto iopOs = dynamic_cast<CIopBios*>(virtualMachine.m_iop->m_bios.get());
|
|
int32 rootModuleId = iopOs->LoadModuleFromHost(moduleData.data());
|
|
connection = iopOs->OnModuleStarted.Connect(
|
|
[&executionOver, rootModuleId](uint32 moduleId) {
|
|
if(rootModuleId == moduleId)
|
|
{
|
|
executionOver = true;
|
|
}
|
|
});
|
|
iopOs->StartModule(CIopBios::MODULESTARTREQUEST_SOURCE::REMOTE, rootModuleId, "", nullptr, 0);
|
|
iopOs->GetIoman()->SetFileStream(Iop::CIoman::FID_STDOUT, resultStream);
|
|
}
|
|
virtualMachine.Resume();
|
|
|
|
while(!executionOver)
|
|
{
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
}
|
|
|
|
virtualMachine.Pause();
|
|
virtualMachine.Destroy();
|
|
}
|
|
|
|
void ScanAndExecuteTests(const fs::path& testDirPath, const TestReportWriterPtr& testReportWriter, const std::string& gsHandlerName)
|
|
{
|
|
fs::directory_iterator endIterator;
|
|
for(auto testPathIterator = fs::directory_iterator(testDirPath);
|
|
testPathIterator != endIterator; testPathIterator++)
|
|
{
|
|
auto testPath = testPathIterator->path();
|
|
if(fs::is_directory(testPath))
|
|
{
|
|
ScanAndExecuteTests(testPath, testReportWriter, gsHandlerName);
|
|
continue;
|
|
}
|
|
if(testPath.extension() == ".elf")
|
|
{
|
|
printf("Testing '%s': ", testPath.string().c_str());
|
|
ExecuteEeTest(testPath, gsHandlerName);
|
|
auto result = GetTestResult(testPath);
|
|
printf("%s.\r\n", result.succeeded ? "SUCCEEDED" : "FAILED");
|
|
if(testReportWriter)
|
|
{
|
|
testReportWriter->ReportTestEntry(testPath.string(), result);
|
|
}
|
|
}
|
|
else if(testPath.extension() == ".irx")
|
|
{
|
|
printf("Testing '%s': ", testPath.string().c_str());
|
|
ExecuteIopTest(testPath);
|
|
auto result = GetTestResult(testPath);
|
|
printf("%s.\r\n", result.succeeded ? "SUCCEEDED" : "FAILED");
|
|
if(testReportWriter)
|
|
{
|
|
testReportWriter->ReportTestEntry(testPath.string(), result);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, const char** argv)
|
|
{
|
|
if(argc < 2)
|
|
{
|
|
auto validGsHandlerNamesString =
|
|
[]() {
|
|
std::string result;
|
|
for(auto nameIterator = g_validGsHandlersNames.begin();
|
|
nameIterator != g_validGsHandlersNames.end(); ++nameIterator)
|
|
{
|
|
if(nameIterator != g_validGsHandlersNames.begin())
|
|
{
|
|
result += "|";
|
|
}
|
|
result += *nameIterator;
|
|
}
|
|
return result;
|
|
}();
|
|
|
|
printf("Usage: AutoTest [options] testDir\r\n");
|
|
printf("Options: \r\n");
|
|
printf("\t --junitreport <path>\t Writes JUnit format report at <path>.\r\n");
|
|
printf("\t --gshandler <%s>\tSelects which GS handler to instantiate (default is '%s').\r\n",
|
|
validGsHandlerNamesString.c_str(), DEFAULT_GS_HANDLER_NAME);
|
|
return -1;
|
|
}
|
|
|
|
TestReportWriterPtr testReportWriter;
|
|
fs::path autoTestRoot;
|
|
fs::path reportPath;
|
|
std::string gsHandlerName = DEFAULT_GS_HANDLER_NAME;
|
|
assert(g_validGsHandlersNames.find(gsHandlerName) != std::end(g_validGsHandlersNames));
|
|
|
|
for(int i = 1; i < argc; i++)
|
|
{
|
|
if(!strcmp(argv[i], "--junitreport"))
|
|
{
|
|
if((i + 1) >= argc)
|
|
{
|
|
printf("Error: Path must be specified for --junitreport option.\r\n");
|
|
return -1;
|
|
}
|
|
testReportWriter = std::make_shared<CJUnitTestReportWriter>();
|
|
reportPath = fs::path(argv[i + 1]);
|
|
i++;
|
|
}
|
|
else if(!strcmp(argv[i], "--gshandler"))
|
|
{
|
|
if((i + 1) >= argc)
|
|
{
|
|
printf("Error: GS handler name must be specified for --gshandler option.\r\n");
|
|
return -1;
|
|
}
|
|
gsHandlerName = argv[i + 1];
|
|
if(g_validGsHandlersNames.find(gsHandlerName) == std::end(g_validGsHandlersNames))
|
|
{
|
|
printf("Error: Invalid GS handler name '%s'.\r\n", gsHandlerName.c_str());
|
|
return -1;
|
|
}
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
autoTestRoot = argv[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(autoTestRoot.empty())
|
|
{
|
|
printf("Error: No test directory specified.\r\n");
|
|
return -1;
|
|
}
|
|
|
|
try
|
|
{
|
|
ScanAndExecuteTests(autoTestRoot, testReportWriter, gsHandlerName);
|
|
}
|
|
catch(const std::exception& exception)
|
|
{
|
|
printf("Error: Failed to execute tests: %s\r\n", exception.what());
|
|
return -1;
|
|
}
|
|
|
|
if(testReportWriter)
|
|
{
|
|
try
|
|
{
|
|
testReportWriter->Write(reportPath);
|
|
}
|
|
catch(const std::exception& exception)
|
|
{
|
|
printf("Error: Failed to write test report: %s\r\n", exception.what());
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|