summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikolai Kosjar <nikolai.kosjar@digia.com>2013-01-22 12:54:22 +0100
committerNikolai Kosjar <nikolai.kosjar@digia.com>2013-01-24 12:39:28 +0100
commit8a1aa5dcf29bfcac07b919b3128789ca456ad206 (patch)
tree526728f84d89baa3fb8fbba6bd3c8f0e07480ba8
parent120f03061dacc4f567d86640afdc3eafbf3a06d3 (diff)
downloadqt-creator-8a1aa5dcf29bfcac07b919b3128789ca456ad206.tar.gz
Plugin tests: Allow to specify which test functions to run
This simplifies debugging single test functions. Test data can be specified the same way as for QTest executables. New syntax for the -test option: -test <plugin> [testfunction[:testdata]]... Examples: ./qtcreator -test Git testDiffFileResolving ./qtcreator -test Git testDiffFileResolving testStatusParsing:"DU" Change-Id: Ifea6b114bfc0fabe3e9ddffcc2fd90af157052ec Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com> Reviewed-by: Daniel Teske <daniel.teske@digia.com>
-rw-r--r--src/libs/extensionsystem/optionsparser.cpp20
-rw-r--r--src/libs/extensionsystem/pluginmanager.cpp59
-rw-r--r--src/libs/extensionsystem/pluginmanager_p.h19
3 files changed, 84 insertions, 14 deletions
diff --git a/src/libs/extensionsystem/optionsparser.cpp b/src/libs/extensionsystem/optionsparser.cpp
index 8aa26f3ec5..e0fb2921c8 100644
--- a/src/libs/extensionsystem/optionsparser.cpp
+++ b/src/libs/extensionsystem/optionsparser.cpp
@@ -107,8 +107,8 @@ bool OptionsParser::checkForTestOption()
if (nextToken(RequiredToken)) {
if (m_currentArg == QLatin1String("all")) {
foreach (PluginSpec *spec, m_pmPrivate->pluginSpecs) {
- if (spec && !m_pmPrivate->testSpecs.contains(spec))
- m_pmPrivate->testSpecs.append(spec);
+ if (spec && !m_pmPrivate->containsTestSpec(spec))
+ m_pmPrivate->testSpecs.append(PluginManagerPrivate::TestSpec(spec));
}
} else {
PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg);
@@ -117,8 +117,20 @@ bool OptionsParser::checkForTestOption()
*m_errorString = QCoreApplication::translate("PluginManager",
"The plugin '%1' does not exist.").arg(m_currentArg);
m_hasError = true;
- } else if (!m_pmPrivate->testSpecs.contains(spec)) {
- m_pmPrivate->testSpecs.append(spec);
+ } else if (!m_pmPrivate->containsTestSpec(spec)) {
+ // Collect optional test functions. Everything following the plugin
+ // name until the next option is interpreted as a test function. E.g.
+ // in './qtcreator -test Git myFile' the argument 'myFile' will be
+ // be interpreted as an function name and not a file to open.
+ const QStringList::const_iterator current(m_it);
+ QStringList testFunctions;
+ while (nextToken() && !m_currentArg.startsWith(QLatin1Char('-')))
+ testFunctions.append(m_currentArg);
+ // Make sure a following nextToken() call will get the current/next option.
+ if (current != m_it && m_it != m_end)
+ --m_it;
+ m_pmPrivate->testSpecs.append(
+ PluginManagerPrivate::TestSpec(spec, testFunctions));
}
}
}
diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp
index 76a67eb935..4109c533d7 100644
--- a/src/libs/extensionsystem/pluginmanager.cpp
+++ b/src/libs/extensionsystem/pluginmanager.cpp
@@ -616,8 +616,11 @@ void PluginManager::formatOptions(QTextStream &str, int optionIndentation, int d
QString(), QLatin1String("Profile plugin loading"),
optionIndentation, descriptionIndentation);
#ifdef WITH_TESTS
- formatOption(str, QLatin1String(OptionsParser::TEST_OPTION),
- QLatin1String("plugin|all"), QLatin1String("Run plugin's tests"),
+ formatOption(str, QString::fromLatin1(OptionsParser::TEST_OPTION)
+ + QLatin1String(" <plugin> [testfunction[:testdata]]..."), QString(),
+ QLatin1String("Run plugin's tests"), optionIndentation, descriptionIndentation);
+ formatOption(str, QString::fromLatin1(OptionsParser::TEST_OPTION) + QLatin1String(" all"),
+ QString(), QLatin1String("Run tests from all plugins"),
optionIndentation, descriptionIndentation);
#endif
}
@@ -662,13 +665,15 @@ void PluginManager::formatPluginVersions(QTextStream &str)
void PluginManager::startTests()
{
#ifdef WITH_TESTS
- foreach (PluginSpec *pluginSpec, d->testSpecs) {
+ foreach (const PluginManagerPrivate::TestSpec &testSpec, d->testSpecs) {
+ const PluginSpec * const pluginSpec = testSpec.pluginSpec;
if (!pluginSpec->plugin())
continue;
+
+ // Collect all test functions/methods of the plugin.
+ QStringList allTestFunctions;
const QMetaObject *mo = pluginSpec->plugin()->metaObject();
- QStringList methods;
- methods.append(QLatin1String("arg0"));
- // We only want slots starting with "test"
+
for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) {
#if QT_VERSION >= 0x050000
const QByteArray signature = mo->method(i).methodSignature();
@@ -677,13 +682,49 @@ void PluginManager::startTests()
#endif
if (signature.startsWith("test") && !signature.endsWith("_data()")) {
const QString method = QString::fromLatin1(signature);
- methods.append(method.left(method.size()-2));
+ allTestFunctions.append(method.left(method.size()-2));
+ }
+ }
+
+ QStringList testFunctionsToExecute;
+
+ // User did not specify any test functions, so add every test function.
+ if (testSpec.testFunctions.isEmpty()) {
+ testFunctionsToExecute = allTestFunctions;
+
+ // User specified test functions. Add them if they are valid.
+ } else {
+ foreach (const QString &userTestFunction, testSpec.testFunctions) {
+ // There might be a test data suffix like in "testfunction:testdata1".
+ QString testFunctionName = userTestFunction;
+ const int index = testFunctionName.indexOf(QLatin1Char(':'));
+ if (index != -1)
+ testFunctionName = testFunctionName.left(index);
+
+ if (allTestFunctions.contains(testFunctionName)) {
+ // If the specified test data is invalid, the QTest framework will
+ // print a reasonable error message for us.
+ testFunctionsToExecute.append(userTestFunction);
+ } else {
+ QTextStream out(stdout);
+ out << "Unknown test function \"" << testFunctionName
+ << "\" for plugin \"" << pluginSpec->name() << "\"." << endl
+ << " Available test functions for plugin \"" << pluginSpec->name()
+ << "\" are:" << endl;
+ foreach (const QString &testFunction, allTestFunctions)
+ out << " " << testFunction << endl;
+ }
}
}
+
+ // QTest::qExec() expects basically QCoreApplication::arguments(),
+ // so prepend a fake argument for the application name.
+ testFunctionsToExecute.prepend(QLatin1String("arg0"));
+
// Don't run QTest::qExec with only one argument, that'd run
// *all* slots as tests.
- if (methods.size() > 1)
- QTest::qExec(pluginSpec->plugin(), methods);
+ if (testFunctionsToExecute.size() > 1)
+ QTest::qExec(pluginSpec->plugin(), testFunctionsToExecute);
}
if (!d->testSpecs.isEmpty())
QTimer::singleShot(1, QCoreApplication::instance(), SLOT(quit()));
diff --git a/src/libs/extensionsystem/pluginmanager_p.h b/src/libs/extensionsystem/pluginmanager_p.h
index b267fc8eb9..5654e5718d 100644
--- a/src/libs/extensionsystem/pluginmanager_p.h
+++ b/src/libs/extensionsystem/pluginmanager_p.h
@@ -79,9 +79,26 @@ public:
void writeSettings();
void disablePluginIndirectly(PluginSpec *spec);
+ class TestSpec {
+ public:
+ TestSpec(PluginSpec *pluginSpec, const QStringList &testFunctions = QStringList())
+ : pluginSpec(pluginSpec), testFunctions(testFunctions) {}
+ PluginSpec *pluginSpec;
+ QStringList testFunctions;
+ };
+
+ bool containsTestSpec(PluginSpec *pluginSpec) const
+ {
+ foreach (const TestSpec &testSpec, testSpecs) {
+ if (testSpec.pluginSpec == pluginSpec)
+ return true;
+ }
+ return false;
+ }
+
QHash<QString, PluginCollection *> pluginCategories;
QList<PluginSpec *> pluginSpecs;
- QList<PluginSpec *> testSpecs;
+ QList<TestSpec> testSpecs;
QStringList pluginPaths;
QString extension;
QList<QObject *> allObjects; // ### make this a QList<QPointer<QObject> > > ?