[education/rkward] rkward: Add support for running autotests at the CPP level (in addition to the existing plugintests)
Thomas Friedrichsmeier
null at kde.org
Sat Jun 11 15:24:21 BST 2022
Git commit f6db47e97d57ff03fa0abb2e496443980dff9696 by Thomas Friedrichsmeier.
Committed on 09/06/2022 at 19:58.
Pushed by tfry into branch 'master'.
Add support for running autotests at the CPP level (in addition to the existing plugintests)
M +8 -4 rkward/CMakeLists.txt
A +18 -0 rkward/autotests/CMakeLists.txt
A +3 -0 rkward/autotests/README.txt
A +76 -0 rkward/autotests/core_test.cpp *
M +1 -1 rkward/main.cpp
M +3 -2 rkward/misc/rkcommonfunctions.cpp
M +3 -2 rkward/rbackend/rkfrontendtransmitter.cpp
M +1 -0 rkward/rbackend/rksessionvars.h
M +3 -1 rkward/rkward.cpp
M +2 -0 rkward/rkward.h
The files marked with a * at the end have a non valid license. Please read: https://community.kde.org/Policies/Licensing_Policy and use the headers which are listed at that page.
https://invent.kde.org/education/rkward/commit/f6db47e97d57ff03fa0abb2e496443980dff9696
diff --git a/rkward/CMakeLists.txt b/rkward/CMakeLists.txt
index c28a74ba..8026a97a 100644
--- a/rkward/CMakeLists.txt
+++ b/rkward/CMakeLists.txt
@@ -26,12 +26,14 @@ ADD_SUBDIRECTORY( core )
ADD_SUBDIRECTORY( icons )
ADD_SUBDIRECTORY( windows )
ADD_SUBDIRECTORY( syntax )
+IF(BUILD_TESTING)
+ ADD_SUBDIRECTORY(autotests)
+ENDIF(BUILD_TESTING)
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} )
SET(RKWard_Sources
rkward.cpp
- main.cpp
robjectviewer.cpp
rkconsole.cpp
)
@@ -45,11 +47,12 @@ LINK_DIRECTORIES(${R_SHAREDLIBDIR})
FILE(GLOB ICON_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/app-icon/*-apps-rkward.png")
# recent ECM versions will prefer the scalable version: prepend it to the icon source list (older versions generate a warning on the SVG, but so what):
ECM_ADD_APP_ICON(RKWard_Sources ICONS ${CMAKE_CURRENT_SOURCE_DIR}/icons/app-icon/sc-apps-rkward.svgz ${ICON_SRCS})
-ADD_EXECUTABLE(rkward ${RKWard_Sources})
+ADD_LIBRARY(rkward_lib STATIC ${RKWard_Sources}) # For auto-tests: pack everything except main in a dummy library
+TARGET_COMPILE_DEFINITIONS(rkward_lib PUBLIC -DR_EXECUTABLE="${R_EXECUTABLE}")
+ADD_EXECUTABLE(rkward main.cpp)
# NOTE: These definitions are needed for the startup procedure (main.cpp), only.
# We should switch with to target_compile_definitions once we require CMAKE 2.6+
-ADD_DEFINITIONS(-DR_EXECUTABLE="${R_EXECUTABLE}")
ADD_DEFINITIONS(-DINSTALL_PATH="${CMAKE_INSTALL_PREFIX}")
SET_TARGET_PROPERTIES(rkward PROPERTIES
MACOSX_BUNDLE_BUNDLE_NAME "RKWard")
@@ -63,7 +66,8 @@ IF(APPLE)
@ONLY)
ENDIF(APPLE)
-TARGET_LINK_LIBRARIES(rkward windows ${RKWARD_ADDLIBS} agents dialogs plugin settings dataeditor core scriptbackends rbackend misc KF5::WindowSystem Qt5::Widgets KF5::XmlGui)
+TARGET_LINK_LIBRARIES(rkward_lib windows ${RKWARD_ADDLIBS} agents dialogs plugin settings dataeditor core scriptbackends rbackend misc KF5::WindowSystem Qt5::Widgets KF5::XmlGui)
+TARGET_LINK_LIBRARIES(rkward rkward_lib)
IF(KF5Crash_FOUND)
TARGET_LINK_LIBRARIES(rkward KF5::Crash)
SET_SOURCE_FILES_PROPERTIES(main.cpp PROPERTIES COMPILE_DEFINITIONS WITH_KCRASH=1)
diff --git a/rkward/autotests/CMakeLists.txt b/rkward/autotests/CMakeLists.txt
new file mode 100644
index 00000000..11e8a3e1
--- /dev/null
+++ b/rkward/autotests/CMakeLists.txt
@@ -0,0 +1,18 @@
+include(ECMMarkAsTest)
+
+find_package(Qt5 5.9 QUIET REQUIRED Test)
+
+macro(rkward_executable_tests)
+ foreach(_testname ${ARGN})
+ add_executable(${_testname} ${_testname}.cpp)
+
+ target_link_libraries(${_testname} PRIVATE rkward_lib Qt5::Test)
+
+ add_test(NAME rkward-${_testname} COMMAND ${_testname})
+ ecm_mark_as_test(${_testname})
+ endforeach()
+endmacro()
+
+rkward_executable_tests(
+ core_test
+)
diff --git a/rkward/autotests/README.txt b/rkward/autotests/README.txt
new file mode 100644
index 00000000..b763e5dc
--- /dev/null
+++ b/rkward/autotests/README.txt
@@ -0,0 +1,3 @@
+Note: This directoy contains autotest running at the C++-level. Please do not overlook the separate plugintests!
+
+(The plugintests are much more extensive at the time of this writing, but cannot cover internals, well.)
diff --git a/rkward/autotests/core_test.cpp b/rkward/autotests/core_test.cpp
new file mode 100644
index 00000000..ada5f77f
--- /dev/null
+++ b/rkward/autotests/core_test.cpp
@@ -0,0 +1,76 @@
+#include <QObject>
+#include <QTest>
+#include <QApplication>
+
+#include <KAboutData>
+
+#include "../debug.h"
+#include "../rkward.h"
+#include "../agents/rkquitagent.h"
+#include "../rbackend/rksessionvars.h"
+#include "../rbackend/rkrinterface.h"
+
+void RKDebug (int, int, const char*, ...) {
+ // disabled for now
+}
+
+class RKWardCoreTest: public QObject {
+ Q_OBJECT
+
+ void runCommandWithTimeout(RCommand *command, RCommandChain* chain, std::function<void(RCommand*)> callback, int timeoutms = 1000) {
+ QString ccopy = command->command();
+ QElapsedTimer t;
+ t.start();
+ bool done = false;
+ bool *_done = &done;
+ connect(command->notifier(), &RCommandNotifier::commandFinished, this, [_done, callback](RCommand *command) { *_done = true; callback(command); });
+ RInterface::issueCommand(command, chain);
+ while (!done && t.elapsed() < timeoutms) {
+ qApp->processEvents();
+ }
+ if (!done) {
+ qDebug("Command timed out: %s", qPrintable(ccopy));
+ QFAIL("Command timed out");
+ }
+ }
+
+ QPointer<RKWardMainWindow> main_win;
+private slots:
+ void init() {
+ }
+ void initTestCase()
+ {
+ KAboutData::setApplicationData(KAboutData("rkward")); // needed for .rc files to load
+ RK_Debug::RK_Debug_Level = DL_WARNING;
+ qDebug(R_EXECUTABLE);
+ RKSessionVars::r_binary = R_EXECUTABLE;
+ main_win = new RKWardMainWindow();
+ main_win->testmode_suppress_dialogs = true;
+ while (!(RInterface::instance()->backendIsDead() || RInterface::instance()->backendIsIdle())) {
+ qApp->processEvents();
+ }
+ qDebug("Startup completed");
+ }
+
+ void getIntVector() {
+ auto c = new RCommand("c(1, 2, 3)", RCommand::GetIntVector);
+ runCommandWithTimeout(c, nullptr, [](RCommand *command) {
+ QCOMPARE(command->getDataType(), RData::IntVector);
+ QCOMPARE(command->getDataLength(), 3);
+ QCOMPARE(command->intVector().value(1), 2);
+ });
+ }
+
+ void cleanupTestCase()
+ {
+ // at least the backend should exit properly, to avoid creating emergency save files
+ RInterface::issueCommand(new RCommand(QString(), RCommand::QuitCommand));
+ while (!(RInterface::instance()->backendIsDead())) {
+ qApp->processEvents();
+ }
+ }
+};
+
+QTEST_MAIN(RKWardCoreTest)
+
+#include "core_test.moc"
diff --git a/rkward/main.cpp b/rkward/main.cpp
index fb6be476..cf788c07 100644
--- a/rkward/main.cpp
+++ b/rkward/main.cpp
@@ -93,7 +93,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
#include "version.h"
#ifndef R_EXECUTABLE
-# define R_EXECUTABLE ""
+#error config problem
#endif
#ifdef Q_OS_WIN
diff --git a/rkward/misc/rkcommonfunctions.cpp b/rkward/misc/rkcommonfunctions.cpp
index 04b26f85..d82ac627 100644
--- a/rkward/misc/rkcommonfunctions.cpp
+++ b/rkward/misc/rkcommonfunctions.cpp
@@ -166,9 +166,10 @@ namespace RKCommonFunctions {
static QString rkward_data_dir;
if (rkward_data_dir.isNull ()) {
QString inside_build_tree = QCoreApplication::applicationDirPath() + "/rkwardinstall/";
- if (QFileInfo(inside_build_tree).isReadable()) {
+ QString inside_build_tree2 = QCoreApplication::applicationDirPath() + "/../rkwardinstall/";
+ if (QFile::exists(inside_build_tree) || QFile::exists(inside_build_tree2)) {
RK_DEBUG(APP, DL_INFO, "Running from inside build tree");
- rkward_data_dir = inside_build_tree;
+ rkward_data_dir = QFile::exists(inside_build_tree) ? inside_build_tree : inside_build_tree2;
return rkward_data_dir;
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
diff --git a/rkward/rbackend/rkfrontendtransmitter.cpp b/rkward/rbackend/rkfrontendtransmitter.cpp
index bb7599d3..6e84042b 100644
--- a/rkward/rbackend/rkfrontendtransmitter.cpp
+++ b/rkward/rbackend/rkfrontendtransmitter.cpp
@@ -92,10 +92,11 @@ void RKFrontendTransmitter::run () {
QString backend_executable = findBackendAtPath (QCoreApplication::applicationDirPath ());
#ifdef Q_OS_MACOS
- if (backend_executable.isEmpty ()) backend_executable = findBackendAtPath (QCoreApplication::applicationDirPath () + "../Resources"); // an appropriate location in a standalone app-bundle
+ if (backend_executable.isEmpty ()) backend_executable = findBackendAtPath (QCoreApplication::applicationDirPath () + "/../Resources"); // an appropriate location in a standalone app-bundle
#endif
if (backend_executable.isEmpty ()) backend_executable = findBackendAtPath (QCoreApplication::applicationDirPath () + "/rbackend"); // for running directly from the build-dir
- if (backend_executable.isEmpty ()) backend_executable = findBackendAtPath (QCoreApplication::applicationDirPath () + "../lib/libexec");
+ if (backend_executable.isEmpty ()) backend_executable = findBackendAtPath (QCoreApplication::applicationDirPath () + "/../rbackend"); // for running directly from the build-test-dir
+ if (backend_executable.isEmpty ()) backend_executable = findBackendAtPath (QCoreApplication::applicationDirPath () + "/../lib/libexec");
#ifdef Q_OS_MACOS
if (backend_executable.isEmpty ()) backend_executable = findBackendAtPath (QCoreApplication::applicationDirPath () + "/../../../rbackend");
if (backend_executable.isEmpty ()) backend_executable = findBackendAtPath (QCoreApplication::applicationDirPath () + "/../Frameworks/libexec"); // For running from .dmg created by craft --package rkward
diff --git a/rkward/rbackend/rksessionvars.h b/rkward/rbackend/rksessionvars.h
index 56ec9580..ef5a0602 100644
--- a/rkward/rbackend/rksessionvars.h
+++ b/rkward/rbackend/rksessionvars.h
@@ -49,6 +49,7 @@ private:
static RKParsedVersion r_version;
static QString r_version_string;
friend int main(int, char**);
+friend class RKWardCoreTest;
static QString r_binary;
};
diff --git a/rkward/rkward.cpp b/rkward/rkward.cpp
index 951796c6..414b0561 100644
--- a/rkward/rkward.cpp
+++ b/rkward/rkward.cpp
@@ -112,6 +112,8 @@ RKWardMainWindow::RKWardMainWindow () : KParts::MainWindow ((QWidget *)0, (Qt::W
RK_TRACE (APP);
RK_ASSERT (rkward_mainwin == 0);
+ Q_INIT_RESOURCE(resources);
+ testmode_suppress_dialogs = false;
gui_rebuild_locked = true;
no_ask_save = true;
workspace_modified = false;
@@ -226,7 +228,7 @@ void RKWardMainWindow::doPostInit () {
gui_rebuild_locked = false;
show ();
- RKSetupWizard::doAutoCheck();
+ if (!testmode_suppress_dialogs) RKSetupWizard::doAutoCheck();
KMessageBox::enableMessage ("external_link_warning"); // can only be disabled per session
QUrl recover_url = RKRecoverDialog::checkRecoverCrashedWorkspace ();
diff --git a/rkward/rkward.h b/rkward/rkward.h
index 2d48c145..5554738e 100644
--- a/rkward/rkward.h
+++ b/rkward/rkward.h
@@ -187,6 +187,8 @@ private:
KatePluginIntegrationApp *katepluginintegration;
KXMLGUIClient *active_ui_buddy;
+friend class RKWardCoreTest;
+ bool testmode_suppress_dialogs;
};
#endif // RKWARD_H
More information about the rkward-tracker
mailing list