#include "TestEngineWnd.h" #include "win32/Rect.h" #include #include #include #include #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(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(itOutput->GetInputId()) + _T("_"); sCaption += lexical_cast(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(Instruction.sName); sCaption += _T("\t") + lexical_cast(nSuccess); sCaption += _T("\t") + lexical_cast(nFailed); sCaption += _T("\t") + lexical_cast(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(Instruction.sName) + _T("': \r\n\r\n") + string_cast(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(&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(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(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(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(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(itValue->GetString()) + _T("\r\n"); } sText += _T("\r\n") + algorithm::trim_copy(string_cast(pInstance->GetSource())) + _T("\r\n\r\n"); for(CMipsTestEngine::CValueSet::ValueIterator itValue(pOutput->GetValuesBegin()); itValue != pOutput->GetValuesEnd(); itValue++) { sText += string_cast(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(Exception.what())).c_str()); } } }