diff --git a/outputview/outputfilteringstrategies.cpp b/outputview/outputfilteringstrategies.cpp
index 91361f1bac..cccc0265d7 100644
--- a/outputview/outputfilteringstrategies.cpp
+++ b/outputview/outputfilteringstrategies.cpp
@@ -1,396 +1,397 @@
/*
This file is part of KDevelop
Copyright (C) 2012 Morten Danielsen Volden mvolden2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "outputfilteringstrategies.h"
#include "outputformats.h"
#include "filtereditem.h"
#include
#include
#include
#include
namespace KDevelop
{
/// --- No filter strategy ---
NoFilterStrategy::NoFilterStrategy()
{
}
FilteredItem NoFilterStrategy::actionInLine(const QString& line)
{
return FilteredItem( line );
}
FilteredItem NoFilterStrategy::errorInLine(const QString& line)
{
return FilteredItem( line );
}
/// --- Compiler error filter strategy ---
/// Impl. of CompilerFilterStrategy.
struct CompilerFilterStrategyPrivate
{
CompilerFilterStrategyPrivate(const KUrl& buildDir);
KUrl urlForFile( const QString& ) const;
bool isMultiLineCase(ErrorFormat curErrFilter) const;
QVector m_currentDirs;
KUrl m_buildDir;
typedef QMap PositionMap;
PositionMap m_positionInCurrentDirs;
};
// All the possible string that indicate an error if we via Regex have been able to
// extract file and linenumber from a given outputline
-static const QVector ERROR_INDICATORS = QVector()
+typedef QPair Indicator;
+static const QVector INDICATORS = QVector()
// ld
- << "undefined reference"
- << "undefined symbol"
- << "ld: cannot find"
- << "No such file"
- // Gcc
- << "error";
+ << Indicator("undefined reference", FilteredItem::ErrorItem)
+ << Indicator("undefined symbol", FilteredItem::ErrorItem)
+ << Indicator("ld: cannot find", FilteredItem::ErrorItem)
+ << Indicator("no such file", FilteredItem::ErrorItem)
+ // gcc
+ << Indicator("error", FilteredItem::ErrorItem)
+ // generic
+ << Indicator("warning", FilteredItem::WarningItem)
+ << Indicator("info", FilteredItem::InformationItem)
+ << Indicator("note", FilteredItem::InformationItem);
// A list of filters for possible compiler, linker, and make errors
const QList ERROR_FILTERS = QList()
// GCC - another case, eg. for #include "pixmap.xpm" which does not exists
<< ErrorFormat( "^([^:\t]+):([0-9]+):([0-9]+):([^0-9]+)", 1, 2, 4, 3 )
// GCC
<< ErrorFormat( "^([^:\t]+):([0-9]+):([^0-9]+)", 1, 2, 3 )
// ICC
<< ErrorFormat( "^([^: \\t]+)\\(([0-9]+)\\):([^0-9]+)", 1, 2, 3, "intel" )
//libtool link
<< ErrorFormat( "^(libtool):( link):( warning): ", 0, 0, 0 )
// make
<< ErrorFormat( "No rule to make target", 0, 0, 0 )
// Fortran
<< ErrorFormat( "\"(.*)\", line ([0-9]+):(.*)", 1, 2, 3 )
// GFortran
<< ErrorFormat( "^(.*):([0-9]+)\\.([0-9]+):(.*)", 1, 2, 4, "gfortran", 3 )
// Jade
<< ErrorFormat( "^[a-zA-Z]+:([^: \t]+):([0-9]+):[0-9]+:[a-zA-Z]:(.*)", 1, 2, 3 )
// ifort
<< ErrorFormat( "^fortcom: (.*): (.*), line ([0-9]+):(.*)", 2, 3, 1, "intel" )
// PGI
<< ErrorFormat( "PGF9(.*)-(.*)-(.*)-(.*) \\((.*): ([0-9]+)\\)", 5, 6, 4, "pgi" )
// PGI (2)
<< ErrorFormat( "PGF9(.*)-(.*)-(.*)-Symbol, (.*) \\((.*)\\)", 5, 5, 4, "pgi" );
// A list of filters for possible compiler, linker, and make actions
QList ACTION_FILTERS = QList()
<< ActionFormat( i18n("compiling"), 1, 2, "(?:^|[^=])\\b(gcc|CC|cc|distcc|c\\+\\+|"
"g\\+\\+|icc|icpc)\\s+.*-c.*[/ '\\\\]+(\\w+\\.(?:cpp|CPP|c|C|cxx|CXX|cs|"
"java|hpf|f|F|f90|F90|f95|F95))")
//moc and uic
<< ActionFormat( i18n("generating"), 1, 2, "/(moc|uic)\\b.*\\s-o\\s([^\\s;]+)")
//libtool linking
<< ActionFormat( i18nc("Linking object files into a library or executable", "linking"),
"libtool", "/bin/sh\\s.*libtool.*--mode=link\\s.*\\s-o\\s([^\\s;]+)", 1 )
//unsermake
<< ActionFormat( i18n("compiling"), 1, 1, "^compiling (.*)" )
<< ActionFormat( i18n("generating"), 1, 2, "^generating (.*)" )
<< ActionFormat( i18nc("Linking object files into a library or executable",
"linking"), 1, 2, "(gcc|cc|c\\+\\+|g\\+\\+|icc|icpc)\\S* (?:\\S* )*-o ([^\\s;]+)")
<< ActionFormat( i18nc("Linking object files into a library or executable",
"linking"), 1, 2, "^linking (.*)" )
//cmake
<< ActionFormat( i18n("built"), -1, 1, "\\[.+%\\] Built target (.*)" )
<< ActionFormat( i18n("compiling"), "cmake", "\\[.+%\\] Building .* object (.*)CMakeFiles/", 1 )
<< ActionFormat( i18n("generating"), -1, 1, "\\[.+%\\] Generating (.*)" )
<< ActionFormat( i18nc("Linking object files into a library or executable",
"linking"), -1, 1, "^Linking (.*)" )
<< ActionFormat( i18n("installing"), -1, 1, "-- Installing (.*)" )
//libtool install
<< ActionFormat( i18n("creating"), "", "/(?:bin/sh\\s.*mkinstalldirs).*\\s([^\\s;]+)", 1 )
<< ActionFormat( i18n("installing"), "", "/(?:usr/bin/install|bin/sh\\s.*mkinstalldirs"
"|bin/sh\\s.*libtool.*--mode=install).*\\s([^\\s;]+)", 1 )
//dcop
<< ActionFormat( i18n("generating"), "dcopidl", "dcopidl .* > ([^\\s;]+)", 1 )
<< ActionFormat( i18n("compiling"), "dcopidl2cpp", "dcopidl2cpp (?:\\S* )*([^\\s;]+)", 1 )
// match against Entering directory to update current build dir
<< ActionFormat( "cd", "", "make\\[\\d+\\]: Entering directory (\\`|\\')(.+)'", 2);
CompilerFilterStrategyPrivate::CompilerFilterStrategyPrivate(const KUrl& buildDir)
: m_buildDir(buildDir)
{
}
KUrl CompilerFilterStrategyPrivate::urlForFile(const QString& filename) const
{
QFileInfo fi( filename );
KUrl currentUrl;
if( fi.isRelative() ) {
if( m_currentDirs.isEmpty() ) {
currentUrl = m_buildDir;
currentUrl.addPath( filename );
return currentUrl;
}
QVector::const_iterator it = m_currentDirs.constEnd() - 1;
do {
currentUrl = KUrl( *it );
currentUrl.addPath( filename );
} while( (it-- != m_currentDirs.constBegin()) && !QFileInfo(currentUrl.toLocalFile()).exists() );
return currentUrl;
} else {
currentUrl = KUrl( filename );
}
return currentUrl;
}
CompilerFilterStrategy::CompilerFilterStrategy(const KUrl& buildDir)
: d(new CompilerFilterStrategyPrivate( buildDir ))
{
}
CompilerFilterStrategy::~CompilerFilterStrategy()
{
delete d;
}
QVector< QString > CompilerFilterStrategy::getCurrentDirs()
{
return d->m_currentDirs;
}
FilteredItem CompilerFilterStrategy::actionInLine(const QString& line)
{
FilteredItem item(line);
foreach( const ActionFormat& curActFilter, ACTION_FILTERS ) {
QRegExp regEx = curActFilter.expression;
if( regEx.indexIn( line ) != -1 )
{
item.type = FilteredItem::ActionItem;
if( curActFilter.fileGroup != -1 && curActFilter.toolGroup != -1 )
{
item.shortenedText = QString( "%1 %2 (%3)").arg( curActFilter.action ).arg( regEx.cap( curActFilter.fileGroup ) ).arg( regEx.cap( curActFilter.toolGroup ) );
}
if( curActFilter.action == "cd" )
{
d->m_currentDirs.push_back( regEx.cap( curActFilter.fileGroup ) );
d->m_positionInCurrentDirs.insert( regEx.cap( curActFilter.fileGroup ) , d->m_currentDirs.size() - 1 );
}
// Special case for cmake: we parse the "Compiling " expression
// and use it to find out about the build paths encountered during a build.
// They are later searched by urlForFile to find source files corresponding to
// compiler errors.
if ( curActFilter.action == i18n("compiling") && curActFilter.tool == "cmake")
{
KUrl url = d->m_buildDir;
url.addPath(regEx.cap( curActFilter.fileGroup ));
QString dirName = url.toLocalFile();
// Use map to check for duplicates, to avoid O(n^2) behaviour
CompilerFilterStrategyPrivate::PositionMap::iterator it = d->m_positionInCurrentDirs.find(dirName);
// Encountered new build directory?
if (it == d->m_positionInCurrentDirs.end())
{
d->m_currentDirs.push_back( dirName );
d->m_positionInCurrentDirs.insert( dirName, d->m_currentDirs.size() - 1 );
}
else
{
// Build dir already in currentDirs, but move it to back of currentDirs list
// (this gives us most-recently-used semantics in urlForFile)
std::rotate(d->m_currentDirs.begin() + it.value(), d->m_currentDirs.begin() + it.value() + 1, d->m_currentDirs.end() );
it.value() = d->m_currentDirs.size() - 1;
}
}
break;
}
}
return item;
}
bool CompilerFilterStrategyPrivate::isMultiLineCase(KDevelop::ErrorFormat curErrFilter) const
{
if(curErrFilter.compiler == "gfortran") {
return true;
}
return false;
}
FilteredItem CompilerFilterStrategy::errorInLine(const QString& line)
{
FilteredItem item(line);
foreach( const ErrorFormat& curErrFilter, ERROR_FILTERS ) {
QRegExp regEx = curErrFilter.expression;
if( regEx.indexIn( line ) != -1 && !( line.contains( "Each undeclared identifier is reported only once" ) || line.contains( "for each function it appears in." ) ) ) {
if(curErrFilter.fileGroup > 0) {
item.url = d->urlForFile( regEx.cap( curErrFilter.fileGroup ) );
}
item.lineNo = regEx.cap( curErrFilter.lineGroup ).toInt() - 1;
if(curErrFilter.columnGroup >= 0) {
item.columnNo = regEx.cap( curErrFilter.columnGroup ).toInt() - 1;
} else {
item.columnNo = 0;
}
QString txt = regEx.cap(curErrFilter.textGroup);
- foreach( const QString curErrIndicator , ERROR_INDICATORS ) {
- if(txt.contains(curErrIndicator, Qt::CaseInsensitive)) {
- item.type = FilteredItem::ErrorItem;
- break;
- }
- }
- if(txt.contains("warning", Qt::CaseInsensitive)) {
- item.type = FilteredItem::WarningItem;
- }
-
- if(txt.contains("note", Qt::CaseInsensitive) || txt.contains("info", Qt::CaseInsensitive)) {
- item.type = FilteredItem::InformationItem;
+ // Find the indicator which happens most early.
+ int earliestIndicatorIdx = txt.length();
+ foreach( const Indicator& curIndicator, INDICATORS ) {
+ int curIndicatorIdx = txt.indexOf(curIndicator.first, 0, Qt::CaseInsensitive);
+ if((curIndicatorIdx >= 0) && (earliestIndicatorIdx > curIndicatorIdx)) {
+ earliestIndicatorIdx = curIndicatorIdx;
+ item.type = curIndicator.second;
+ }
}
// Make the item clickable if it comes with the necessary file & line number information
if (curErrFilter.fileGroup > 0 && curErrFilter.lineGroup > 0) {
item.isActivatable = true;
if(item.type == FilteredItem::InvalidItem) {
// If there are no error indicators in the line
// maybe this is a multiline case
if(d->isMultiLineCase(curErrFilter))
{
item.type = FilteredItem::ErrorItem;
} else {
// Okay so we couldn't find anything to indicate an error, but we have file and lineGroup
// Lets keep this item clickable and indicate this to the user.
item.type = FilteredItem::InformationItem;
}
}
}
break;
}
}
return item;
}
/// --- Script error filter strategy ---
// A list of filters for possible Python and PHP errors
const QList SCRIPT_ERROR_FILTERS = QList()
//QRegExp python("^ File \"(.*)\", line (\\d*), in(.*)$");
<< ErrorFormat( "^ File \"(.*)\", line ([0-9]+)(.*$|, in(.*)$)", 1, 2, -1 )
//QRegExp phpstacktrace("^.*(/.*):(\\d*).*$");
<< ErrorFormat( "^.*(/.*):([0-9]+).*$", 1, 2, -1 )
//QRegExp phperror("^.* in (/.*) on line (\\d*).*$");
<< ErrorFormat( "^.* in (/.*) on line ([0-9]+).*$", 1, 2, -1 );
ScriptErrorFilterStrategy::ScriptErrorFilterStrategy()
{
}
FilteredItem ScriptErrorFilterStrategy::actionInLine(const QString& line)
{
return FilteredItem(line);
}
FilteredItem ScriptErrorFilterStrategy::errorInLine(const QString& line)
{
FilteredItem item(line);
foreach( const ErrorFormat& curErrFilter, SCRIPT_ERROR_FILTERS ) {
QRegExp regEx = curErrFilter.expression;
if( regEx.indexIn( line ) != -1 )
{
item.url = regEx.cap( curErrFilter.fileGroup );
item.lineNo = regEx.cap( curErrFilter.lineGroup ).toInt() - 1;
if(curErrFilter.columnGroup >= 0) {
item.columnNo = regEx.cap( curErrFilter.columnGroup ).toInt() - 1;
} else {
item.columnNo = 0;
}
QString txt = regEx.cap(curErrFilter.textGroup);
item.type = FilteredItem::ErrorItem;
// Make the item clickable if it comes with the necessary file & line number information
if (curErrFilter.fileGroup > 0 && curErrFilter.lineGroup > 0)
item.isActivatable = true;
break;
}
}
return item;
}
/// --- Static Analysis filter strategy ---
// A list of filters for static analysis tools (krazy2, cppcheck)
const QList STATIC_ANALYSIS_FILTERS = QList()
// CppCheck
<< ErrorFormat( "^\\[(.*):([0-9]+)\\]:(.*)", 1, 2, 3 )
// krazy2
<< ErrorFormat( "^\\t([^:]+).*line#([0-9]+).*", 1, 2, -1 )
// krazy2 without line info
<< ErrorFormat( "^\\t(.*): missing license", 1, -1, -1 );
StaticAnalysisFilterStrategy::StaticAnalysisFilterStrategy()
{
}
FilteredItem StaticAnalysisFilterStrategy::actionInLine(const QString& line)
{
return FilteredItem(line);
}
FilteredItem StaticAnalysisFilterStrategy::errorInLine(const QString& line)
{
FilteredItem item(line);
foreach( const ErrorFormat& curErrFilter, STATIC_ANALYSIS_FILTERS ) {
QRegExp regEx = curErrFilter.expression;
if( regEx.indexIn( line ) != -1 )
{
item.url = regEx.cap( curErrFilter.fileGroup );
item.lineNo = regEx.cap( curErrFilter.lineGroup ).toInt() - 1;
if(curErrFilter.columnGroup >= 0) {
item.columnNo = regEx.cap( curErrFilter.columnGroup ).toInt() - 1;
} else {
item.columnNo = 0;
}
QString txt = regEx.cap(curErrFilter.textGroup);
item.type = FilteredItem::ErrorItem;
// Make the item clickable if it comes with the necessary file & line number information
if (curErrFilter.fileGroup > 0 && curErrFilter.lineGroup > 0) {
item.isActivatable = true;
}
break;
}
}
return item;
}
} // namespace KDevelop
diff --git a/outputview/tests/filteringstrategytest.cpp b/outputview/tests/filteringstrategytest.cpp
index 8ff26b585c..bcd5b780f4 100644
--- a/outputview/tests/filteringstrategytest.cpp
+++ b/outputview/tests/filteringstrategytest.cpp
@@ -1,317 +1,351 @@
/*
This file is part of KDevelop
Copyright 2012 Milian Wolff
Copyright (C) 2012 Morten Danielsen Volden mvolden2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "filteringstrategytest.h"
#include "testlinebuilderfunctions.h"
#include
#include
#include
#include
QTEST_KDEMAIN(KDevelop::FilteringStrategyTest, NoGUI)
namespace KDevelop
{
void FilteringStrategyTest::testNoFilterstrategy_data()
{
QTest::addColumn("line");
QTest::addColumn("expected");
QTest::newRow("cppcheck-info-line")
<< buildCppCheckInformationLine() << FilteredItem::InvalidItem;
QTest::newRow("cppcheck-error-line")
<< buildCppCheckErrorLine() << FilteredItem::InvalidItem;
QTest::newRow("compiler-line")
<< buildCompilerLine() << FilteredItem::InvalidItem;
QTest::newRow("compiler-error-line")
<< buildCompilerErrorLine() << FilteredItem::InvalidItem;
QTest::newRow("compiler-action-line")
<< buildCompilerActionLine() << FilteredItem::InvalidItem;
QTest::newRow("compiler-information-line")
<< buildCompilerInformationLine() << FilteredItem::InvalidItem;
QTest::newRow("python-error-line")
<< buildPythonErrorLine() << FilteredItem::InvalidItem;
}
void FilteringStrategyTest::testNoFilterstrategy()
{
QFETCH(QString, line);
QFETCH(FilteredItem::FilteredOutputItemType, expected);
NoFilterStrategy testee;
FilteredItem item1 = testee.errorInLine(line);
QVERIFY(item1.type == expected);
item1 = testee.actionInLine(line);
QVERIFY(item1.type == expected);
}
void FilteringStrategyTest::testCompilerFilterstrategy_data()
{
QTest::addColumn("line");
QTest::addColumn("expectedError");
QTest::addColumn("expectedAction");
QTest::newRow("cppcheck-info-line")
<< buildCppCheckInformationLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("cppcheck-error-line")
<< buildCppCheckErrorLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-line")
<< buildCompilerLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-error-line")
<< buildCompilerErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-information-line")
<< buildCompilerInformationLine() << FilteredItem::InformationItem << FilteredItem::InvalidItem;
QTest::newRow("linker-action-line")
<< "linking testCustombuild (g++)" << FilteredItem::InvalidItem << FilteredItem::ActionItem;
QTest::newRow("linker-error-line")
<< buildLinkerErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("python-error-line")
<< buildPythonErrorLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
}
void FilteringStrategyTest::testCompilerFilterstrategy()
{
QFETCH(QString, line);
QFETCH(FilteredItem::FilteredOutputItemType, expectedError);
QFETCH(FilteredItem::FilteredOutputItemType, expectedAction);
KUrl projecturl( PROJECTS_SOURCE_DIR"/onefileproject/" );
CompilerFilterStrategy testee(projecturl);
FilteredItem item1 = testee.errorInLine(line);
QVERIFY(item1.type == expectedError);
item1 = testee.actionInLine(line);
QVERIFY(item1.type == expectedAction);
}
+void FilteringStrategyTest::testCompilerFilterstrategyMultipleKeywords_data()
+{
+ QTest::addColumn("line");
+ QTest::addColumn("expectedError");
+ QTest::addColumn("expectedAction");
+
+ QTest::newRow("warning-containing-error-word")
+ << "RingBuffer.cpp:64:6: warning: unused parameter ‘errorItem’ [-Wunused-parameter]"
+ << FilteredItem::WarningItem << FilteredItem::InvalidItem;
+ QTest::newRow("error-containing-info-word")
+ << "NodeSet.hpp:89:27: error: ‘Info’ was not declared in this scope"
+ << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
+ QTest::newRow("warning-in-filename-containing-error-word")
+ << "ErrorHandling.cpp:100:56: warning: unused parameter ‘item’ [-Wunused-parameter]"
+ << FilteredItem::WarningItem << FilteredItem::InvalidItem;
+ QTest::newRow("error-in-filename-containing-warning-word")
+ << "WarningHandling.cpp:100:56: error: ‘Item’ was not declared in this scope"
+ << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
+}
+
+void FilteringStrategyTest::testCompilerFilterstrategyMultipleKeywords()
+{
+ QFETCH(QString, line);
+ QFETCH(FilteredItem::FilteredOutputItemType, expectedError);
+ QFETCH(FilteredItem::FilteredOutputItemType, expectedAction);
+ KUrl projecturl( PROJECTS_SOURCE_DIR"/onefileproject/" );
+ CompilerFilterStrategy testee(projecturl);
+ FilteredItem item1 = testee.errorInLine(line);
+ QVERIFY(item1.type == expectedError);
+ item1 = testee.actionInLine(line);
+ QVERIFY(item1.type == expectedAction);
+}
+
+
void FilteringStrategyTest::testScriptErrorFilterstrategy_data()
{
QTest::addColumn("line");
QTest::addColumn("expectedError");
QTest::addColumn("expectedAction");
QTest::newRow("cppcheck-info-line")
<< buildCppCheckInformationLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("cppcheck-error-line")
<< buildCppCheckErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-line")
<< buildCompilerLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-error-line")
<< buildCompilerErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-action-line")
<< "linking testCustombuild (g++)" << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("python-error-line")
<< buildPythonErrorLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
}
void FilteringStrategyTest::testScriptErrorFilterstrategy()
{
QFETCH(QString, line);
QFETCH(FilteredItem::FilteredOutputItemType, expectedError);
QFETCH(FilteredItem::FilteredOutputItemType, expectedAction);
ScriptErrorFilterStrategy testee;
FilteredItem item1 = testee.errorInLine(line);
QVERIFY(item1.type == expectedError);
item1 = testee.actionInLine(line);
QVERIFY(item1.type == expectedAction);
}
void FilteringStrategyTest::testStaticAnalysisFilterStrategy_data()
{
QTest::addColumn("line");
QTest::addColumn("expectedError");
QTest::addColumn("expectedAction");
QTest::newRow("cppcheck-info-line")
<< buildCppCheckInformationLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("cppcheck-error-line")
<< buildCppCheckErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("krazy2-error-line")
<< buildKrazyErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("krazy2-error-line-two-colons")
<< buildKrazyErrorLine2() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("krazy2-error-line-error-description")
<< buildKrazyErrorLine3() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("krazy2-error-line-wo-line-info")
<< buildKrazyErrorLineNoLineInfo() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-line")
<< buildCompilerLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-error-line")
<< buildCompilerErrorLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-action-line")
<< "linking testCustombuild (g++)" << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("python-error-line")
<< buildPythonErrorLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
}
void FilteringStrategyTest::testStaticAnalysisFilterStrategy()
{
// Test that url's are extracted correctly as well
QString referencePath( PROJECTS_SOURCE_DIR"/onefileproject/main.cpp" );
QFETCH(QString, line);
QFETCH(FilteredItem::FilteredOutputItemType, expectedError);
QFETCH(FilteredItem::FilteredOutputItemType, expectedAction);
StaticAnalysisFilterStrategy testee;
FilteredItem item1 = testee.errorInLine(line);
QString extractedPath = item1.url.toLocalFile();
QVERIFY((item1.type != FilteredItem::ErrorItem) || ( extractedPath == referencePath));
QVERIFY(item1.type == expectedError);
item1 = testee.actionInLine(line);
QVERIFY(item1.type == expectedAction);
}
void FilteringStrategyTest::testCompilerFilterstrategyUrlFromAction_data()
{
QTest::addColumn("line");
QTest::addColumn("expectedLastDir");
QString basepath( PROJECTS_SOURCE_DIR"/onefileproject/" );
QTest::newRow("cmake-line1")
<< "[ 25%] Building CXX object /path/to/one/CMakeFiles/file.o" << QString( basepath + "path/to/one/" );
QTest::newRow("cmake-line2")
<< "[ 26%] Building CXX object /path/to/two/CMakeFiles/file.o" << QString( basepath + "path/to/two/");
QTest::newRow("cmake-line3")
<< "[ 26%] Building CXX object /path/to/three/CMakeFiles/file.o" << QString( basepath + "path/to/three/");
QTest::newRow("cmake-line4")
<< "[ 26%] Building CXX object /path/to/four/CMakeFiles/file.o" << QString( basepath + "path/to/four/");
QTest::newRow("cmake-line5")
<< "[ 26%] Building CXX object /path/to/two/CMakeFiles/file.o" << QString( basepath + "path/to/two/");
QTest::newRow("cd-line6")
<< QString("make[4]: Entering directory '" + basepath + "path/to/one/'") << QString( basepath + "path/to/one/");
QTest::newRow("cmake-line7")
<< QString("[ 50%] Building CXX object CMakeFiles/testdeque.dir/RingBuffer.cpp.o") << QString( basepath);
}
void FilteringStrategyTest::testCompilerFilterstrategyUrlFromAction()
{
QFETCH(QString, line);
QFETCH(QString, expectedLastDir);
KUrl projecturl( PROJECTS_SOURCE_DIR"/onefileproject/" );
static CompilerFilterStrategy testee(projecturl);
FilteredItem item1 = testee.actionInLine(line);
QCOMPARE(testee.getCurrentDirs().last(), expectedLastDir);
}
void FilteringStrategyTest::benchMarkCompilerFilterAction()
{
QString projecturl( PROJECTS_SOURCE_DIR"/onefileproject/" );
QStringList outputlines;
const int numLines(10000);
int j(0), k(0), l(0), m(0);
do {
++j; ++k; ++l;
QString tmp;
if(m % 2 == 0) {
tmp = QString( "[ 26%] Building CXX object /this/is/the/path/to/the/files/%1/%2/%3/CMakeFiles/file.o").arg( j ).arg( k ).arg( l );
} else {
tmp = QString( "make[4]: Entering directory '" + projecturl + "/this/is/the/path/to/the/files/%1/%2/%3/").arg( j ).arg( k ).arg( l );
}
outputlines << tmp;
if(j % 6 == 0) {
j = 0; ++m;
}
if(k % 9 == 0) {
k = 0; ++m;
}
if(l % 13 == 0) {
l = 0; ++m;
}
}
while(outputlines.size() < numLines ); // gives us numLines (-ish)
QElapsedTimer totalTime;
totalTime.start();
static CompilerFilterStrategy testee(projecturl);
FilteredItem item1("dummyline", FilteredItem::InvalidItem);
QBENCHMARK {
for(int i = 0; i < outputlines.size(); ++i) {
item1 = testee.actionInLine(outputlines.at(i));
}
}
const qint64 elapsed = totalTime.elapsed();
qDebug() << "ms elapsed to add directories: " << elapsed;
qDebug() << "total number of directories: " << outputlines.count();
const double avgDirectoryInsertion = double(elapsed) / outputlines.count();
qDebug() << "average ms spend pr. dir: " << avgDirectoryInsertion;
QVERIFY(avgDirectoryInsertion < 2);
}
void FilteringStrategyTest::testExtractionOfLineAndCulmn_data()
{
QTest::addColumn("line");
QTest::addColumn("file");
QTest::addColumn("lineNr");
QTest::addColumn("column");
QTest::addColumn("itemtype");
QTest::newRow("gcc-with-col")
<< "/path/to/file.cpp:123:45: fatal error: ..."
<< "/path/to/file.cpp" << 122 << 44 << FilteredItem::ErrorItem;
QTest::newRow("gcc-no-col")
<< "/path/to/file.cpp:123: error ..."
<< "/path/to/file.cpp" << 122 << 0 << FilteredItem::ErrorItem;
QTest::newRow("fortcom")
<< "fortcom: Error: Ogive8.f90, line 123: ..."
<< "./Ogive8.f90" << 122 << 0 << FilteredItem::ErrorItem;
QTest::newRow("fortcomError")
<< "fortcom: Error: ./Ogive8.f90, line 123: ..."
<< "././Ogive8.f90" << 122 << 0 << FilteredItem::ErrorItem;
QTest::newRow("fortcomWarning")
<< "fortcom: Warning: /path/Ogive8.f90, line 123: ..."
<< "/path/Ogive8.f90" << 122 << 0 << FilteredItem::WarningItem;
QTest::newRow("fortcomInfo")
<< "fortcom: Info: Ogive8.f90, line 123: ..."
<< "./Ogive8.f90" << 122 << 0 << FilteredItem::InformationItem;
QTest::newRow("libtool")
<< "libtool: link: warning: ..."
<< "" << -1 << 0 << FilteredItem::WarningItem;
QTest::newRow("gfortranError1")
<< "/path/to/file.f90:123.456:Error: ...."
<< "/path/to/file.f90" << 122 << 455 << FilteredItem::ErrorItem;
QTest::newRow("gfortranError2")
<< "/path/flib.f90:3567.22:"
<< "/path/flib.f90" << 3566 << 21 << FilteredItem::ErrorItem;
}
void FilteringStrategyTest::testExtractionOfLineAndCulmn()
{
QFETCH(QString, line);
QFETCH(QString, file);
QFETCH(int, lineNr);
QFETCH(int, column);
QFETCH(FilteredItem::FilteredOutputItemType, itemtype);
KUrl projecturl( "./" );
CompilerFilterStrategy testee(projecturl);
FilteredItem item1 = testee.errorInLine(line);
QCOMPARE(item1.type , itemtype);
QCOMPARE(item1.url.path(), file);
QCOMPARE(item1.lineNo , lineNr);
QCOMPARE(item1.columnNo , column);
}
}
diff --git a/outputview/tests/filteringstrategytest.h b/outputview/tests/filteringstrategytest.h
index 0d9b9433df..9f04503ac0 100644
--- a/outputview/tests/filteringstrategytest.h
+++ b/outputview/tests/filteringstrategytest.h
@@ -1,48 +1,50 @@
/*
This file is part of KDevelop
Copyright (C) 2012 Morten Danielsen Volden mvolden2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef FILTERINGSTRATEGYTEST_H
#define FILTERINGSTRATEGYTEST_H
#include
namespace KDevelop
{
class FilteringStrategyTest : public QObject
{
Q_OBJECT
private slots:
void testNoFilterstrategy_data();
void testNoFilterstrategy();
void testCompilerFilterstrategy_data();
void testCompilerFilterstrategy();
+ void testCompilerFilterstrategyMultipleKeywords_data();
+ void testCompilerFilterstrategyMultipleKeywords();
void testCompilerFilterstrategyUrlFromAction_data();
void testCompilerFilterstrategyUrlFromAction();
void testScriptErrorFilterstrategy_data();
void testScriptErrorFilterstrategy();
void testStaticAnalysisFilterStrategy_data();
void testStaticAnalysisFilterStrategy();
void benchMarkCompilerFilterAction();
void testExtractionOfLineAndCulmn_data();
void testExtractionOfLineAndCulmn();
};
}
#endif // FILTERINGSTRATEGYTEST_H