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