mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-29 14:07:58 +03:00
377 lines
13 KiB
C++
377 lines
13 KiB
C++
#include "TestEngineWnd.h"
|
|
#include "win32/Rect.h"
|
|
#include <boost/filesystem/operations.hpp>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/bind.hpp>
|
|
#include <boost/algorithm/string.hpp>
|
|
#include "string_cast.h"
|
|
#include "../PS2VM.h"
|
|
|
|
#define CLSNAME _T("TestEngineWnd")
|
|
|
|
using namespace Framework;
|
|
using namespace boost;
|
|
using namespace std;
|
|
|
|
CTestEngineWnd::CTestEngineWnd(HWND hParent) :
|
|
m_pInstructionList(NULL),
|
|
m_pTestAllButton(NULL)
|
|
{
|
|
if(!DoesWindowClassExist(CLSNAME))
|
|
{
|
|
WNDCLASSEX wc;
|
|
memset(&wc, 0, sizeof(WNDCLASSEX));
|
|
wc.cbSize = sizeof(WNDCLASSEX);
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
|
|
wc.hInstance = GetModuleHandle(NULL);
|
|
wc.lpszClassName = CLSNAME;
|
|
wc.lpfnWndProc = CWindow::WndProc;
|
|
RegisterClassEx(&wc);
|
|
}
|
|
|
|
Create(NULL, CLSNAME, _T("Instruction Test Console"), WS_CLIPCHILDREN | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_CHILD | WS_MAXIMIZEBOX, Win32::CRect(0, 0, 500, 300), hParent, NULL);
|
|
SetClassPtr();
|
|
|
|
m_pInstructionList = new Win32::CColumnTreeView(m_hWnd, Win32::CRect(0, 0, 1, 1), TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_FULLROWSELECT);
|
|
m_pInstructionList->GetHeader()->InsertItem(_T("Instruction/Test case"), 100);
|
|
m_pInstructionList->GetHeader()->InsertItem(_T("Succeded"), 100);
|
|
m_pInstructionList->GetHeader()->InsertItem(_T("Failed"), 100);
|
|
m_pInstructionList->GetHeader()->InsertItem(_T("Error"), 100);
|
|
|
|
m_pTestAllButton = new Win32::CButton(_T("Test All"), m_hWnd, Win32::CRect(0, 0, 1, 1));
|
|
m_pDescriptionEdit = new Win32::CEdit(m_hWnd, Win32::CRect(0, 0, 1, 1), NULL, ES_READONLY | ES_MULTILINE | WS_VSCROLL);
|
|
|
|
m_Layout.InsertObject(new Win32::CLayoutWindow(1, 1, 1, 1, m_pInstructionList));
|
|
m_Layout.InsertObject(new Win32::CLayoutWindow(1, 1, 1, 1, m_pDescriptionEdit));
|
|
|
|
{
|
|
CHorizontalLayout* pTempLayout(new CHorizontalLayout());
|
|
pTempLayout->InsertObject(Win32::CLayoutWindow::CreateButtonBehavior(130, 23, m_pTestAllButton));
|
|
pTempLayout->InsertObject(new CLayoutStretch());
|
|
m_Layout.InsertObject(pTempLayout);
|
|
}
|
|
|
|
RefreshInstructionMap();
|
|
RefreshInstructionList();
|
|
RefreshLayout();
|
|
}
|
|
|
|
CTestEngineWnd::~CTestEngineWnd()
|
|
{
|
|
|
|
}
|
|
|
|
long CTestEngineWnd::OnSize(unsigned int nX, unsigned int nY, unsigned int nType)
|
|
{
|
|
RefreshLayout();
|
|
return TRUE;
|
|
}
|
|
|
|
long CTestEngineWnd::OnCommand(unsigned short nCmd, unsigned short nId, HWND hWnd)
|
|
{
|
|
if((m_pTestAllButton != NULL) && (m_pTestAllButton->m_hWnd == hWnd))
|
|
{
|
|
TestAll();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
long CTestEngineWnd::OnNotify(WPARAM wParam, NMHDR* pHdr)
|
|
{
|
|
if((m_pInstructionList != NULL) && (pHdr->hwndFrom == m_pInstructionList->m_hWnd))
|
|
{
|
|
Win32::CColumnTreeView::MESSAGE* pMsg(
|
|
static_cast<Win32::CColumnTreeView::MESSAGE*>(pHdr));
|
|
|
|
switch(pMsg->code)
|
|
{
|
|
case NM_DBLCLK:
|
|
ProcessListEvent(bind(&CTestEngineWnd::OnItemDblClick, this, _1, _2));
|
|
break;
|
|
case TVN_SELCHANGED:
|
|
ProcessListEvent(bind(&CTestEngineWnd::OnListSelChange, this, _1, _2));
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void CTestEngineWnd::TestAll()
|
|
{
|
|
for(InstructionByIdMapType::iterator itInstruction(m_InstructionsById.begin());
|
|
itInstruction != m_InstructionsById.end(); itInstruction++)
|
|
{
|
|
Test(itInstruction->second);
|
|
}
|
|
}
|
|
|
|
void CTestEngineWnd::Test(INSTRUCTION& Instruction)
|
|
{
|
|
try
|
|
{
|
|
CMipsTestEngine Engine(("./tests/" + Instruction.sName + ".xml").c_str());
|
|
|
|
unsigned int nFailed, nSuccess, nError, nTotal;
|
|
|
|
nFailed = nSuccess = nError = nTotal = 0;
|
|
|
|
//Delete all existing nodes
|
|
m_pInstructionList->GetTreeView()->DeleteChildren(Instruction.nTreeItem);
|
|
|
|
for(CMipsTestEngine::OutputsType::iterator itOutput(Engine.GetOutputsBegin());
|
|
itOutput != Engine.GetOutputsEnd(); itOutput++)
|
|
{
|
|
bool nHasSucceeded, nHasFailed, nHasError;
|
|
|
|
nHasSucceeded = nHasFailed = nHasError = false;
|
|
|
|
nTotal++;
|
|
|
|
try
|
|
{
|
|
CMipsTestEngine::CValueSet* pInput(Engine.GetInput(itOutput->GetInputId()));
|
|
CMipsTestEngine::CInstance* pInstance(Engine.GetInstance(itOutput->GetInstanceId()));
|
|
|
|
if((pInput != NULL) && (pInstance != NULL))
|
|
{
|
|
unsigned int nProgramSize;
|
|
const unsigned int nBaseAddress = 0x00100000;
|
|
|
|
nProgramSize = AssembleTestCase(nBaseAddress, pInput, pInstance);
|
|
|
|
CPS2VM::m_EE.m_State.nDelayedJumpAddr = MIPS_INVALID_PC;
|
|
CPS2VM::m_EE.m_State.nPC = nBaseAddress;
|
|
CPS2VM::m_EE.Execute(nProgramSize);
|
|
|
|
if(!itOutput->Verify(CPS2VM::m_EE))
|
|
{
|
|
nHasFailed = true;
|
|
}
|
|
else
|
|
{
|
|
nHasSucceeded = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nHasError = true;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
nHasError = true;
|
|
}
|
|
|
|
if(nHasSucceeded) nSuccess++;
|
|
if(nHasFailed) nFailed++;
|
|
if(nHasError) nError++;
|
|
|
|
//Insert the item into the list
|
|
tstring sCaption;
|
|
sCaption = lexical_cast<tstring>(itOutput->GetInputId()) + _T("_");
|
|
sCaption += lexical_cast<tstring>(itOutput->GetInstanceId());
|
|
sCaption += tstring(_T("\t")) + (nHasSucceeded ? _T("X") : _T(""));
|
|
sCaption += tstring(_T("\t")) + (nHasFailed ? _T("X") : _T(""));
|
|
sCaption += tstring(_T("\t")) + (nHasError ? _T("X") : _T(""));
|
|
|
|
HTREEITEM nCaseTreeItem;
|
|
nCaseTreeItem = m_pInstructionList->GetTreeView()->InsertItem(Instruction.nTreeItem, sCaption.c_str());
|
|
Instruction.TestCases[nCaseTreeItem] = INSTRUCTION::TestCaseType(itOutput->GetInputId(), itOutput->GetInstanceId());
|
|
}
|
|
|
|
//Update the totals
|
|
tstring sCaption;
|
|
sCaption = string_cast<tstring>(Instruction.sName);
|
|
sCaption += _T("\t") + lexical_cast<tstring>(nSuccess);
|
|
sCaption += _T("\t") + lexical_cast<tstring>(nFailed);
|
|
sCaption += _T("\t") + lexical_cast<tstring>(nError);
|
|
|
|
m_pInstructionList->GetTreeView()->SetItemText(Instruction.nTreeItem, sCaption.c_str());
|
|
}
|
|
catch(const exception& Exception)
|
|
{
|
|
MessageBox(m_hWnd,
|
|
(_T("Error occured while parsing the test suite for instruction '") +
|
|
string_cast<tstring>(Instruction.sName) + _T("': \r\n\r\n") +
|
|
string_cast<tstring>(Exception.what())).c_str(),
|
|
NULL,
|
|
16);
|
|
}
|
|
|
|
m_pInstructionList->GetTreeView()->Redraw();
|
|
}
|
|
|
|
unsigned int CTestEngineWnd::AssembleTestCase(unsigned int nBaseAddress, CMipsTestEngine::CValueSet* pInput, CMipsTestEngine::CInstance* pInstance)
|
|
{
|
|
CMIPSAssembler Assembler(reinterpret_cast<uint32*>(&CPS2VM::m_pRAM[nBaseAddress]));
|
|
|
|
CPS2VM::m_EE.m_pExecMap->InvalidateBlocks();
|
|
|
|
pInput->AssembleLoad(Assembler);
|
|
Assembler.AssembleString(pInstance->GetSource());
|
|
|
|
return Assembler.GetProgramSize();
|
|
}
|
|
|
|
void CTestEngineWnd::RefreshLayout()
|
|
{
|
|
RECT rc(GetClientRect());
|
|
|
|
SetRect(&rc, rc.left + 10, rc.top + 10, rc.right - 10, rc.bottom - 10);
|
|
|
|
m_Layout.SetRect(rc.left, rc.top, rc.right, rc.bottom);
|
|
m_Layout.RefreshGeometry();
|
|
|
|
Redraw();
|
|
|
|
m_pInstructionList->GetHeader()->SetItemWidth(0, 0.5);
|
|
|
|
m_pInstructionList->GetHeader()->SetItemWidth(1, 0.5 * 0.33);
|
|
m_pInstructionList->GetHeader()->SetItemWidth(2, 0.5 * 0.33);
|
|
m_pInstructionList->GetHeader()->SetItemWidth(3, 0.5 * 0.33);
|
|
}
|
|
|
|
void CTestEngineWnd::RefreshInstructionMap()
|
|
{
|
|
filesystem::path TestsPath("./tests");
|
|
|
|
filesystem::directory_iterator itEnd;
|
|
for(filesystem::directory_iterator itFile(TestsPath);
|
|
itFile != itEnd; itFile++)
|
|
{
|
|
if(filesystem::is_directory(*itFile)) continue;
|
|
|
|
string sPath(itFile->leaf().c_str());
|
|
string sExtension(sPath.end() - 3, sPath.end());
|
|
|
|
if(_stricmp(sExtension.c_str(), "xml")) continue;
|
|
|
|
INSTRUCTION Instruction;
|
|
Instruction.sName = string(sPath.begin(), sPath.end() - 4);
|
|
Instruction.nTreeItem = NULL;
|
|
|
|
m_InstructionsById[static_cast<unsigned int>(m_InstructionsById.size())] = Instruction;
|
|
}
|
|
}
|
|
|
|
void CTestEngineWnd::RefreshInstructionList()
|
|
{
|
|
Win32::CTreeView* pTreeView(m_pInstructionList->GetTreeView());
|
|
|
|
for(InstructionByIdMapType::iterator itInstruction(m_InstructionsById.begin());
|
|
itInstruction != m_InstructionsById.end(); itInstruction++)
|
|
{
|
|
tstring sCaption;
|
|
INSTRUCTION& Instruction(itInstruction->second);
|
|
sCaption = string_cast<tstring>(Instruction.sName) + _T("\t?\t?\t?");
|
|
Instruction.nTreeItem = pTreeView->InsertItem(TVI_ROOT, sCaption.c_str());
|
|
pTreeView->SetItemParam(Instruction.nTreeItem, itInstruction->first);
|
|
}
|
|
}
|
|
|
|
void CTestEngineWnd::ProcessListEvent(ListMessageHandlerType Handler)
|
|
{
|
|
Win32::CTreeView* pTreeView(m_pInstructionList->GetTreeView());
|
|
HTREEITEM nItem(pTreeView->GetSelection());
|
|
|
|
if(nItem == NULL) return;
|
|
|
|
HTREEITEM nParent(pTreeView->GetItemParent(nItem));
|
|
|
|
if(nParent != NULL)
|
|
{
|
|
//This is a test case
|
|
unsigned int nInstructionId(pTreeView->GetItemParam<unsigned int>(nParent));
|
|
InstructionByIdMapType::iterator itInstruction(m_InstructionsById.find(nInstructionId));
|
|
|
|
if(itInstruction == m_InstructionsById.end()) return;
|
|
|
|
const INSTRUCTION& Instruction(itInstruction->second);
|
|
INSTRUCTION::CaseListType::const_iterator itTestCase(Instruction.TestCases.find(nItem));
|
|
|
|
if(itTestCase == Instruction.TestCases.end()) return;
|
|
|
|
const INSTRUCTION::TestCaseType& TestCase(itTestCase->second);
|
|
|
|
Handler(&Instruction, &TestCase);
|
|
}
|
|
else
|
|
{
|
|
//Instruction
|
|
}
|
|
}
|
|
|
|
void CTestEngineWnd::OnItemDblClick(const INSTRUCTION* pInstruction, const INSTRUCTION::TestCaseType* pTestCase)
|
|
{
|
|
if(pTestCase != NULL)
|
|
{
|
|
try
|
|
{
|
|
CMipsTestEngine Engine(("./tests/" + pInstruction->sName + ".xml").c_str());
|
|
CMipsTestEngine::CValueSet* pInput(Engine.GetInput(pTestCase->first));
|
|
CMipsTestEngine::CInstance* pInstance(Engine.GetInstance(pTestCase->second));
|
|
|
|
if((pInput != NULL) && (pInstance != NULL))
|
|
{
|
|
const unsigned int nBaseAddress = 0x00100000;
|
|
AssembleTestCase(nBaseAddress, pInput, pInstance);
|
|
CPS2VM::m_EE.m_State.nPC = nBaseAddress;
|
|
m_OnTestCaseLoad(nBaseAddress);
|
|
}
|
|
}
|
|
catch(const exception& Exception)
|
|
{
|
|
MessageBox(m_hWnd,
|
|
(_T("Error occured while trying to assemble the test case: \r\n\r\n") +
|
|
string_cast<tstring>(Exception.what())).c_str(),
|
|
NULL,
|
|
16);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Instruction
|
|
}
|
|
}
|
|
|
|
void CTestEngineWnd::OnListSelChange(const INSTRUCTION* pInstruction, const INSTRUCTION::TestCaseType* pTestCase)
|
|
{
|
|
if(pTestCase != NULL)
|
|
{
|
|
try
|
|
{
|
|
CMipsTestEngine Engine(("./tests/" + pInstruction->sName + ".xml").c_str());
|
|
CMipsTestEngine::CValueSet* pInput(Engine.GetInput(pTestCase->first));
|
|
CMipsTestEngine::CValueSet* pOutput(Engine.GetOutput(pTestCase->first, pTestCase->second));
|
|
CMipsTestEngine::CInstance* pInstance(Engine.GetInstance(pTestCase->second));
|
|
|
|
if((pInput != NULL) && (pInstance != NULL) && (pOutput != NULL))
|
|
{
|
|
tstring sText;
|
|
|
|
for(CMipsTestEngine::CValueSet::ValueIterator itValue(pInput->GetValuesBegin());
|
|
itValue != pInput->GetValuesEnd(); itValue++)
|
|
{
|
|
sText += string_cast<tstring>(itValue->GetString()) + _T("\r\n");
|
|
}
|
|
|
|
sText += _T("\r\n") + algorithm::trim_copy(string_cast<tstring>(pInstance->GetSource())) + _T("\r\n\r\n");
|
|
|
|
for(CMipsTestEngine::CValueSet::ValueIterator itValue(pOutput->GetValuesBegin());
|
|
itValue != pOutput->GetValuesEnd(); itValue++)
|
|
{
|
|
sText += string_cast<tstring>(itValue->GetString()) + _T("\r\n");
|
|
}
|
|
|
|
m_pDescriptionEdit->SetText(sText.c_str());
|
|
}
|
|
}
|
|
catch(const exception& Exception)
|
|
{
|
|
m_pDescriptionEdit->SetText(
|
|
(_T("Error occured while trying to assemble the test case: \r\n\r\n") +
|
|
string_cast<tstring>(Exception.what())).c_str());
|
|
}
|
|
}
|
|
}
|