Automated testing

This commit is contained in:
Souryo 2014-06-22 08:38:42 -04:00
parent d2b074296d
commit 7e2ad19da3
8 changed files with 107 additions and 99 deletions

View File

@ -6,6 +6,8 @@ uint32_t Console::Flags = 0;
Console::Console(wstring filename)
{
_romFilename = filename;
_mapper = MapperFactory::InitializeFromFile(filename);
_memoryManager.reset(new MemoryManager(_mapper->GetHeader()));
_cpu.reset(new CPU(_memoryManager.get()));
@ -87,105 +89,47 @@ void Console::Run()
}
}
void Console::RunTest(bool callback(Console*))
bool Console::RunTest(uint8_t *expectedResult)
{
Timer timer;
uint32_t lastFrameCount = 0;
uint8_t maxWait = 30;
while(true) {
if(callback(this)) {
break;
}
_cpu->Exec();
_ppu->Exec();
if(timer.GetElapsedMS() > 2000) {
uint32_t frameCount = _ppu->GetFrameCount();
std::cout << ((frameCount - lastFrameCount) / (timer.GetElapsedMS() / 1000)) << std::endl;
if(timer.GetElapsedMS() > 100) {
if(memcmp(_ppu->GetFrameBuffer(), expectedResult, 256 * 240 * 4)) {
return true;
}
timer.Reset();
lastFrameCount = frameCount;
maxWait--;
if(maxWait == 0) {
return false;
}
}
}
return false;
}
void Console::Load(wstring filename)
void Console::SaveTestResult()
{
(new Console(filename))->Run();
}
wstring filename = _romFilename + L".trt";
ofstream testResultFile(filename, ios::out | ios::binary);
void Console::RunTests()
{
//(new Console("TestSuite/mario.nes"))->Run();
/*
if(!testResultFile) {
throw std::exception("File could not be opened");
}
vector<wstring> testROMs {
//"Bomberman",
L"IceClimber",
//"Excitebike",
"dk",
//"mario",
"01-basics",
"02-implied",
"03-immediate",
"04-zero_page",
"05-zp_xy",
"06-absolute",
"07-abs_xy",
"08-ind_x",
"09-ind_y",
"10-branches",
"11-stack",
"12-jmp_jsr",
"13-rts",
"14-rti",
"15-brk",
"16-special"
};
uint8_t* buffer = new uint8_t[256 * 240 * 4];
memcpy(buffer, _ppu->GetFrameBuffer(), 256 * 240 * 4);
for(wstring testROM : testROMs) {
Console *console = new Console(wstring(L"TestSuite/") + testROM + L".nes");
if(testROM == L"nestest") {
console->RunTest([] (Console *console) {
State state = console->_cpu->GetState();
std::cout << std::hex << std::uppercase <<
"A:" << std::setfill('0') << std::setw(2) << (short)state.A <<
" X:" << std::setfill('0') << std::setw(2) << (short)state.X <<
" Y:" << std::setfill('0') << std::setw(2) << (short)state.Y <<
" S:" << std::setfill('0') << std::setw(2) << (short)state.SP <<
" P:........ $" <<
std::setfill('0') << std::setw(4) << (short)state.PC <<std::endl;
return false;
});
} else {
console->RunTest([] (Console *console) {
//static std::ofstream output("test.log", ios::out | ios::binary);
static bool testStarted = false;
uint8_t testStatus = console->_memoryManager->Read(0x6000);
State state = console->_cpu->GetState();
/*output << std::hex << std::uppercase <<
"A:" << std::setfill('0') << std::setw(2) << (short)state.A <<
" X:" << std::setfill('0') << std::setw(2) << (short)state.X <<
" Y:" << std::setfill('0') << std::setw(2) << (short)state.Y <<
" S:" << std::setfill('0') << std::setw(2) << (short)state.SP <<
" P:........ $" <<
std::setfill('0') << std::setw(4) << (short)state.PC <<std::endl;*/
/*
if(testStatus == 0x81) {
//need reset
std::cout << "reset needed";
} else if(testStatus == 0x80) {
testStarted = true;
} else if(testStatus < 0x80 && testStarted) {
char *result = console->_memoryManager->GetTestResult();
std::cout << result;
delete[] result;
testStarted = false;
return true;
}
return false;
});
}
delete console;
}*/
testResultFile.write((char *)buffer, 256 * 240 * 4);
testResultFile.close();
delete[] buffer;
}

View File

@ -23,6 +23,8 @@ class Console
unique_ptr<ControlManager> _controlManager;
unique_ptr<MemoryManager> _memoryManager;
wstring _romFilename;
bool _stop = false;
public:
@ -30,13 +32,12 @@ class Console
~Console();
void Run();
void Stop();
void RunTest(bool callback(Console*));
void Reset();
bool RunTest(uint8_t* expectedResult);
void SaveTestResult();
static bool CheckFlag(int flag);
static void SetFlags(int flags);
static void ClearFlags(int flags);
static void RunTests();
static void Load(wstring filename);
};

