Simplify starting subCreator process even more

Use SUB_CREATOR_PROCESS macro for registering subprocess'
main() function.

Invoke registered subprocesses by a call to
invokeSubProcessIfRequired().

Substitute subTestCase env variables with TestCase subclasses.
This should make the code even more readable.

Amends bbb0270fb1

Change-Id: Id63b15841ea539f367dab4972a6ecbb298d277e7
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Jarek Kobus
2022-03-09 19:59:08 +01:00
parent 82108e949a
commit e66bd6ed90

View File

@@ -49,28 +49,37 @@
using namespace Utils; using namespace Utils;
#define SUB_CREATOR_PROCESS(var)\ using SubProcessMain = std::function<void ()>;
const char var[] = "TST_QTC_PROCESS_" QTC_ASSERT_STRINGIFY(var);\ static QMap<const char *, SubProcessMain> s_subProcesses = {};
static void var ## Main();
// Many tests in this file need to start a new subprocess with custom code. static void invokeSubProcessIfRequired()
// In order to simplify things we don't produce separate executables, but invoke {
// the same test process recursively and prior to the execution we set one of the for (auto it = s_subProcesses.constBegin(); it != s_subProcesses.constEnd(); ++it) {
// following environment variables: if (qEnvironmentVariableIsSet(it.key()))
it.value()();
}
}
SUB_CREATOR_PROCESS(subExitCode); static void registerSubProcess(const char *envVar, const SubProcessMain &main)
SUB_CREATOR_PROCESS(subRunBlockingStdOut); {
SUB_CREATOR_PROCESS(subLineCallback); s_subProcesses.insert(envVar, main);
SUB_CREATOR_PROCESS(subSimpleTest); }
SUB_CREATOR_PROCESS(subProcessChannelForwarding);
SUB_CREATOR_PROCESS(subSubProcessChannelForwarding);
SUB_CREATOR_PROCESS(subKillBlockingProcess);
// The variables above are meant to be different custom executables. Inside initTestCase() #define SUB_CREATOR_PROCESS(SubProcessClass)\
// we are detecting if one of these variables is set and invoke directly a respective custom class SubProcessClass\
// executable code, which always ends up with a call to exit(). In this case we need to stop {\
// the recursion, as from the test point of view we meant to execute only our custom code public:\
// without further execution of the test itself. SubProcessClass()\
{\
registerSubProcess(envVar(), &SubProcessClass::main);\
}\
static const char *envVar() { return m_envVar; }\
private:\
static void main();\
static constexpr char m_envVar[] = "TST_QTC_PROCESS_" QTC_ASSERT_STRINGIFY(SubProcessClass);\
};\
\
SubProcessClass m_ ## SubProcessClass
const char simpleTestData[] = "Test process successfully executed."; const char simpleTestData[] = "Test process successfully executed.";
const char forwardedOutputData[] = "This is the output message."; const char forwardedOutputData[] = "This is the output message.";
@@ -137,12 +146,6 @@ public:
TestProcess() { new TestProcessDeleter(this); } TestProcess() { new TestProcessDeleter(this); }
}; };
static void subSimpleTestMain()
{
std::cout << simpleTestData << std::endl;
exit(0);
}
class MacroMapExpander : public AbstractMacroExpander { class MacroMapExpander : public AbstractMacroExpander {
public: public:
virtual bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander*> &seen) virtual bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander*> &seen)
@@ -200,6 +203,29 @@ private slots:
void cleanupTestCase(); void cleanupTestCase();
private: private:
// Many tests in this file need to start a new subprocess with custom code.
// In order to simplify things we don't produce separate executables, but invoke
// the same test process recursively. These tests are embedded in classes,
// defined by the SUB_CREATOR_PROCESS macro. The macro defines a class alongside of the
// corresponding environment variable which is set prior to the execution of the subprocess.
// The following subprocess classes are defined:
SUB_CREATOR_PROCESS(SimpleTest);
SUB_CREATOR_PROCESS(ExitCode);
SUB_CREATOR_PROCESS(RunBlockingStdOut);
SUB_CREATOR_PROCESS(LineCallback);
SUB_CREATOR_PROCESS(ProcessChannelForwarding);
SUB_CREATOR_PROCESS(SubProcessChannelForwarding);
SUB_CREATOR_PROCESS(KillBlockingProcess);
// In order to get a value associated with the certain subprocess use SubProcessClass::envVar().
// The classes above define different custom executables. Inside initTestCase()
// we are detecting if one of these variables is set (by a call to
// invokeSubProcessIfRequired()) and invoke directly a respective custom
// executable code, which always ends up with a call to exit(). In this way (by calling exit()
// by the end of each subprocess executable) we stop the recursion, as from the test point of
// view we meant to execute only our custom code without further execution of the test itself.
void iteratorEditsHelper(OsType osType); void iteratorEditsHelper(OsType osType);
Environment envWindows; Environment envWindows;
@@ -211,26 +237,20 @@ private:
QString home; QString home;
}; };
void tst_QtcProcess::SimpleTest::main()
{
std::cout << simpleTestData << std::endl;
exit(0);
}
void tst_QtcProcess::initTestCase() void tst_QtcProcess::initTestCase()
{ {
Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/"
+ Core::Constants::IDE_CASED_ID + "-XXXXXX"); + Core::Constants::IDE_CASED_ID + "-XXXXXX");
Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/' Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/'
+ QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH));
if (qEnvironmentVariableIsSet(subExitCode))
subExitCodeMain(); invokeSubProcessIfRequired();
if (qEnvironmentVariableIsSet(subRunBlockingStdOut))
subRunBlockingStdOutMain();
if (qEnvironmentVariableIsSet(subLineCallback))
subLineCallbackMain();
if (qEnvironmentVariableIsSet(subSimpleTest))
subSimpleTestMain();
if (qEnvironmentVariableIsSet(subProcessChannelForwarding))
subProcessChannelForwardingMain();
if (qEnvironmentVariableIsSet(subSubProcessChannelForwarding))
subSubProcessChannelForwardingMain();
if (qEnvironmentVariableIsSet(subKillBlockingProcess))
subKillBlockingProcessMain();
homeStr = QLatin1String("@HOME@"); homeStr = QLatin1String("@HOME@");
home = QDir::homePath(); home = QDir::homePath();
@@ -891,9 +911,9 @@ void tst_QtcProcess::iteratorEditsLinux()
iteratorEditsHelper(OsTypeLinux); iteratorEditsHelper(OsTypeLinux);
} }
static void subExitCodeMain() void tst_QtcProcess::ExitCode::main()
{ {
const int exitCode = qEnvironmentVariableIntValue(subExitCode); const int exitCode = qEnvironmentVariableIntValue(envVar());
std::cout << "Exiting with code:" << exitCode << std::endl; std::cout << "Exiting with code:" << exitCode << std::endl;
exit(exitCode); exit(exitCode);
} }
@@ -916,7 +936,7 @@ void tst_QtcProcess::exitCode()
{ {
QFETCH(int, exitCode); QFETCH(int, exitCode);
SubCreatorConfig subConfig(subExitCode, QString::number(exitCode)); SubCreatorConfig subConfig(ExitCode::envVar(), QString::number(exitCode));
{ {
TestProcess process; TestProcess process;
subConfig.setupSubProcess(&process); subConfig.setupSubProcess(&process);
@@ -937,13 +957,13 @@ void tst_QtcProcess::exitCode()
} }
} }
static void subRunBlockingStdOutMain() void tst_QtcProcess::RunBlockingStdOut::main()
{ {
std::cout << "Wait for the Answer to the Ultimate Question of Life, " std::cout << "Wait for the Answer to the Ultimate Question of Life, "
"The Universe, and Everything..." << std::endl; "The Universe, and Everything..." << std::endl;
QThread::msleep(300); QThread::msleep(300);
std::cout << runBlockingStdOutSubProcessMagicWord << "...Now wait for the question..."; std::cout << runBlockingStdOutSubProcessMagicWord << "...Now wait for the question...";
if (qEnvironmentVariable(subRunBlockingStdOut) == "true") if (qEnvironmentVariable(envVar()) == "true")
std::cout << std::endl; std::cout << std::endl;
QThread::msleep(5000); QThread::msleep(5000);
exit(0); exit(0);
@@ -970,7 +990,7 @@ void tst_QtcProcess::runBlockingStdOut()
QFETCH(bool, withEndl); QFETCH(bool, withEndl);
QFETCH(int, timeOutS); QFETCH(int, timeOutS);
SubCreatorConfig subConfig(subRunBlockingStdOut, withEndl ? "true" : "false"); SubCreatorConfig subConfig(RunBlockingStdOut::envVar(), withEndl ? "true" : "false");
TestProcess process; TestProcess process;
subConfig.setupSubProcess(&process); subConfig.setupSubProcess(&process);
@@ -992,7 +1012,7 @@ void tst_QtcProcess::runBlockingStdOut()
QVERIFY2(readLastLine, "Last line was read."); QVERIFY2(readLastLine, "Last line was read.");
} }
static void subLineCallbackMain() void tst_QtcProcess::LineCallback::main()
{ {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
// Prevent \r\n -> \r\r\n translation. // Prevent \r\n -> \r\r\n translation.
@@ -1004,7 +1024,7 @@ static void subLineCallbackMain()
void tst_QtcProcess::lineCallback() void tst_QtcProcess::lineCallback()
{ {
SubCreatorConfig subConfig(subLineCallback, {}); SubCreatorConfig subConfig(LineCallback::envVar(), {});
TestProcess process; TestProcess process;
subConfig.setupSubProcess(&process); subConfig.setupSubProcess(&process);
@@ -1048,7 +1068,7 @@ void tst_QtcProcess::lineCallbackIntern()
void tst_QtcProcess::waitForStartedAndFinished() void tst_QtcProcess::waitForStartedAndFinished()
{ {
SubCreatorConfig subConfig(subSimpleTest, {}); SubCreatorConfig subConfig(SimpleTest::envVar(), {});
TestProcess process; TestProcess process;
subConfig.setupSubProcess(&process); subConfig.setupSubProcess(&process);
@@ -1096,26 +1116,26 @@ void tst_QtcProcess::notRunningAfterStartingNonExistingProgram()
// went into our output channels or not. // went into our output channels or not.
// So we start two processes in chain instead. On the beginning the processChannelForwarding() // So we start two processes in chain instead. On the beginning the processChannelForwarding()
// test starts the "subProcessChannelForwardingMain" - this one will start another process // test starts the ProcessChannelForwarding::main() - this one will start another process
// "subSubProcessChannelForwardingMain" with forwarding options. // SubProcessChannelForwarding::main() with forwarding options.
// The "subSubProcessChannelForwardingMain" is very simple - it just puts something to the output // The SubProcessChannelForwarding::main() is very simple - it just puts something to the output
// and the error channels. Then "subProcessChannelForwardingMain" either forwards these channels // and the error channels. Then ProcessChannelForwarding::main() either forwards these channels
// or not - we check it in the outer processChannelForwarding() test. // or not - we check it in the outer processChannelForwarding() test.
static void subSubProcessChannelForwardingMain() void tst_QtcProcess::SubProcessChannelForwarding::main()
{ {
std::cout << forwardedOutputData << std::endl; std::cout << forwardedOutputData << std::endl;
std::cerr << forwardedErrorData << std::endl; std::cerr << forwardedErrorData << std::endl;
exit(0); exit(0);
} }
static void subProcessChannelForwardingMain() void tst_QtcProcess::ProcessChannelForwarding::main()
{ {
const QProcess::ProcessChannelMode channelMode const QProcess::ProcessChannelMode channelMode
= QProcess::ProcessChannelMode(qEnvironmentVariableIntValue(subProcessChannelForwarding)); = QProcess::ProcessChannelMode(qEnvironmentVariableIntValue(envVar()));
qunsetenv(subProcessChannelForwarding); qunsetenv(envVar());
SubCreatorConfig subConfig(subSubProcessChannelForwarding, {}); SubCreatorConfig subConfig(SubProcessChannelForwarding::envVar(), {});
TestProcess process; TestProcess process;
subConfig.setupSubProcess(&process); subConfig.setupSubProcess(&process);
@@ -1143,7 +1163,7 @@ void tst_QtcProcess::processChannelForwarding()
QFETCH(bool, outputForwarded); QFETCH(bool, outputForwarded);
QFETCH(bool, errorForwarded); QFETCH(bool, errorForwarded);
SubCreatorConfig subConfig(subProcessChannelForwarding, QString::number(int(channelMode))); SubCreatorConfig subConfig(ProcessChannelForwarding::envVar(), QString::number(int(channelMode)));
TestProcess process; TestProcess process;
subConfig.setupSubProcess(&process); subConfig.setupSubProcess(&process);
@@ -1195,7 +1215,7 @@ protected:
bool MessageHandler::ok = true; bool MessageHandler::ok = true;
QtMessageHandler MessageHandler::oldMessageHandler = 0; QtMessageHandler MessageHandler::oldMessageHandler = 0;
static void subKillBlockingProcessMain() void tst_QtcProcess::KillBlockingProcess::main()
{ {
std::cout << "Blocking process successfully executed." << std::endl; std::cout << "Blocking process successfully executed." << std::endl;
while (true) while (true)
@@ -1204,7 +1224,7 @@ static void subKillBlockingProcessMain()
void tst_QtcProcess::killBlockingProcess() void tst_QtcProcess::killBlockingProcess()
{ {
SubCreatorConfig subConfig(subKillBlockingProcess, {}); SubCreatorConfig subConfig(KillBlockingProcess::envVar(), {});
MessageHandler msgHandler; MessageHandler msgHandler;
{ {
@@ -1220,7 +1240,7 @@ void tst_QtcProcess::killBlockingProcess()
void tst_QtcProcess::flushFinishedWhileWaitingForReadyRead() void tst_QtcProcess::flushFinishedWhileWaitingForReadyRead()
{ {
SubCreatorConfig subConfig(subSimpleTest, {}); SubCreatorConfig subConfig(SimpleTest::envVar(), {});
TestProcess process; TestProcess process;
subConfig.setupSubProcess(&process); subConfig.setupSubProcess(&process);