diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp index 32a0b92946164087c0456202c5379a58c87ce853..949e9b042b6680695d404a717410a2a78f5b8d5e 100644 --- a/src/plugins/projectexplorer/gccparser.cpp +++ b/src/plugins/projectexplorer/gccparser.cpp @@ -88,3 +88,162 @@ void GccParser::stdError(const QString &line) } IOutputParser::stdError(line); } + +// Unit tests: + +#ifdef WITH_TESTS +# include <QTest> + +# include "projectexplorer.h" +# include "metatypedeclarations.h" +# include "outputparser_test.h" + +void ProjectExplorerPlugin::testGccOutputParsers_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<OutputParserTester::Channel>("inputChannel"); + QTest::addColumn<QString>("childStdOutLines"); + QTest::addColumn<QString>("childStdErrLines"); + QTest::addColumn<QList<ProjectExplorer::TaskWindow::Task> >("tasks"); + QTest::addColumn<QString>("outputLines"); + + + QTest::newRow("pass-through stdout") + << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT + << QString::fromLatin1("Sometext") << QString() + << QList<ProjectExplorer::TaskWindow::Task>() + << QString(); + QTest::newRow("pass-through stderr") + << QString::fromLatin1("Sometext") << OutputParserTester::STDERR + << QString() << QString::fromLatin1("Sometext") + << QList<ProjectExplorer::TaskWindow::Task>() + << QString(); + + QTest::newRow("GCCE error") + << QString::fromLatin1("/temp/test/untitled8/main.cpp: In function `int main(int, char**)':\n" + "/temp/test/untitled8/main.cpp:9: error: `sfasdf' undeclared (first use this function)\n" + "/temp/test/untitled8/main.cpp:9: error: (Each undeclared identifier is reported only once for each function it appears in.)") + << OutputParserTester::STDERR + << QString() << QString() + << (QList<ProjectExplorer::TaskWindow::Task>() + << TaskWindow::Task(TaskWindow::Unknown, + QLatin1String("In function `int main(int, char**)':"), + QLatin1String("/temp/test/untitled8/main.cpp"), -1, + Constants::TASK_CATEGORY_COMPILE) + << TaskWindow::Task(TaskWindow::Error, + QLatin1String("`sfasdf' undeclared (first use this function)"), + QLatin1String("/temp/test/untitled8/main.cpp"), 9, + Constants::TASK_CATEGORY_COMPILE) + << TaskWindow::Task(TaskWindow::Error, + QLatin1String("(Each undeclared identifier is reported only once for each function it appears in.)"), + QLatin1String("/temp/test/untitled8/main.cpp"), 9, + Constants::TASK_CATEGORY_COMPILE) + ) + << QString(); + QTest::newRow("GCCE warning") + << QString::fromLatin1("/src/corelib/global/qglobal.h:1635: warning: inline function `QDebug qDebug()' used but never defined") + << OutputParserTester::STDERR + << QString() << QString() + << (QList<ProjectExplorer::TaskWindow::Task>() + << TaskWindow::Task(TaskWindow::Warning, + QLatin1String("inline function `QDebug qDebug()' used but never defined"), + QLatin1String("/src/corelib/global/qglobal.h"), 1635, + Constants::TASK_CATEGORY_COMPILE)) + << QString(); + QTest::newRow("warning") + << QString::fromLatin1("main.cpp:7:2: warning: Some warning") + << OutputParserTester::STDERR + << QString() << QString() + << (QList<ProjectExplorer::TaskWindow::Task>() << TaskWindow::Task(TaskWindow::Warning, + QLatin1String("Some warning"), + QLatin1String("main.cpp"), 7, + Constants::TASK_CATEGORY_COMPILE)) + << QString(); + QTest::newRow("GCCE #error") + << QString::fromLatin1("C:\\temp\\test\\untitled8\\main.cpp:7: #error Symbian error") + << OutputParserTester::STDERR + << QString() << QString() + << (QList<ProjectExplorer::TaskWindow::Task>() << TaskWindow::Task(TaskWindow::Error, + QLatin1String("#error Symbian error"), + QLatin1String("C:\\temp\\test\\untitled8\\main.cpp"), 7, + Constants::TASK_CATEGORY_COMPILE)) + << QString(); + // Symbian reports #warning(s) twice (using different syntax). + QTest::newRow("GCCE #warning1") + << QString::fromLatin1("C:\\temp\\test\\untitled8\\main.cpp:8: warning: #warning Symbian warning") + << OutputParserTester::STDERR + << QString() << QString() + << (QList<ProjectExplorer::TaskWindow::Task>() << TaskWindow::Task(TaskWindow::Warning, + QLatin1String("#warning Symbian warning"), + QLatin1String("C:\\temp\\test\\untitled8\\main.cpp"), 8, + Constants::TASK_CATEGORY_COMPILE)) + << QString(); + QTest::newRow("GCCE #warning2") + << QString::fromLatin1("/temp/test/untitled8/main.cpp:8:2: warning: #warning Symbian warning") + << OutputParserTester::STDERR + << QString() << QString() + << (QList<ProjectExplorer::TaskWindow::Task>() << TaskWindow::Task(TaskWindow::Warning, + QLatin1String("#warning Symbian warning"), + QLatin1String("/temp/test/untitled8/main.cpp"), 8, + Constants::TASK_CATEGORY_COMPILE)) + << QString(); + QTest::newRow("Undefined reference (debug)") + << QString::fromLatin1("main.o: In function `main':\n" + "C:\\temp\\test\\untitled8/main.cpp:8: undefined reference to `MainWindow::doSomething()'\n" + "collect2: ld returned 1 exit status") + << OutputParserTester::STDERR + << QString() << QString() + << (QList<ProjectExplorer::TaskWindow::Task>() + << TaskWindow::Task(TaskWindow::Unknown, + QLatin1String("In function `main':"), + QLatin1String("main.o"), -1, + Constants::TASK_CATEGORY_COMPILE) + << TaskWindow::Task(TaskWindow::Error, + QLatin1String("undefined reference to `MainWindow::doSomething()'"), + QLatin1String("C:\\temp\\test\\untitled8/main.cpp"), 8, + Constants::TASK_CATEGORY_COMPILE) + << TaskWindow::Task(TaskWindow::Error, + QLatin1String("collect2: ld returned 1 exit status"), + QString(), -1, + Constants::TASK_CATEGORY_COMPILE) + ) + << QString(); + QTest::newRow("Undefined reference (release)") + << QString::fromLatin1("main.o: In function `main':\n" + "C:\\temp\\test\\untitled8/main.cpp:(.text+0x40): undefined reference to `MainWindow::doSomething()'\n" + "collect2: ld returned 1 exit status") + << OutputParserTester::STDERR + << QString() << QString() + << (QList<ProjectExplorer::TaskWindow::Task>() + << TaskWindow::Task(TaskWindow::Unknown, + QLatin1String("In function `main':"), + QLatin1String("main.o"), -1, + Constants::TASK_CATEGORY_COMPILE) + << TaskWindow::Task(TaskWindow::Error, + QLatin1String("undefined reference to `MainWindow::doSomething()'"), + QLatin1String("C:\\temp\\test\\untitled8/main.cpp"), -1, + Constants::TASK_CATEGORY_COMPILE) + << TaskWindow::Task(TaskWindow::Error, + QLatin1String("collect2: ld returned 1 exit status"), + QString(), -1, + Constants::TASK_CATEGORY_COMPILE) + ) + << QString(); +} + +void ProjectExplorerPlugin::testGccOutputParsers() +{ + OutputParserTester testbench; + testbench.appendOutputParser(new GccParser); + QFETCH(QString, input); + QFETCH(OutputParserTester::Channel, inputChannel); + QFETCH(QList<TaskWindow::Task>, tasks); + QFETCH(QString, childStdOutLines); + QFETCH(QString, childStdErrLines); + QFETCH(QString, outputLines); + + testbench.testParsing(input, inputChannel, + tasks, childStdOutLines, childStdErrLines, + outputLines); +} +#endif diff --git a/src/plugins/projectexplorer/outputparser_test.cpp b/src/plugins/projectexplorer/outputparser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26b6b053f79fae05433b13401814e1872410039e --- /dev/null +++ b/src/plugins/projectexplorer/outputparser_test.cpp @@ -0,0 +1,159 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "outputparser_test.h" + +#include <QtTest> + +using namespace ProjectExplorer; + +OutputParserTester::OutputParserTester() : + m_debug(false) +{ +} + +OutputParserTester::~OutputParserTester() +{ + if (childParser()) + childParser()->takeOutputParserChain(); +} + +// test methods: +void OutputParserTester::testParsing(const QString &lines, + Channel inputChannel, + QList<TaskWindow::Task> tasks, + const QString &childStdOutLines, + const QString &childStdErrLines, + const QString &outputLines) +{ + reset(); + Q_ASSERT(childParser()); + + QStringList inputLines = lines.split(QChar('\n')); + foreach (const QString &input, inputLines) { + if (inputChannel == STDOUT) + childParser()->stdOutput(input); + else + childParser()->stdError(input); + } + + QCOMPARE(m_receivedOutput, outputLines); + QCOMPARE(m_receivedStdErrChildLine, childStdErrLines); + QCOMPARE(m_receivedStdOutChildLine, childStdOutLines); + QCOMPARE(m_receivedTasks.size(), tasks.size()); + if (m_receivedTasks.size() == tasks.size()) { + for(int i = 0; i < tasks.size(); ++i) { + QCOMPARE(m_receivedTasks.at(i).category, tasks.at(i).category); + QCOMPARE(m_receivedTasks.at(i).description, tasks.at(i).description); + QCOMPARE(m_receivedTasks.at(i).file, tasks.at(i).file); + QCOMPARE(m_receivedTasks.at(i).line, tasks.at(i).line); + QCOMPARE(m_receivedTasks.at(i).type, tasks.at(i).type); + } + } +} + +void OutputParserTester::testTaskMangling(const TaskWindow::Task input, + const TaskWindow::Task output) +{ + reset(); + childParser()->taskAdded(input); + + QVERIFY(m_receivedOutput.isNull()); + QVERIFY(m_receivedStdErrChildLine.isNull()); + QVERIFY(m_receivedStdOutChildLine.isNull()); + QVERIFY(m_receivedTasks.size() == 1); + if (m_receivedTasks.size() == 1) { + QCOMPARE(m_receivedTasks.at(0).category, output.category); + QCOMPARE(m_receivedTasks.at(0).description, output.description); + QCOMPARE(m_receivedTasks.at(0).file, output.file); + QCOMPARE(m_receivedTasks.at(0).line, output.line); + QCOMPARE(m_receivedTasks.at(0).type, output.type); + } +} + +void OutputParserTester::testOutputMangling(const QString &input, + const QString &output) +{ + reset(); + + childParser()->outputAdded(input); + + QCOMPARE(m_receivedOutput, output); + QVERIFY(m_receivedStdErrChildLine.isNull()); + QVERIFY(m_receivedStdOutChildLine.isNull()); + QVERIFY(m_receivedTasks.isEmpty()); +} + +void OutputParserTester::setDebugEnabled(bool debug) +{ + m_debug = debug; +} + +void OutputParserTester::stdOutput(const QString &line) +{ + if (!m_receivedStdOutChildLine.isEmpty()) + m_receivedStdOutChildLine.append(QChar('\n')); + m_receivedStdOutChildLine.append(line); +} + +void OutputParserTester::stdError(const QString &line) +{ + if (!m_receivedStdErrChildLine.isEmpty()) + m_receivedStdErrChildLine.append(QChar('\n')); + m_receivedStdErrChildLine.append(line); +} + +void OutputParserTester::appendOutputParser(IOutputParser *parser) +{ + Q_ASSERT(!childParser()); + Q_ASSERT(!parser->childParser()); + + IOutputParser::appendOutputParser(parser); + parser->appendOutputParser(this); +} + +void OutputParserTester::outputAdded(const QString &line) +{ + if (!m_receivedOutput.isEmpty()) + m_receivedOutput.append(QChar('\n')); + m_receivedOutput.append(line); +} + +void OutputParserTester::taskAdded(const ProjectExplorer::TaskWindow::Task &task) +{ + m_receivedTasks.append(task); +} + +void OutputParserTester::reset() +{ + m_receivedStdErrChildLine = QString(); + m_receivedStdOutChildLine = QString(); + m_receivedTasks.clear(); + m_receivedOutput = QString(); +} diff --git a/src/plugins/projectexplorer/outputparser_test.h b/src/plugins/projectexplorer/outputparser_test.h new file mode 100644 index 0000000000000000000000000000000000000000..5f53a7681b7c003f7f18234c8bd656758ede9bc6 --- /dev/null +++ b/src/plugins/projectexplorer/outputparser_test.h @@ -0,0 +1,89 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef OUTPUTPARSER_TESTER_H +#define OUTPUTPARSER_TESTER_H + +#include "projectexplorer_export.h" +#include "ioutputparser.h" + +namespace ProjectExplorer { + +class PROJECTEXPLORER_EXPORT OutputParserTester : public IOutputParser +{ + Q_OBJECT + +public: + enum Channel { + STDOUT, + STDERR + }; + + OutputParserTester(); + ~OutputParserTester(); + + // test methods: + void testParsing(const QString &lines, Channel inputChannel, + QList<TaskWindow::Task> tasks, + const QString &childStdOutLines, + const QString &childStdErrLines, + const QString &outputLines); + void testTaskMangling(const TaskWindow::Task input, + const TaskWindow::Task output); + void testOutputMangling(const QString &input, + const QString &output); + + void setDebugEnabled(bool); + + // IOutputParser interface: + void stdOutput(const QString &line); + void stdError(const QString &line); + + void appendOutputParser(IOutputParser *parser); + +private slots: + void outputAdded(const QString &line); + void taskAdded(const ProjectExplorer::TaskWindow::Task &task); + +private: + void reset(); + + bool m_debug; + + QString m_receivedStdErrChildLine; + QString m_receivedStdOutChildLine; + QList<TaskWindow::Task> m_receivedTasks; + QString m_receivedOutput; +}; + +} // namespace ProjectExplorer + +Q_DECLARE_METATYPE(ProjectExplorer::OutputParserTester::Channel) + +#endif // OUTPUTPARSER_TESTER_H diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index e964ce8b4b85b9cad6babe837925967fc66f58d1..1f35e261f3bcf8ebd81f2b2b433998e8373cbd13 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -220,6 +220,11 @@ private slots: void currentModeChanged(Core::IMode *mode, Core::IMode *oldMode); void updateActions(); +#ifdef WITH_TESTS + void testGccOutputParsers_data(); + void testGccOutputParsers(); +#endif + private: void runProjectImpl(Project *pro, QString mode); void executeRunConfiguration(RunConfiguration *, const QString &mode); diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index cbdf7c71e0adebb1e0f950a834243245a210dd88..c912a1985d6e108698f8ef682f4a470a5cdd7d95 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -149,6 +149,13 @@ FORMS += processstep.ui \ doubletabwidget.ui \ addtargetdialog.ui +equals(TEST, 1) { + SOURCES += \ + outputparser_test.cpp + HEADERS += \ + outputparser_test.h +} + win32 { SOURCES += applicationlauncher_win.cpp \ winguiprocess.cpp