View File

@ -176,6 +176,11 @@ class PPU : public IMemoryHandler
PPU::VideoDevice = videoDevice;
}
uint8_t* GetFrameBuffer()
{
return _outputBuffer;
}
uint32_t GetFrameCount()
{
return _frameCount;

View File

@ -32,6 +32,7 @@ using std::shared_ptr;
using std::unique_ptr;
using std::ios;
using std::ifstream;
using std::ofstream;
using std::wstring;
using std::exception;
using std::atomic;

Binary file not shown.

View File

@ -204,6 +204,58 @@ namespace NES
}
}
void MainWindow::SaveTestResult()
{
if(_console) {
_console->SaveTestResult();
}
}
vector<wstring> MainWindow::GetFilesInFolder(wstring folderMask)
{
HANDLE hFind;
WIN32_FIND_DATA data;
vector<wstring> files;
hFind = FindFirstFile(folderMask.c_str(), &data);
if(hFind != INVALID_HANDLE_VALUE) {
do {
files.push_back(data.cFileName);
} while(FindNextFile(hFind, &data));
FindClose(hFind);
}
return files;
}
void MainWindow::RunTests()
{
Stop();
for(wstring testROM : GetFilesInFolder(L"TestSuite/*.nes")) {
ifstream testResult(L"TestSuite/" + testROM + L".trt", ios::in | ios::binary);
if(testResult) {
uint8_t* expectedResult = new uint8_t[256 * 240 * 4];
Console *console = new Console(L"TestSuite/" + testROM);
std::wcout << testROM << ": ";
if(console->RunTest(expectedResult)) {
std::cout << "Passed";
} else {
std::cout << "FAILED";
}
std::cout << std::endl;
testResult.close();
delete[] expectedResult;
} else {
std::wcout << testROM << ": [NO KNOWN RESULT]" << std::endl;
}
}
}
LRESULT CALLBACK MainWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static MainWindow *mainWindow = MainWindow::GetInstance();
@ -217,19 +269,22 @@ namespace NES
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDM_FILE_OPEN:
case ID_FILE_OPEN:
mainWindow->OpenROM();
break;
case IDM_FILE_RUNTESTS:
case ID_TESTS_RUNTESTS:
mainWindow->RunTests();
break;
case ID_TESTS_SAVETESTRESULT:
mainWindow->SaveTestResult();
break;
case ID_OPTIONS_LIMITFPS:
mainWindow->LimitFPS_Click();
break;
case IDM_ABOUT:
case ID_HELP_ABOUT:
DialogBox(nullptr, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
case ID_FILE_EXIT:
DestroyWindow(hWnd);
break;
default:

View File

@ -19,10 +19,12 @@ namespace NES {
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
static MainWindow* GetInstance()
{
return MainWindow::Instance;
}
static MainWindow* GetInstance() { return MainWindow::Instance; }
void SaveTestResult();
void RunTests();
vector<wstring> GetFilesInFolder(wstring folderMask);
void LimitFPS_Click();

Binary file not shown.