Factor out program loading to separate object in tests
MODIFY
src/edittab.cpp
src/edittab.cpp
@@ -199,6 +199,12 @@ void EditTab::updateProgramViewerHighlighting() {
}
}
+Assembler::Errors* EditTab::errors() {
+ if (m_sourceErrors->empty())
+ return nullptr;
+ return m_sourceErrors.get();
+}
+
void EditTab::sourceTypeChanged() {
if (!m_editorEnabled) {
// Do nothing; editor is currently disabled so we should not care about updating our source type being the code
@@ -339,9 +345,13 @@ bool EditTab::loadFlatBinaryFile(Program& program, QFile& file, unsigned long en
return true;
}
-bool EditTab::loadSourceFile(Program&, QFile& file) {
+void EditTab::loadSourceText(const QString& text) {
enableEditor();
- setSourceText(file.readAll());
+ setSourceText(text);
+}
+
+bool EditTab::loadSourceFile(Program&, QFile& file) {
+ loadSourceText(file.readAll());
return true;
}

MODIFY
src/edittab.h
src/edittab.h
@@ -35,6 +35,9 @@ public:
const QByteArray* getBinaryData();
void loadFile(const LoadFileParams&);
+ void loadSourceText(const QString& text);
+ Assembler::Errors* errors();
+
/**
* @brief loadExternalFile
* sets the current source type to whatever is specified by @p params and calls loadFile(@p params);

MODIFY
test/CMakeLists.txt
test/CMakeLists.txt
@@ -13,7 +13,7 @@ add_definitions(-DRISCV32_C_TEST_DIR="${RISCV32_C_TEST_DIR}")
add_definitions(-DRISCV64_C_TEST_DIR="${RISCV64_C_TEST_DIR}")
macro(create_qtest name)
- add_executable(${name} ${name}.cpp)
+ add_executable(${name} ${name}.cpp programloader.h)
add_test(${name} ${name})
target_include_directories (${name} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${name} Qt5::Core Qt5::Widgets Qt5::Test)
@@ -24,3 +24,4 @@ create_qtest(tst_riscv)
create_qtest(tst_assembler)
create_qtest(tst_expreval)
create_qtest(tst_cosimulate)
+create_qtest(tst_reverse)

ADD
test/programloader.h
+#pragma once
+
+#include <QObject>
+#include <QTest>
+
+#include "edittab.h"
+#include "processorhandler.h"
+#include "processorregistry.h"
+
+#include <optional>
+
+namespace Ripes {
+
+/// Utility class around a Ripes EditTab which helps in loading and assembling programs from tests.
+class ProgramLoader : public QObject {
+ Q_OBJECT
+
+public:
+ ProgramLoader() {
+ m_editTab = new EditTab(new QToolBar(), nullptr);
+ connect(m_editTab, &EditTab::programChanged, ProcessorHandler::get(), &ProcessorHandler::loadProgram);
+ }
+
+ void loadTest(LoadFileParams params) {
+ currentTestType = params.type;
+ m_editTab->loadExternalFile(params);
+ processNewTest();
+ }
+
+ void loadTest(const QString& assembly) {
+ currentTestType = SourceType::Assembly;
+ m_editTab->loadSourceText(assembly);
+ processNewTest();
+ }
+
+private:
+ // Load a program through the edittab. This is not really suited for automatic testing, since the edit tab will
+ // trigger assembling after some timeout. To work around this, we allow for a bit of delay when loading the program.
+ void processNewTest() {
+ if (currentTestType == SourceType::Assembly)
+ m_editTab->sourceCodeChanged();
+
+ int timeouts = 5;
+ while (timeouts-- > 0 && !ProcessorHandler::getProgram()) {
+ QCoreApplication::processEvents(QEventLoop::AllEvents, 500);
+ }
+ if (!ProcessorHandler::getProgram()) {
+ QFAIL("No program was loaded!");
+ }
+ if (m_editTab->errors() && !m_editTab->errors()->empty())
+ QFAIL("Errors during assembly!");
+ }
+
+ SourceType currentTestType;
+ EditTab* m_editTab = nullptr;
+};
+
+} // namespace Ripes

MODIFY
test/tst_cosimulate.cpp
test/tst_cosimulate.cpp
#include "edittab.h"
#include "isa/rvisainfo_common.h"
+#include "programloader.h"
#include "ripessettings.h"
/**
@@ -72,7 +73,7 @@ private:
bool m_stop = false;
QString m_err;
LoadFileParams m_currentTest;
- EditTab* m_loader = nullptr;
+ ProgramLoader* m_loader;
std::map<QString, Trace> m_referenceTraces;
@@ -151,14 +152,6 @@ QString tst_Cosimulate::generateErrorReport(const RegisterChange& change, const
return err;
}
-void tst_Cosimulate::loadCurrentTest() {
- // Some manual work is required here since we are not instantiating the full application
- m_loader->loadExternalFile(m_currentTest);
- if (m_currentTest.type == SourceType::Assembly) {
- m_loader->sourceCodeChanged();
- }
-}
-
/**
* @brief tst_Cosimulate::executeSimulator
* Runs the currently loaded simulator on the currently loaded program, generating a register trace while doing so.
@@ -166,16 +159,7 @@ void tst_Cosimulate::loadCurrentTest() {
* discrepancy is detected.
*/
void tst_Cosimulate::executeSimulator(Trace& trace, const Trace* refTrace) {
- // Load a program through the edittab. This is not really suited for automatic testing, since the edit tab will
- // trigger assembling after some timeout. To work around this, we allow for a bit of delay when loading the program.
- loadCurrentTest();
- int timeouts = 5;
- while (timeouts-- > 0 && !ProcessorHandler::getProgram()) {
- QCoreApplication::processEvents(QEventLoop::AllEvents, 500);
- }
- if (!ProcessorHandler::getProgram()) {
- QFAIL("No program was loaded!");
- }
+ m_loader->loadTest(m_currentTest);
// Override the ProcessorHandler's ECALL handling. In doing so, we can hook into when the EXIT syscall was executed,
// to verify whether the correct test value was reached.
@@ -265,9 +249,7 @@ const Trace& tst_Cosimulate::generateReferenceTrace(const QStringList& extension
* once in Ripes, due to the static nature of the ProcessorHandler.
*/
void tst_Cosimulate::cosimulate(const ProcessorID& id, const QStringList& extensions) {
- m_loader = new EditTab(new QToolBar(), nullptr);
- connect(m_loader, &EditTab::programChanged, ProcessorHandler::get(), &ProcessorHandler::loadProgram);
-
+ m_loader = new ProgramLoader();
for (const auto& test : s_testFiles) {
m_currentTest = test;
std::cout << test.filepath.toStdString() << std::endl;

Factor out program loading to separate object in tests