that way the file formatting is better preserved.
tests/auto/qml/qmldesigner/bauhaustests/tst_bauhaus
tests/auto/qml/qmldesigner/coretests/tst_qmldesigner_core
tests/auto/qml/qmldesigner/propertyeditortests/tst_propertyeditor
+tests/auto/profilewriter/tst_profilewriter
return true;
}
-static void findProVariables(ProBlock *block, const QStringList &vars,
- QList<ProVariable *> *proVars)
-{
- foreach (ProItem *item, block->items()) {
- if (item->kind() == ProItem::BlockKind) {
- ProBlock *subBlock = static_cast<ProBlock *>(item);
- if (subBlock->blockKind() == ProBlock::VariableKind) {
- ProVariable *proVar = static_cast<ProVariable*>(subBlock);
- if (vars.contains(proVar->variable()))
- *proVars << proVar;
- } else {
- findProVariables(subBlock, vars, proVars);
- }
- }
- }
-}
-
void Qt4PriFileNode::changeFiles(const FileType fileType,
const QStringList &filePaths,
QStringList *notChanged,
if (!saveModifiedEditors(m_projectFilePath))
return;
- ProFileReader *reader = m_project->createProFileReader(m_qt4ProFileNode);
- ProFile *includeFile = reader->parsedProFile(m_projectFilePath);
- m_project->destroyProFileReader(reader);
- if (!includeFile) {
- m_project->proFileParseError(tr("Error while changing pro file %1.").arg(m_projectFilePath));
- return;
+ QStringList lines;
+ ProFile *includeFile;
+ {
+ QString contents;
+ {
+ QFile qfile(m_projectFilePath);
+ if (qfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ contents = QString::fromLatin1(qfile.readAll()); // yes, really latin1
+ qfile.close();
+ lines = contents.split(QLatin1Char('\n'));
+ while (lines.last().isEmpty())
+ lines.removeLast();
+ } else {
+ m_project->proFileParseError(tr("Error while reading PRO file %1: %2")
+ .arg(m_projectFilePath, qfile.errorString()));
+ return;
+ }
+ }
+
+ ProFileReader *reader = m_project->createProFileReader(m_qt4ProFileNode);
+ includeFile = reader->parsedProFile(m_projectFilePath, contents);
+ m_project->destroyProFileReader(reader);
}
const QStringList vars = varNames(fileType);
QDir priFileDir = QDir(m_qt4ProFileNode->m_projectDir);
if (change == AddToProFile) {
- ProVariable *proVar = 0;
-
- // Check if variable item exists as child of root item
- foreach (ProItem *item, includeFile->items()) {
- if (item->kind() == ProItem::BlockKind) {
- ProBlock *block = static_cast<ProBlock *>(item);
- if (block->blockKind() == ProBlock::VariableKind) {
- proVar = static_cast<ProVariable*>(block);
- if (vars.contains(proVar->variable())
- && proVar->variableOperator() != ProVariable::RemoveOperator
- && proVar->variableOperator() != ProVariable::ReplaceOperator)
- break;
- proVar = 0;
- }
- }
- }
-
- if (!proVar) {
- // Create & append new variable item
-
- // TODO: This will always store e.g. a source file in SOURCES and not OBJECTIVE_SOURCES
- proVar = new ProVariable(vars.first(), includeFile);
- proVar->setVariableOperator(ProVariable::AddOperator);
- includeFile->appendItem(proVar);
- }
-
- const QString &proFilePath = includeFile->fileName();
- foreach (const QString &filePath, filePaths) {
- if (filePath == proFilePath)
- continue;
- const QString &relativeFilePath = priFileDir.relativeFilePath(filePath);
- proVar->appendItem(new ProValue(relativeFilePath, proVar));
- notChanged->removeOne(filePath);
- }
+ ProWriter::addFiles(includeFile, &lines, priFileDir, filePaths, vars);
+ notChanged->clear();
} else { // RemoveFromProFile
- QList<ProVariable *> proVars;
- findProVariables(includeFile, vars, &proVars);
-
- QStringList relativeFilePaths;
- foreach (const QString &absoluteFilePath, filePaths)
- relativeFilePaths << priFileDir.relativeFilePath(absoluteFilePath);
-
- foreach (ProVariable *proVar, proVars) {
- if (proVar->variableOperator() != ProVariable::RemoveOperator
- && proVar->variableOperator() != ProVariable::ReplaceOperator) {
- QList<ProItem *> values = proVar->items();
- for (int i = values.count(); --i >= 0; ) {
- ProItem *item = values.at(i);
- if (item->kind() == ProItem::ValueKind) {
- ProValue *val = static_cast<ProValue *>(item);
- if (relativeFilePaths.contains(val->value())) {
- notChanged->removeOne(priFileDir.absoluteFilePath(val->value()));
- delete values.takeAt(i);
- }
- }
- }
- proVar->setItems(values);
- }
- }
+ *notChanged = ProWriter::removeFiles(includeFile, &lines, priFileDir, filePaths, vars);
}
// save file
- save(includeFile);
+ save(lines);
includeFile->deref();
}
-void Qt4PriFileNode::save(ProFile *includeFile)
+void Qt4PriFileNode::save(const QStringList &lines)
{
Core::ICore *core = Core::ICore::instance();
Core::FileManager *fileManager = core->fileManager();
- QList<Core::IFile *> allFileHandles = fileManager->managedFiles(includeFile->fileName());
+ QList<Core::IFile *> allFileHandles = fileManager->managedFiles(m_projectFilePath);
Core::IFile *modifiedFileHandle = 0;
foreach (Core::IFile *file, allFileHandles)
- if (file->fileName() == includeFile->fileName())
+ if (file->fileName() == m_projectFilePath)
modifiedFileHandle = file;
if (modifiedFileHandle)
fileManager->blockFileChange(modifiedFileHandle);
- ProWriter pw;
- const bool ok = pw.write(includeFile, includeFile->fileName());
- Q_UNUSED(ok)
- m_project->qt4ProjectManager()->notifyChanged(includeFile->fileName());
+ QFile qfile(m_projectFilePath);
+ if (qfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ foreach (const QString &str, lines) {
+ qfile.write(str.toLatin1()); // yes, really latin1
+ qfile.write("\n");
+ }
+ qfile.close();
+ }
+ m_project->qt4ProjectManager()->notifyChanged(m_projectFilePath);
if (modifiedFileHandle)
fileManager->unblockFileChange(modifiedFileHandle);
void scheduleUpdate();
private:
- void save(ProFile *includeFile);
+ void save(const QStringList &lines);
bool priFileWritable(const QString &path);
bool saveModifiedEditors(const QString &path);
#include "proitems.h"
#include "prowriter.h"
-#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <QtCore/QPair>
using namespace Qt4ProjectManager::Internal;
-bool ProWriter::write(ProFile *profile, const QString &fileName)
+void ProWriter::addFiles(ProFile *profile, QStringList *lines,
+ const QDir &proFileDir, const QStringList &filePaths,
+ const QStringList &vars)
{
- QFile data(fileName);
- if (!data.open(QFile::WriteOnly|QFile::Text))
- return false;
-
- m_writeState = 0;
- m_comment.clear();
- m_out.setDevice(&data);
- writeItem(profile, QString());
- data.close();
-
- return true;
-}
-
-QString ProWriter::contents(ProFile *profile)
-{
- QString result;
-
- m_writeState = 0;
- m_comment.clear();
- m_out.setString(&result, QIODevice::WriteOnly);
- writeItem(profile, QString());
-
- return result;
-}
-
-QString ProWriter::fixComment(const QString &comment, const QString &indent) const
-{
- QString result = comment;
- result = result.replace(QLatin1Char('\n'),
- QLatin1Char('\n') + indent + QLatin1String("# "));
- return QLatin1String("# ") + result;
-}
-
-void ProWriter::writeValue(ProValue *value, const QString &indent)
-{
- if (m_writeState & NewLine) {
- m_out << indent << QLatin1String(" ");
- m_writeState &= ~NewLine;
- }
-
- m_out << value->value();
-
- if (!(m_writeState & LastItem))
- m_out << QLatin1String(" \\");
-
- if (!value->comment().isEmpty())
- m_out << QLatin1Char(' ') << fixComment(value->comment(), indent);
-
- m_out << endl;
- m_writeState |= NewLine;
-}
-
-void ProWriter::writeOther(ProItem *item, const QString &indent)
-{
- if (m_writeState & NewLine) {
- m_out << indent;
- m_writeState &= ~NewLine;
- }
-
- if (item->kind() == ProItem::FunctionKind) {
- ProFunction *v = static_cast<ProFunction*>(item);
- m_out << v->text();
- } else if (item->kind() == ProItem::ConditionKind) {
- ProCondition *v = static_cast<ProCondition*>(item);
- m_out << v->text();
- } else if (item->kind() == ProItem::OperatorKind) {
- ProOperator *v = static_cast<ProOperator*>(item);
- if (v->operatorKind() == ProOperator::OrOperator)
- m_out << QLatin1Char('|');
- else
- m_out << QLatin1Char('!');
+ // Check if variable item exists as child of root item
+ foreach (ProItem *item, profile->items()) {
+ if (item->kind() == ProItem::BlockKind) {
+ ProBlock *block = static_cast<ProBlock *>(item);
+ if (block->blockKind() == ProBlock::VariableKind) {
+ ProVariable *proVar = static_cast<ProVariable*>(block);
+ if (vars.contains(proVar->variable())
+ && proVar->variableOperator() != ProVariable::RemoveOperator
+ && proVar->variableOperator() != ProVariable::ReplaceOperator) {
+
+ int lineNo = proVar->lineNumber() - 1;
+ for (; lineNo < lines->count(); lineNo++) {
+ QString line = lines->at(lineNo);
+ int idx = line.indexOf(QLatin1Char('#'));
+ if (idx >= 0)
+ line.truncate(idx);
+ while (line.endsWith(QLatin1Char(' ')) || line.endsWith(QLatin1Char('\t')))
+ line.chop(1);
+ if (line.isEmpty()) {
+ if (idx >= 0)
+ continue;
+ break;
+ }
+ if (!line.endsWith(QLatin1Char('\\'))) {
+ (*lines)[lineNo].insert(line.length(), QLatin1String(" \\"));
+ lineNo++;
+ break;
+ }
+ }
+ QString added;
+ foreach (const QString &filePath, filePaths)
+ added += QLatin1String(" ") + proFileDir.relativeFilePath(filePath)
+ + QLatin1String(" \\\n");
+ added.chop(3);
+ lines->insert(lineNo, added);
+ return;
+ }
+ }
+ }
}
- if (!item->comment().isEmpty()) {
- if (!m_comment.isEmpty())
- m_comment += QLatin1Char('\n');
- m_comment += item->comment();
- }
+ // Create & append new variable item
+ QString added = QLatin1Char('\n') + vars.first() + QLatin1String(" +=");
+ foreach (const QString &filePath, filePaths)
+ added += QLatin1String(" \\\n ") + proFileDir.relativeFilePath(filePath);
+ *lines << added;
}
-void ProWriter::writeBlock(ProBlock *block, const QString &indent)
+static void findProVariables(ProBlock *block, const QStringList &vars,
+ QList<ProVariable *> *proVars)
{
- if (m_writeState & NewLine) {
- m_out << indent;
- m_writeState &= ~NewLine;
- }
-
- if (!block->comment().isEmpty()) {
- if (!(m_writeState & FirstItem))
- m_out << endl << indent;
- m_out << fixComment(block->comment(), indent) << endl << indent;
- }
-
- QString newindent = indent;
- if (block->blockKind() & ProBlock::VariableKind) {
- ProVariable *v = static_cast<ProVariable*>(block);
- m_out << v->variable();
- switch (v->variableOperator()) {
- case ProVariable::AddOperator:
- m_out << QLatin1String(" += "); break;
- case ProVariable::RemoveOperator:
- m_out << QLatin1String(" -= "); break;
- case ProVariable::ReplaceOperator:
- m_out << QLatin1String(" ~= "); break;
- case ProVariable::SetOperator:
- m_out << QLatin1String(" = "); break;
- case ProVariable::UniqueAddOperator:
- m_out << QLatin1String(" *= "); break;
- }
- } else if (block->blockKind() & ProBlock::ScopeContentsKind) {
- if (block->items().count() > 1) {
- newindent = indent + QLatin1String(" ");
- m_out << QLatin1String(" { ");
- if (!m_comment.isEmpty()) {
- m_out << fixComment(m_comment, indent);
- m_comment.clear();
+ foreach (ProItem *item, block->items()) {
+ if (item->kind() == ProItem::BlockKind) {
+ ProBlock *subBlock = static_cast<ProBlock *>(item);
+ if (subBlock->blockKind() == ProBlock::VariableKind) {
+ ProVariable *proVar = static_cast<ProVariable*>(subBlock);
+ if (vars.contains(proVar->variable()))
+ *proVars << proVar;
+ } else {
+ findProVariables(subBlock, vars, proVars);
}
- m_out << endl;
- m_writeState |= NewLine;
- } else {
- m_out << QLatin1Char(':');
- }
- }
-
- QList<ProItem*> items = block->items();
- for (int i = 0; i < items.count(); ++i) {
- m_writeState &= ~LastItem;
- m_writeState &= ~FirstItem;
- if (i == 0)
- m_writeState |= FirstItem;
- if (i == items.count() - 1)
- m_writeState |= LastItem;
- writeItem(items.at(i), newindent);
- }
-
- if ((block->blockKind() & ProBlock::ScopeContentsKind) && (block->items().count() > 1)) {
- if (m_writeState & NewLine) {
- m_out << indent;
- m_writeState &= ~NewLine;
}
- m_out << QLatin1Char('}');
- }
-
- if (!m_comment.isEmpty()) {
- m_out << fixComment(m_comment, indent);
- m_out << endl;
- m_writeState |= NewLine;
- m_comment.clear();
- }
-
- if (!(m_writeState & NewLine)) {
- m_out << endl;
- m_writeState |= NewLine;
}
}
-void ProWriter::writeItem(ProItem *item, const QString &indent)
+QStringList ProWriter::removeFiles(ProFile *profile, QStringList *lines,
+ const QDir &proFileDir, const QStringList &filePaths,
+ const QStringList &vars)
{
- if (item->kind() == ProItem::ValueKind) {
- writeValue(static_cast<ProValue*>(item), indent);
- } else if (item->kind() == ProItem::BlockKind) {
- writeBlock(static_cast<ProBlock*>(item), indent);
- } else {
- writeOther(item, indent);
+ QStringList notChanged = filePaths;
+
+ QList<ProVariable *> proVars;
+ findProVariables(profile, vars, &proVars);
+
+ // This is a tad stupid - basically, it can remove only entries which
+ // the above code added.
+ QStringList relativeFilePaths;
+ foreach (const QString &absoluteFilePath, filePaths)
+ relativeFilePaths << proFileDir.relativeFilePath(absoluteFilePath);
+
+ // This code expects proVars to be sorted by the variables' appearance in the file.
+ int delta = 1;
+ foreach (ProVariable *proVar, proVars) {
+ if (proVar->variableOperator() != ProVariable::RemoveOperator
+ && proVar->variableOperator() != ProVariable::ReplaceOperator) {
+
+ bool first = true;
+ int lineNo = proVar->lineNumber() - delta;
+ typedef QPair<int, int> ContPos;
+ QList<ContPos> contPos;
+ while (lineNo < lines->count()) {
+ QString &line = (*lines)[lineNo];
+ int lineLen = line.length();
+ bool killed = false;
+ bool saved = false;
+ int idx = line.indexOf(QLatin1Char('#'));
+ if (idx >= 0)
+ lineLen = idx;
+ QChar *chars = line.data();
+ forever {
+ if (!lineLen) {
+ if (idx >= 0)
+ goto nextLine;
+ goto nextVar;
+ }
+ QChar c = chars[lineLen - 1];
+ if (c != QLatin1Char(' ') && c != QLatin1Char('\t'))
+ break;
+ lineLen--;
+ }
+ {
+ int contCol = -1;
+ if (chars[lineLen - 1] == QLatin1Char('\\'))
+ contCol = --lineLen;
+ int colNo = 0;
+ if (first) {
+ colNo = line.indexOf(QLatin1Char('=')) + 1;
+ first = false;
+ saved = true;
+ }
+ while (colNo < lineLen) {
+ QChar c = chars[colNo];
+ if (c == QLatin1Char(' ') || c == QLatin1Char('\t')) {
+ colNo++;
+ continue;
+ }
+ int varCol = colNo;
+ while (colNo < lineLen) {
+ QChar c = chars[colNo];
+ if (c == QLatin1Char(' ') || c == QLatin1Char('\t'))
+ break;
+ colNo++;
+ }
+ QString fn = line.mid(varCol, colNo - varCol);
+ if (relativeFilePaths.contains(fn)) {
+ notChanged.removeOne(QDir::cleanPath(proFileDir.absoluteFilePath(fn)));
+ if (colNo < lineLen)
+ colNo++;
+ else if (varCol)
+ varCol--;
+ int len = colNo - varCol;
+ colNo = varCol;
+ line.remove(varCol, len);
+ lineLen -= len;
+ contCol -= len;
+ idx -= len;
+ if (idx >= 0)
+ line.insert(idx, QLatin1String("# ") + fn + QLatin1Char(' '));
+ killed = true;
+ } else {
+ saved = true;
+ }
+ }
+ if (saved) {
+ // Entries remained
+ contPos.clear();
+ } else if (killed) {
+ // Entries existed, but were all removed
+ if (contCol < 0) {
+ // This is the last line, so clear continuations leading to it
+ foreach (const ContPos &pos, contPos) {
+ QString &bline = (*lines)[pos.first];
+ bline.remove(pos.second, 1);
+ if (pos.second == bline.length())
+ while (bline.endsWith(QLatin1Char(' '))
+ || bline.endsWith(QLatin1Char('\t')))
+ bline.chop(1);
+ }
+ contPos.clear();
+ }
+ if (idx < 0) {
+ // Not even a comment stayed behind, so zap the line
+ lines->removeAt(lineNo);
+ delta++;
+ continue;
+ }
+ }
+ if (contCol >= 0)
+ contPos.append(qMakePair(lineNo, contCol));
+ }
+ nextLine:
+ lineNo++;
+ }
+ nextVar: ;
+ }
}
+ return notChanged;
}
#include "namespace_global.h"
-#include <QtCore/QTextStream>
+#include <QStringList>
QT_BEGIN_NAMESPACE
+class QDir;
class ProFile;
-class ProValue;
-class ProItem;
-class ProBlock;
QT_END_NAMESPACE
namespace Qt4ProjectManager {
class ProWriter
{
public:
- bool write(ProFile *profile, const QString &fileName);
- QString contents(ProFile *profile);
-
-protected:
- QString fixComment(const QString &comment, const QString &indent) const;
- void writeValue(ProValue *value, const QString &indent);
- void writeOther(ProItem *item, const QString &indent);
- void writeBlock(ProBlock *block, const QString &indent);
- void writeItem(ProItem *item, const QString &indent);
-
-private:
- enum ProWriteState {
- NewLine = 0x01,
- FirstItem = 0x02,
- LastItem = 0x04
- };
-
- QTextStream m_out;
- int m_writeState;
- QString m_comment;
+ static void addFiles(ProFile *profile, QStringList *lines,
+ const QDir &proFileDir, const QStringList &filePaths,
+ const QStringList &vars);
+ static QStringList removeFiles(ProFile *profile, QStringList *lines,
+ const QDir &proFileDir, const QStringList &filePaths,
+ const QStringList &vars);
};
} // namespace Internal
--- /dev/null
+/**************************************************************************
+**
+** 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 "profileevaluator.h"
+#include "prowriter.h"
+
+#include <QtTest/QtTest>
+//#include <QtCore/QSet>
+
+#define BASE_DIR "/some/stuff"
+
+class tst_ProFileWriter : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void edit_data();
+ void edit();
+ void multiVar();
+};
+
+void tst_ProFileWriter::edit_data()
+{
+ QTest::addColumn<bool>("add");
+ QTest::addColumn<QStringList>("files");
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("output");
+
+ struct Case {
+ bool add;
+ const char *title;
+ const char * const *files;
+ const char *input;
+ const char *output;
+ };
+
+ static const char *f_foo[] = { "foo", 0 };
+ static const char *f_foo_bar[] = { "foo", "bar", 0 };
+ static const Case cases[] = {
+ // Adding entries
+ {
+ true, "add new", f_foo,
+ "# test file",
+ "# test file\n"
+ "\n"
+ "SOURCES += \\\n"
+ " foo"
+ },
+ {
+ true, "add new ignoring scoped", f_foo,
+ "unix:SOURCES = some files",
+ "unix:SOURCES = some files\n"
+ "\n"
+ "SOURCES += \\\n"
+ " foo"
+ },
+ {
+ true, "add to existing", f_foo,
+ "SOURCES = some files",
+ "SOURCES = some files \\\n"
+ " foo"
+ },
+ {
+ true, "add to existing after comment", f_foo,
+ "SOURCES = some files # comment",
+ "SOURCES = some files \\ # comment\n"
+ " foo"
+ },
+ {
+ true, "add to existing after comment line", f_foo,
+ "SOURCES = some \\\n"
+ " # comment\n"
+ " files",
+ "SOURCES = some \\\n"
+ " # comment\n"
+ " files \\\n"
+ " foo"
+ },
+
+ // Removing entries
+ {
+ false, "remove fail", f_foo,
+ "SOURCES = bak bar",
+ "SOURCES = bak bar"
+ },
+ {
+ false, "remove one-line middle", f_foo,
+ "SOURCES = bak foo bar",
+ "SOURCES = bak bar"
+ },
+ {
+ false, "remove one-line trailing", f_foo,
+ "SOURCES = bak bar foo",
+ "SOURCES = bak bar"
+ },
+ {
+ false, "remove multi-line single leading", f_foo,
+ "SOURCES = foo \\\n"
+ " bak \\\n"
+ " bar",
+ "SOURCES = \\\n"
+ " bak \\\n"
+ " bar"
+ },
+ {
+ false, "remove multi-line single middle", f_foo,
+ "SOURCES = bak \\\n"
+ " foo \\\n"
+ " bar",
+ "SOURCES = bak \\\n"
+ " bar"
+ },
+ {
+ false, "remove multi-line single trailing", f_foo,
+ "SOURCES = bak \\\n"
+ " bar \\\n"
+ " foo",
+ "SOURCES = bak \\\n"
+ " bar"
+ },
+ {
+ false, "remove multi-line single leading with comment", f_foo,
+ "SOURCES = foo \\ # comment\n"
+ " bak \\\n"
+ " bar",
+ "SOURCES = \\ # foo # comment\n"
+ " bak \\\n"
+ " bar"
+ },
+ {
+ false, "remove multi-line single middle with comment", f_foo,
+ "SOURCES = bak \\\n"
+ " foo \\ # comment\n"
+ " bar",
+ "SOURCES = bak \\\n"
+ " \\ # foo # comment\n"
+ " bar"
+ },
+ {
+ false, "remove multi-line single trailing with comment", f_foo,
+ "SOURCES = bak \\\n"
+ " bar \\\n"
+ " foo # comment",
+ "SOURCES = bak \\\n"
+ " bar\n"
+ " # foo # comment"
+ },
+ {
+ false, "remove multi-line single trailing after empty line", f_foo,
+ "SOURCES = bak \\\n"
+ " bar \\\n"
+ " \\\n"
+ " foo",
+ "SOURCES = bak \\\n"
+ " bar\n"
+ },
+ {
+ false, "remove multi-line single trailing after comment line", f_foo,
+ "SOURCES = bak \\\n"
+ " bar \\\n"
+ " # just a comment\n"
+ " foo",
+ "SOURCES = bak \\\n"
+ " bar\n"
+ " # just a comment"
+ },
+ {
+ false, "remove multi-line single trailing after empty line with comment", f_foo,
+ "SOURCES = bak \\\n"
+ " bar \\\n"
+ " \\ # just a comment\n"
+ " foo",
+ "SOURCES = bak \\\n"
+ " bar\n"
+ " # just a comment"
+ },
+ {
+ false, "remove multiple one-line middle", f_foo_bar,
+ "SOURCES = bak foo bar baz",
+ "SOURCES = bak baz"
+ },
+ {
+ false, "remove multiple one-line trailing", f_foo_bar,
+ "SOURCES = bak baz foo bar",
+ "SOURCES = bak baz"
+ },
+ {
+ false, "remove multiple one-line interleaved", f_foo_bar,
+ "SOURCES = bak foo baz bar",
+ "SOURCES = bak baz"
+ },
+ {
+ false, "remove multiple one-line middle with comment", f_foo_bar,
+ "SOURCES = bak foo bar baz # comment",
+ "SOURCES = bak baz # bar # foo # comment"
+ },
+ {
+ false, "remove multi-line multiple trailing with empty line with comment", f_foo_bar,
+ "SOURCES = bak \\\n"
+ " bar \\\n"
+ " \\ # just a comment\n"
+ " foo",
+ "SOURCES = bak\n"
+ " # just a comment"
+ },
+ };
+
+ for (uint i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ const Case *_case = &cases[i];
+ QStringList files;
+ for (const char * const *file = _case->files; *file; file++)
+ files << QString::fromLatin1(BASE_DIR "/") + QString::fromLatin1(*file);
+ QTest::newRow(_case->title)
+ << _case->add
+ << files
+ << QString::fromLatin1(_case->input)
+ << QString::fromLatin1(_case->output);
+ }
+}
+
+void tst_ProFileWriter::edit()
+{
+ QFETCH(bool, add);
+ QFETCH(QStringList, files);
+ QFETCH(QString, input);
+ QFETCH(QString, output);
+
+ QDir baseDir(BASE_DIR);
+ QStringList lines = input.split(QLatin1String("\n"));
+ QStringList vars; vars << QLatin1String("SOURCES");
+
+ ProFileOption option;
+ ProFileEvaluator reader(&option);
+ ProFile *proFile = reader.parsedProFile(BASE_DIR "/test.pro", input);
+ QVERIFY(proFile);
+ if (add)
+ Qt4ProjectManager::Internal::ProWriter::addFiles(proFile, &lines, baseDir, files, vars);
+ else
+ Qt4ProjectManager::Internal::ProWriter::removeFiles(proFile, &lines, baseDir, files, vars);
+
+ QCOMPARE(lines.join(QLatin1String("\n")), output);
+}
+
+void tst_ProFileWriter::multiVar()
+{
+ QDir baseDir(BASE_DIR);
+ QString input = QLatin1String(
+ "SOURCES = foo bar\n"
+ "# comment line\n"
+ "HEADERS = baz bak"
+ );
+ QStringList lines = input.split(QLatin1String("\n"));
+ QString output = QLatin1String(
+ "SOURCES = bar\n"
+ "# comment line\n"
+ "HEADERS = baz"
+ );
+ QStringList files; files
+ << QString::fromLatin1(BASE_DIR "/foo")
+ << QString::fromLatin1(BASE_DIR "/bak");
+ QStringList vars; vars << QLatin1String("SOURCES") << QLatin1String("HEADERS");
+
+ ProFileOption option;
+ ProFileEvaluator reader(&option);
+ ProFile *proFile = reader.parsedProFile(BASE_DIR "/test.pro", input);
+ QVERIFY(proFile);
+ Qt4ProjectManager::Internal::ProWriter::removeFiles(proFile, &lines, baseDir, files, vars);
+
+ QCOMPARE(lines.join(QLatin1String("\n")), output);
+}
+
+QTEST_MAIN(tst_ProFileWriter)
+#include "main.moc"
--- /dev/null
+load(qttest_p4)
+
+include(../../../src/shared/proparser/proparser.pri)
+
+SOURCES += main.cpp
+QT -= gui