aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--qbs-resources/imports/QbsAutotest.qbs5
-rw-r--r--src/lib/corelib/buildgraph/artifact.h2
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.h3
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.pri5
-rw-r--r--src/lib/corelib/buildgraph/cycledetector.h2
-rw-r--r--src/lib/corelib/buildgraph/productbuilddata.h2
-rw-r--r--src/lib/corelib/buildgraph/projectbuilddata.h2
-rw-r--r--src/lib/corelib/buildgraph/rescuableartifactdata.h2
-rw-r--r--src/lib/corelib/buildgraph/tst_buildgraph.cpp140
-rw-r--r--src/lib/corelib/corelib.pro1
-rw-r--r--src/lib/corelib/corelib.qbs19
-rw-r--r--src/lib/corelib/language/evaluator.h2
-rw-r--r--src/lib/corelib/language/filecontext.h2
-rw-r--r--src/lib/corelib/language/identifiersearch.h3
-rw-r--r--src/lib/corelib/language/item.h2
-rw-r--r--src/lib/corelib/language/itempool.h3
-rw-r--r--src/lib/corelib/language/language.h8
-rw-r--r--src/lib/corelib/language/language.pri5
-rw-r--r--src/lib/corelib/language/loader.h2
-rw-r--r--src/lib/corelib/language/propertymapinternal.h8
-rw-r--r--src/lib/corelib/language/qualifiedid.h4
-rw-r--r--src/lib/corelib/language/scriptengine.h2
-rw-r--r--src/lib/corelib/language/tst_language.cpp2444
-rw-r--r--src/lib/corelib/language/value.h2
-rw-r--r--src/lib/corelib/parser/qmljsastvisitor_p.h3
-rw-r--r--src/lib/corelib/parser/qmljsengine_p.h3
-rw-r--r--src/lib/corelib/parser/qmljslexer_p.h3
-rw-r--r--src/lib/corelib/parser/qmljsparser_p.h3
-rw-r--r--src/lib/corelib/tools/fileinfo.h2
-rw-r--r--src/lib/corelib/tools/filetime.h2
-rw-r--r--src/lib/corelib/tools/id.h4
-rw-r--r--src/lib/corelib/tools/processutils.h4
-rw-r--r--src/lib/corelib/tools/qbs_export.h11
-rw-r--r--src/lib/corelib/tools/scripttools.h2
-rw-r--r--src/lib/corelib/tools/tools.pri5
-rw-r--r--src/lib/corelib/tools/tst_tools.cpp950
-rw-r--r--src/lib/corelib/use_corelib.pri1
-rw-r--r--src/lib/corelib/use_installed_corelib.pri1
-rw-r--r--src/lib/library.pri1
-rw-r--r--tests/auto/auto.pri2
-rw-r--r--tests/auto/buildgraph/buildgraph.pro1
-rw-r--r--tests/auto/buildgraph/buildgraph.qbs5
-rw-r--r--tests/auto/buildgraph/tst_buildgraph.cpp123
-rw-r--r--tests/auto/buildgraph/tst_buildgraph.h (renamed from src/lib/corelib/buildgraph/tst_buildgraph.h)22
-rw-r--r--tests/auto/language/language.pro3
-rw-r--r--tests/auto/language/language.qbs14
-rw-r--r--tests/auto/language/tst_language.cpp2425
-rw-r--r--tests/auto/language/tst_language.h (renamed from src/lib/corelib/language/tst_language.h)35
-rw-r--r--tests/auto/tools/tools.pro1
-rw-r--r--tests/auto/tools/tools.qbs10
-rw-r--r--tests/auto/tools/tst_tools.cpp928
-rw-r--r--tests/auto/tools/tst_tools.h (renamed from src/lib/corelib/tools/tst_tools.h)13
52 files changed, 3578 insertions, 3669 deletions
diff --git a/qbs-resources/imports/QbsAutotest.qbs b/qbs-resources/imports/QbsAutotest.qbs
index 66e076677..7fc959394 100644
--- a/qbs-resources/imports/QbsAutotest.qbs
+++ b/qbs-resources/imports/QbsAutotest.qbs
@@ -9,7 +9,10 @@ QtApplication {
Depends { name: "Qt.testlib" }
Depends { name: "qbscore" }
Depends { name: "qbsbuildconfig" }
- cpp.includePaths: "../../../src"
+ cpp.includePaths: [
+ "../../../src",
+ "../../../src/app/shared", // for the logger
+ ]
cpp.cxxLanguageVersion: "c++11"
destinationDirectory: "bin"
Group {
diff --git a/src/lib/corelib/buildgraph/artifact.h b/src/lib/corelib/buildgraph/artifact.h
index 466169d46..ea0b6a6dc 100644
--- a/src/lib/corelib/buildgraph/artifact.h
+++ b/src/lib/corelib/buildgraph/artifact.h
@@ -64,7 +64,7 @@ using ArtifactSet = Set<Artifact *>;
*
*
*/
-class Artifact : public FileResourceBase, public BuildGraphNode
+class QBS_AUTOTEST_EXPORT Artifact : public FileResourceBase, public BuildGraphNode
{
public:
Artifact();
diff --git a/src/lib/corelib/buildgraph/buildgraph.h b/src/lib/corelib/buildgraph/buildgraph.h
index 1d127af30..0620cebb2 100644
--- a/src/lib/corelib/buildgraph/buildgraph.h
+++ b/src/lib/corelib/buildgraph/buildgraph.h
@@ -41,6 +41,7 @@
#include "forward_decls.h"
#include <language/forward_decls.h>
+#include <tools/qbs_export.h>
#include <QtCore/qstringlist.h>
@@ -73,7 +74,7 @@ void dumpProductBuildData(const ResolvedProductConstPtr &product);
bool findPath(BuildGraphNode *u, BuildGraphNode *v, QList<BuildGraphNode*> &path);
-void connect(BuildGraphNode *p, BuildGraphNode *c);
+void QBS_AUTOTEST_EXPORT connect(BuildGraphNode *p, BuildGraphNode *c);
void loggedConnect(BuildGraphNode *u, BuildGraphNode *v, const Logger &logger);
bool safeConnect(Artifact *u, Artifact *v, const Logger &logger);
void removeGeneratedArtifactFromDisk(Artifact *artifact, const Logger &logger);
diff --git a/src/lib/corelib/buildgraph/buildgraph.pri b/src/lib/corelib/buildgraph/buildgraph.pri
index fabba661e..4229ad414 100644
--- a/src/lib/corelib/buildgraph/buildgraph.pri
+++ b/src/lib/corelib/buildgraph/buildgraph.pri
@@ -70,11 +70,6 @@ HEADERS += \
$$PWD/timestampsupdater.h \
$$PWD/transformer.h
-qbs_enable_unit_tests {
- HEADERS += $$PWD/tst_buildgraph.h
- SOURCES += $$PWD/tst_buildgraph.cpp
-}
-
!qbs_no_dev_install {
buildgraph_headers.files = $$PWD/forward_decls.h
buildgraph_headers.path = $${QBS_INSTALL_PREFIX}/include/qbs/buildgraph
diff --git a/src/lib/corelib/buildgraph/cycledetector.h b/src/lib/corelib/buildgraph/cycledetector.h
index a3275e0d5..d280f6ecd 100644
--- a/src/lib/corelib/buildgraph/cycledetector.h
+++ b/src/lib/corelib/buildgraph/cycledetector.h
@@ -49,7 +49,7 @@ namespace Internal {
class BuildGraphNode;
-class CycleDetector : private BuildGraphVisitor
+class QBS_AUTOTEST_EXPORT CycleDetector : private BuildGraphVisitor
{
public:
CycleDetector(const Logger &logger);
diff --git a/src/lib/corelib/buildgraph/productbuilddata.h b/src/lib/corelib/buildgraph/productbuilddata.h
index 1bac76593..6027de282 100644
--- a/src/lib/corelib/buildgraph/productbuilddata.h
+++ b/src/lib/corelib/buildgraph/productbuilddata.h
@@ -53,7 +53,7 @@ namespace Internal {
class Logger;
-class ProductBuildData : public PersistentObject
+class QBS_AUTOTEST_EXPORT ProductBuildData : public PersistentObject
{
public:
~ProductBuildData();
diff --git a/src/lib/corelib/buildgraph/projectbuilddata.h b/src/lib/corelib/buildgraph/projectbuilddata.h
index ebcdf53fc..12c943880 100644
--- a/src/lib/corelib/buildgraph/projectbuilddata.h
+++ b/src/lib/corelib/buildgraph/projectbuilddata.h
@@ -59,7 +59,7 @@ class FileDependency;
class FileResourceBase;
class ScriptEngine;
-class ProjectBuildData : public PersistentObject
+class QBS_AUTOTEST_EXPORT ProjectBuildData : public PersistentObject
{
public:
ProjectBuildData(const ProjectBuildData *other = 0);
diff --git a/src/lib/corelib/buildgraph/rescuableartifactdata.h b/src/lib/corelib/buildgraph/rescuableartifactdata.h
index 1a6b33cdc..0058885a1 100644
--- a/src/lib/corelib/buildgraph/rescuableartifactdata.h
+++ b/src/lib/corelib/buildgraph/rescuableartifactdata.h
@@ -54,7 +54,7 @@ namespace qbs {
namespace Internal {
class PersistentPool;
-class RescuableArtifactData
+class QBS_AUTOTEST_EXPORT RescuableArtifactData
{
public:
~RescuableArtifactData();
diff --git a/src/lib/corelib/buildgraph/tst_buildgraph.cpp b/src/lib/corelib/buildgraph/tst_buildgraph.cpp
deleted file mode 100644
index 9cc502cf4..000000000
--- a/src/lib/corelib/buildgraph/tst_buildgraph.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qbs.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "tst_buildgraph.h"
-
-#include <buildgraph/artifact.h>
-#include <buildgraph/buildgraph.h>
-#include <buildgraph/cycledetector.h>
-#include <buildgraph/productbuilddata.h>
-#include <buildgraph/projectbuilddata.h>
-#include <language/language.h>
-#include <logging/logger.h>
-#include <tools/error.h>
-
-#include <QtTest/qtest.h>
-
-namespace qbs {
-namespace Internal {
-
-const TopLevelProjectPtr project = TopLevelProject::create();
-
-TestBuildGraph::TestBuildGraph(ILogSink *logSink) : m_logSink(logSink)
-{
- project->buildData.reset(new ProjectBuildData);
-}
-
-void TestBuildGraph::initTestCase()
-{
-}
-
-void TestBuildGraph::cleanupTestCase()
-{
-}
-
-
-bool TestBuildGraph::cycleDetected(const ResolvedProductConstPtr &product)
-{
- try {
- CycleDetector(Logger(m_logSink)).visitProduct(product);
- return false;
- } catch (const ErrorInfo &) {
- return true;
- }
-}
-
-ResolvedProductConstPtr TestBuildGraph::productWithDirectCycle()
-{
- const ResolvedProductPtr product = ResolvedProduct::create();
- product->project = project;
- product->buildData.reset(new ProductBuildData);
- Artifact * const root = new Artifact;
- root->product = product;
- Artifact * const child = new Artifact;
- child->product = product;
- product->buildData->roots.insert(root);
- product->buildData->nodes << root << child;
- qbs::Internal::connect(root, child);
- qbs::Internal::connect(child, root);
- return product;
-}
-
-ResolvedProductConstPtr TestBuildGraph::productWithLessDirectCycle()
-{
- const ResolvedProductPtr product = ResolvedProduct::create();
- product->project = project;
- product->buildData.reset(new ProductBuildData);
- Artifact * const root = new Artifact;
- Artifact * const child = new Artifact;
- Artifact * const grandchild = new Artifact;
- root->product = product;
- child->product = product;
- grandchild->product = product;
- product->buildData->roots << root;
- product->buildData->nodes << root << child << grandchild;
- qbs::Internal::connect(root, child);
- qbs::Internal::connect(child, grandchild);
- qbs::Internal::connect(grandchild, root);
- return product;
-}
-
-// root appears as a child, but in a different tree
-ResolvedProductConstPtr TestBuildGraph::productWithNoCycle()
-{
- const ResolvedProductPtr product = ResolvedProduct::create();
- product->project = project;
- product->buildData.reset(new ProductBuildData);
- Artifact * const root = new Artifact;
- Artifact * const root2 = new Artifact;
- root->product = product;
- root2->product = product;
- product->buildData->roots << root << root2;
- product->buildData->nodes << root << root2;
- qbs::Internal::connect(root2, root);
- return product;
-}
-
-void TestBuildGraph::testCycle()
-{
- QVERIFY(cycleDetected(productWithDirectCycle()));
- QVERIFY(cycleDetected(productWithLessDirectCycle()));
- QVERIFY(!cycleDetected(productWithNoCycle()));
-}
-
-} // namespace Internal
-} // namespace qbs
diff --git a/src/lib/corelib/corelib.pro b/src/lib/corelib/corelib.pro
index 97093e319..8e53891fd 100644
--- a/src/lib/corelib/corelib.pro
+++ b/src/lib/corelib/corelib.pro
@@ -8,7 +8,6 @@ isEmpty(QBS_RELATIVE_LIBEXEC_PATH) {
DEFINES += QBS_RELATIVE_LIBEXEC_PATH=\\\"$${QBS_RELATIVE_LIBEXEC_PATH}\\\"
QT += core-private network script
-qbs_enable_unit_tests:QT += testlib
qbs_enable_project_file_updates: QT += gui
INCLUDEPATH += $$PWD
diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs
index eac9e709c..6f470902a 100644
--- a/src/lib/corelib/corelib.qbs
+++ b/src/lib/corelib/corelib.qbs
@@ -4,7 +4,6 @@ QbsLibrary {
Depends { name: "cpp" }
Depends { name: "Qt"; submodules: ["core-private", "network", "script", "xml"] }
Depends { condition: qbsbuildconfig.enableProjectFileUpdates; name: "Qt.gui" }
- Depends { condition: qbsbuildconfig.enableUnitTests; name: "Qt.testlib" }
Depends { condition: Qt.core.staticBuild; productTypes: ["qbsplugin"] }
name: "qbscore"
cpp.includePaths: base.concat([
@@ -13,13 +12,14 @@ QbsLibrary {
])
property stringList projectFileUpdateDefines:
qbsbuildconfig.enableProjectFileUpdates ? ["QBS_ENABLE_PROJECT_FILE_UPDATES"] : []
+ property stringList enableUnitTestsDefines:
+ qbsbuildconfig.enableUnitTests ? ["QBS_ENABLE_UNIT_TESTS"] : []
// TODO: Use Utilities.cStringQuote
cpp.defines: base.concat([
'QBS_RELATIVE_LIBEXEC_PATH="' + qbsbuildconfig.relativeLibexecPath + '"',
"QBS_VERSION=\"" + version + "\"",
"QT_CREATOR", "QML_BUILD_STATIC_LIB", // needed for QmlJS
- "SRCDIR=\"" + path + "\""
- ]).concat(projectFileUpdateDefines)
+ ]).concat(projectFileUpdateDefines).concat(enableUnitTestsDefines)
Properties {
condition: qbs.targetOS.contains("windows")
@@ -455,19 +455,6 @@ QbsLibrary {
qbs.install: qbsbuildconfig.installApiHeaders
qbs.installDir: headerInstallPrefix
}
- Group {
- condition: qbsbuildconfig.enableUnitTests
- name: "tests"
- cpp.defines: outer.filter(function(def) { return def !== "QT_NO_CAST_FROM_ASCII"; })
- files: [
- "buildgraph/tst_buildgraph.cpp",
- "buildgraph/tst_buildgraph.h",
- "language/tst_language.cpp",
- "language/tst_language.h",
- "tools/tst_tools.h",
- "tools/tst_tools.cpp"
- ]
- }
Export {
Depends { name: "cpp" }
cpp.defines: product.projectFileUpdateDefines
diff --git a/src/lib/corelib/language/evaluator.h b/src/lib/corelib/language/evaluator.h
index b602326ca..c86f0375d 100644
--- a/src/lib/corelib/language/evaluator.h
+++ b/src/lib/corelib/language/evaluator.h
@@ -55,7 +55,7 @@ class FileTags;
class Logger;
class ScriptEngine;
-class Evaluator : private ItemObserver
+class QBS_AUTOTEST_EXPORT Evaluator : private ItemObserver
{
friend class SVConverter;
diff --git a/src/lib/corelib/language/filecontext.h b/src/lib/corelib/language/filecontext.h
index 7a0511632..001e64066 100644
--- a/src/lib/corelib/language/filecontext.h
+++ b/src/lib/corelib/language/filecontext.h
@@ -53,7 +53,7 @@ class ItemPool;
class FileContext : public FileContextBase
{
public:
- static FileContextPtr create();
+ static FileContextPtr QBS_AUTOTEST_EXPORT create();
void setContent(const QString &content) { m_content = content; }
const QString &content() const { return m_content; }
diff --git a/src/lib/corelib/language/identifiersearch.h b/src/lib/corelib/language/identifiersearch.h
index 999366314..e466c576a 100644
--- a/src/lib/corelib/language/identifiersearch.h
+++ b/src/lib/corelib/language/identifiersearch.h
@@ -42,13 +42,14 @@
#include <parser/qmljsastfwd_p.h>
#include <parser/qmljsastvisitor_p.h>
+#include <tools/qbs_export.h>
#include <QtCore/qmap.h>
#include <QtCore/qstring.h>
namespace qbs {
namespace Internal {
-class IdentifierSearch : private QbsQmlJS::AST::Visitor
+class QBS_AUTOTEST_EXPORT IdentifierSearch : private QbsQmlJS::AST::Visitor
{
public:
IdentifierSearch();
diff --git a/src/lib/corelib/language/item.h b/src/lib/corelib/language/item.h
index 6e2621d07..3df4c5903 100644
--- a/src/lib/corelib/language/item.h
+++ b/src/lib/corelib/language/item.h
@@ -60,7 +60,7 @@ class ItemObserver;
class ItemPool;
class Logger;
-class Item : public QbsQmlJS::Managed
+class QBS_AUTOTEST_EXPORT Item : public QbsQmlJS::Managed
{
friend class ASTPropertiesItemHandler;
friend class ItemPool;
diff --git a/src/lib/corelib/language/itempool.h b/src/lib/corelib/language/itempool.h
index 7ab62d6c1..a4837a057 100644
--- a/src/lib/corelib/language/itempool.h
+++ b/src/lib/corelib/language/itempool.h
@@ -41,6 +41,7 @@
#define QBS_ITEMPOOL_H
#include <parser/qmljsmemorypool_p.h>
+#include <tools/qbs_export.h>
#include <QtCore/qlist.h>
@@ -50,7 +51,7 @@ namespace Internal {
class Item;
enum class ItemType;
-class ItemPool
+class QBS_AUTOTEST_EXPORT ItemPool
{
Q_DISABLE_COPY(ItemPool)
public:
diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h
index b27fb7c71..f3c0f058e 100644
--- a/src/lib/corelib/language/language.h
+++ b/src/lib/corelib/language/language.h
@@ -252,7 +252,7 @@ private:
void store(PersistentPool &pool) const;
};
-class ResolvedGroup : public PersistentObject
+class QBS_AUTOTEST_EXPORT ResolvedGroup : public PersistentObject
{
public:
static GroupPtr create() { return GroupPtr(new ResolvedGroup); }
@@ -393,7 +393,7 @@ private:
class TopLevelProject;
class ScriptEngine;
-class ResolvedProduct : public PersistentObject
+class QBS_AUTOTEST_EXPORT ResolvedProduct : public PersistentObject
{
public:
static ResolvedProductPtr create() { return ResolvedProductPtr(new ResolvedProduct); }
@@ -471,7 +471,7 @@ private:
mutable std::mutex m_executablePathCacheLock;
};
-class ResolvedProject : public PersistentObject
+class QBS_AUTOTEST_EXPORT ResolvedProject : public PersistentObject
{
public:
static ResolvedProjectPtr create() { return ResolvedProjectPtr(new ResolvedProject); }
@@ -502,7 +502,7 @@ private:
TopLevelProject *m_topLevelProject;
};
-class TopLevelProject : public ResolvedProject
+class QBS_AUTOTEST_EXPORT TopLevelProject : public ResolvedProject
{
friend class BuildGraphLoader;
public:
diff --git a/src/lib/corelib/language/language.pri b/src/lib/corelib/language/language.pri
index c3bcbb674..d1961df9e 100644
--- a/src/lib/corelib/language/language.pri
+++ b/src/lib/corelib/language/language.pri
@@ -73,11 +73,6 @@ SOURCES += \
$$PWD/scriptimporter.cpp \
$$PWD/value.cpp
-qbs_enable_unit_tests {
- HEADERS += $$PWD/tst_language.h
- SOURCES += $$PWD/tst_language.cpp
-}
-
!qbs_no_dev_install {
language_headers.files = $$PWD/forward_decls.h
language_headers.path = $${QBS_INSTALL_PREFIX}/include/qbs/language
diff --git a/src/lib/corelib/language/loader.h b/src/lib/corelib/language/loader.h
index f923f1700..b94fb7553 100644
--- a/src/lib/corelib/language/loader.h
+++ b/src/lib/corelib/language/loader.h
@@ -52,7 +52,7 @@ class Logger;
class ProgressObserver;
class ScriptEngine;
-class Loader
+class QBS_AUTOTEST_EXPORT Loader
{
public:
Loader(ScriptEngine *engine, const Logger &logger);
diff --git a/src/lib/corelib/language/propertymapinternal.h b/src/lib/corelib/language/propertymapinternal.h
index 9874f5546..69890fef3 100644
--- a/src/lib/corelib/language/propertymapinternal.h
+++ b/src/lib/corelib/language/propertymapinternal.h
@@ -42,12 +42,13 @@
#include "forward_decls.h"
#include <tools/persistentobject.h>
+#include <tools/qbs_export.h>
#include <QtCore/qvariant.h>
namespace qbs {
namespace Internal {
-class PropertyMapInternal : public PersistentObject
+class QBS_AUTOTEST_EXPORT PropertyMapInternal : public PersistentObject
{
public:
static PropertyMapPtr create() { return PropertyMapPtr(new PropertyMapInternal); }
@@ -76,8 +77,9 @@ inline bool operator==(const PropertyMapInternal &lhs, const PropertyMapInternal
return lhs.m_value == rhs.m_value;
}
-QVariant moduleProperty(const QVariantMap &properties, const QString &moduleName,
- const QString &key);
+QVariant QBS_AUTOTEST_EXPORT moduleProperty(const QVariantMap &properties,
+ const QString &moduleName,
+ const QString &key);
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/qualifiedid.h b/src/lib/corelib/language/qualifiedid.h
index 007133be8..1415f668e 100644
--- a/src/lib/corelib/language/qualifiedid.h
+++ b/src/lib/corelib/language/qualifiedid.h
@@ -49,7 +49,7 @@
namespace qbs {
namespace Internal {
-class QualifiedId : public QStringList
+class QBS_AUTOTEST_EXPORT QualifiedId : public QStringList
{
public:
QualifiedId();
@@ -60,7 +60,7 @@ public:
QString toString() const;
};
-bool operator<(const QualifiedId &a, const QualifiedId &b);
+bool QBS_AUTOTEST_EXPORT operator<(const QualifiedId &a, const QualifiedId &b);
inline uint qHash(const QualifiedId &qid) { return qHash(qid.toString()); }
using QualifiedIdSet = Set<QualifiedId>;
diff --git a/src/lib/corelib/language/scriptengine.h b/src/lib/corelib/language/scriptengine.h
index 732ce8a09..da0b6028c 100644
--- a/src/lib/corelib/language/scriptengine.h
+++ b/src/lib/corelib/language/scriptengine.h
@@ -76,7 +76,7 @@ public:
};
using DubiousContextList = std::vector<DubiousContext>;
-class ScriptEngine : public QScriptEngine
+class QBS_AUTOTEST_EXPORT ScriptEngine : public QScriptEngine
{
Q_OBJECT
public:
diff --git a/src/lib/corelib/language/tst_language.cpp b/src/lib/corelib/language/tst_language.cpp
deleted file mode 100644
index 64a0e9790..000000000
--- a/src/lib/corelib/language/tst_language.cpp
+++ /dev/null
@@ -1,2444 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qbs.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack.
-
-#include "tst_language.h"
-
-#include "../../../../tests/auto/shared.h"
-
-#include <language/evaluator.h>
-#include <language/filecontext.h>
-#include <language/identifiersearch.h>
-#include <language/item.h>
-#include <language/itempool.h>
-#include <language/language.h>
-#include <language/propertymapinternal.h>
-#include <language/scriptengine.h>
-#include <language/value.h>
-#include <parser/qmljslexer_p.h>
-#include <parser/qmljsparser_p.h>
-#include <tools/scripttools.h>
-#include <tools/error.h>
-#include <tools/fileinfo.h>
-#include <tools/hostosinfo.h>
-#include <tools/jsliterals.h>
-#include <tools/profile.h>
-#include <tools/settings.h>
-
-#include <QtCore/qprocess.h>
-
-#include <algorithm>
-#include <utility>
-#include <vector>
-
-Q_DECLARE_METATYPE(QList<bool>)
-
-namespace qbs {
-namespace Internal {
-static QString testDataDir() {
- return FileInfo::resolvePath(QLatin1String(SRCDIR),
- QLatin1String("../../../tests/auto/language/testdata"));
-}
-static QString testProject(const char *fileName) {
- return testDataDir() + QLatin1Char('/') + QLatin1String(fileName);
-}
-
-TestLanguage::TestLanguage(ILogSink *logSink, Settings *settings)
- : m_logSink(logSink)
- , m_settings(settings)
- , m_wildcardsTestDirPath(QDir::tempPath() + QLatin1String("/_wildcards_test_dir_"))
-{
- qsrand(QTime::currentTime().msec());
- qRegisterMetaType<QList<bool> >("QList<bool>");
- defaultParameters.setBuildRoot("/some/build/directory");
- defaultParameters.setPropertyCheckingMode(ErrorHandlingMode::Strict);
- defaultParameters.setSettingsDirectory(m_settings->baseDirectory());
-}
-
-TestLanguage::~TestLanguage()
-{
-}
-
-QHash<QString, ResolvedProductPtr> TestLanguage::productsFromProject(ResolvedProjectPtr project)
-{
- QHash<QString, ResolvedProductPtr> result;
- foreach (const ResolvedProductPtr &product, project->allProducts())
- result.insert(product->name, product);
- return result;
-}
-
-ResolvedModuleConstPtr TestLanguage::findModuleByName(ResolvedProductPtr product, const QString &name)
-{
- foreach (const ResolvedModuleConstPtr &module, product->modules)
- if (module->name == name)
- return module;
- return ResolvedModuleConstPtr();
-}
-
-QVariant TestLanguage::productPropertyValue(ResolvedProductPtr product, QString propertyName)
-{
- QStringList propertyNameComponents = propertyName.split(QLatin1Char('.'));
- if (propertyNameComponents.count() > 1) {
- propertyNameComponents.prepend(QLatin1String("modules"));
- return product->moduleProperties->property(propertyNameComponents);
- }
- return getConfigProperty(product->productProperties, propertyNameComponents);
-}
-
-void TestLanguage::handleInitCleanupDataTags(const char *projectFileName, bool *handled)
-{
- const QByteArray dataTag = QTest::currentDataTag();
- if (dataTag == "init") {
- *handled = true;
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject(projectFileName));
- project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
- } else if (dataTag == "cleanup") {
- *handled = true;
- project.reset();
- } else {
- *handled = false;
- }
-}
-
-void TestLanguage::init()
-{
- m_logSink->setLogLevel(LoggerInfo);
-}
-
-#define HANDLE_INIT_CLEANUP_DATATAGS(fn) {\
- bool handled;\
- handleInitCleanupDataTags(fn, &handled);\
- if (handled)\
- return;\
- QVERIFY(!!project);\
-}
-
-void TestLanguage::initTestCase()
-{
- m_logger = Logger(m_logSink);
- m_engine = new ScriptEngine(m_logger, EvalContext::PropertyEvaluation, this);
- loader = new Loader(m_engine, m_logger);
- loader->setSearchPaths(QStringList()
- << QLatin1String(SRCDIR "/../../../share/qbs"));
- defaultParameters.setTopLevelProfile(profileName());
- defaultParameters.setConfigurationName("default");
- defaultParameters.expandBuildConfiguration();
- defaultParameters.setEnvironment(QProcessEnvironment::systemEnvironment());
- QVERIFY(QFileInfo(m_wildcardsTestDirPath).isAbsolute());
-}
-
-void TestLanguage::cleanupTestCase()
-{
- delete loader;
-}
-
-void TestLanguage::baseProperty()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("baseproperty.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value("product1");
- QVERIFY(!!product);
- QVariantMap cfg = product->productProperties;
- QCOMPARE(cfg.value("narf").toStringList(), QStringList() << "boo");
- QCOMPARE(cfg.value("zort").toStringList(), QStringList() << "bar" << "boo");
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::baseValidation()
-{
- qbs::SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("base-validate/base-validate.qbs"));
- try {
- project = loader->loadProject(params);
- QVERIFY2(false, "exception expected");
- } catch (const qbs::ErrorInfo &e) {
- QVERIFY2(e.toString().contains("Parent succeeded, child failed."),
- qPrintable(e.toString()));
- }
-}
-
-void TestLanguage::buildConfigStringListSyntax()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters parameters = defaultParameters;
- QVariantMap overriddenValues;
- overriddenValues.insert("project.someStrings", "foo,bar,baz");
- parameters.setOverriddenValues(overriddenValues);
- parameters.setProjectFilePath(testProject("buildconfigstringlistsyntax.qbs"));
- project = loader->loadProject(parameters);
- QVERIFY(!!project);
- QCOMPARE(project->projectProperties().value("someStrings").toStringList(),
- QStringList() << "foo" << "bar" << "baz");
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::builtinFunctionInSearchPathsProperty()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters parameters = defaultParameters;
- parameters.setProjectFilePath(testProject("builtinFunctionInSearchPathsProperty.qbs"));
- QVERIFY(!!loader->loadProject(parameters));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::chainedProbes()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters parameters = defaultParameters;
- parameters.setProjectFilePath(testProject("chained-probes/chained-probes.qbs"));
- const TopLevelProjectConstPtr project = loader->loadProject(parameters);
- QVERIFY(!!project);
- QCOMPARE(project->products.count(), 1);
- const QString prop2Val = project->products.first()->moduleProperties
- ->moduleProperty("m", "prop2").toString();
- QCOMPARE(prop2Val, QLatin1String("probe1Valprobe2Val"));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-
-}
-
-void TestLanguage::versionCompare()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters parameters = defaultParameters;
- parameters.setProjectFilePath(testProject("versionCompare.qbs"));
- QVERIFY(!!loader->loadProject(parameters));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::canonicalArchitecture()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("canonicalArchitecture.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value(QLatin1String("x86"));
- QVERIFY(!!product);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::rfc1034Identifier()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("rfc1034identifier.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value(QLatin1String("this-has-special-characters-"
- "uh-oh-Undersc0r3s-Are.Bad"));
- QVERIFY(!!product);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::conditionalDepends()
-{
- bool exceptionCaught = false;
- ResolvedProductPtr product;
- ResolvedModuleConstPtr dependency;
- try {
- defaultParameters.setProjectFilePath(testProject("conditionaldepends.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
-
- product = products.value("conditionaldepends_derived");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(!!dependency);
-
- product = products.value("conditionaldepends_derived_false");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "dummy");
- QCOMPARE(dependency, ResolvedModuleConstPtr());
-
- product = products.value("product_props_true");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(!!dependency);
-
- product = products.value("product_props_false");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "dummy");
- QCOMPARE(dependency, ResolvedModuleConstPtr());
-
- product = products.value("project_props_true");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(!!dependency);
-
- product = products.value("project_props_false");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "dummy");
- QCOMPARE(dependency, ResolvedModuleConstPtr());
-
- product = products.value("module_props_true");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "dummy2");
- QVERIFY(!!dependency);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(!!dependency);
-
- product = products.value("module_props_false");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "dummy2");
- QVERIFY(!!dependency);
- dependency = findModuleByName(product, "dummy");
- QCOMPARE(dependency, ResolvedModuleConstPtr());
-
- product = products.value("contradictory_conditions1");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(!!dependency);
-
- product = products.value("contradictory_conditions2");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(!!dependency);
-
- product = products.value("unknown_dependency_condition_false");
- QVERIFY(!!product);
- dependency = findModuleByName(product, "doesonlyexistifhellfreezesover");
- QVERIFY(!dependency);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::delayedError()
-{
- QFETCH(bool, productEnabled);
- try {
- QFETCH(QString, projectFileName);
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject(projectFileName.toLatin1()));
- QVariantMap overriddenValues;
- overriddenValues.insert("project.enableProduct", productEnabled);
- params.setOverriddenValues(overriddenValues);
- project = loader->loadProject(params);
- QCOMPARE(productEnabled, false);
- QVERIFY(!!project);
- QCOMPARE(project->products.count(), 1);
- const ResolvedProductConstPtr theProduct = productsFromProject(project).value("theProduct");
- QVERIFY(!!theProduct);
- QCOMPARE(theProduct->enabled, false);
- } catch (const ErrorInfo &e) {
- if (!productEnabled)
- qDebug() << e.toString();
- QCOMPARE(productEnabled, true);
- }
-}
-
-void TestLanguage::delayedError_data()
-{
- QTest::addColumn<QString>("projectFileName");
- QTest::addColumn<bool>("productEnabled");
- QTest::newRow("product enabled, module validation error")
- << "delayed-error/validation.qbs" << true;
- QTest::newRow("product disabled, module validation error")
- << "delayed-error/validation.qbs" << false;
- QTest::newRow("product enabled, module not found")
- << "delayed-error/nonexisting.qbs" << true;
- QTest::newRow("product disabled, module not found")
- << "delayed-error/nonexisting.qbs" << false;
-}
-
-void qbs::Internal::TestLanguage::dependencyOnAllProfiles()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("dependencyOnAllProfiles.qbs"));
- TemporaryProfile p1("p1", m_settings);
- p1.p.setValue("qbs.architecture", "arch1");
- TemporaryProfile p2("p2", m_settings);
- p2.p.setValue("qbs.architecture", "arch2");
- QVariantMap overriddenValues;
- overriddenValues.insert("project.profile1", "p1");
- overriddenValues.insert("project.profile2", "p2");
- params.setOverriddenValues(overriddenValues);
- project = loader->loadProject(params);
- QVERIFY(!!project);
- QCOMPARE(project->products.count(), 3);
- const ResolvedProductConstPtr mainProduct = productsFromProject(project).value("main");
- QVERIFY(!!mainProduct);
- QCOMPARE(mainProduct->dependencies.count(), 2);
- foreach (const ResolvedProductConstPtr &p, mainProduct->dependencies) {
- QCOMPARE(p->name, QLatin1String("dep"));
- QVERIFY(p->profile == "p1" || p->profile == "p2");
- }
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::derivedSubProject()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("derived-sub-project/project.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(!!project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::enumerateProjectProperties()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("enum-project-props.qbs"));
- auto project = loader->loadProject(params);
- QVERIFY(!!project);
- auto products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- auto product = products.values().first();
- auto files = product->groups.first()->allFiles();
- QCOMPARE(product->groups.count(), 1);
- QCOMPARE(files.count(), 1);
- auto fileName = FileInfo::fileName(files.first()->absoluteFilePath);
- QCOMPARE(fileName, QString("dummy.txt"));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::defaultValue()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("defaultvalue/egon.qbs"));
- QFETCH(QString, prop1Value);
- QVariantMap overridden;
- if (!prop1Value.isEmpty())
- overridden.insert("modules.lower.prop1", prop1Value);
- params.setOverriddenValues(overridden);
- TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 2);
- const ResolvedProductPtr product = products.value("egon");
- QVERIFY(!!product);
- QStringList propertyName = QStringList() << "modules" << "lower" << "prop2";
- QVariant propertyValue = product->moduleProperties->property(propertyName);
- QFETCH(QVariant, expectedProp2Value);
- QCOMPARE(propertyValue, expectedProp2Value);
- propertyName = QStringList() << "modules" << "lower" << "listProp";
- propertyValue = product->moduleProperties->property(propertyName);
- QFETCH(QVariant, expectedListPropValue);
- QCOMPARE(propertyValue.toStringList(), expectedListPropValue.toStringList());
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::defaultValue_data()
-{
- QTest::addColumn<QString>("prop1Value");
- QTest::addColumn<QVariant>("expectedProp2Value");
- QTest::addColumn<QVariant>("expectedListPropValue");
- QTest::newRow("controlling property with random value") << "random" << QVariant("withoutBlubb")
- << QVariant(QStringList({"other"}));
- QTest::newRow("controlling property with blubb value") << "blubb" << QVariant("withBlubb")
- << QVariant(QStringList({"blubb", "other"}));
- QTest::newRow("controlling property with egon value") << "egon" << QVariant("withEgon")
- << QVariant(QStringList({"egon", "other"}));
- QTest::newRow("controlling property not overwritten") << "" << QVariant("withBlubb")
- << QVariant(QStringList({"blubb", "other"}));
-}
-
-void TestLanguage::environmentVariable()
-{
- bool exceptionCaught = false;
- try {
- // Create new environment:
- const QString varName = QLatin1String("PRODUCT_NAME");
- const QString productName = QLatin1String("MyApp") + QString::number(qrand());
- QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
- env.insert(varName, productName);
-
- QProcessEnvironment origEnv = defaultParameters.environment(); // store orig environment
-
- defaultParameters.setEnvironment(env);
- defaultParameters.setProjectFilePath(testProject("environmentvariable.qbs"));
- project = loader->loadProject(defaultParameters);
-
- defaultParameters.setEnvironment(origEnv); // reset environment
-
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value(productName);
- QVERIFY(!!product);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::erroneousFiles_data()
-{
- QTest::addColumn<QString>("errorMessage");
- QTest::newRow("unknown_module")
- << "Dependency 'neitherModuleNorProduct' not found";
- QTest::newRow("multiple_exports")
- << "Multiple Export items in one product are prohibited.";
- QTest::newRow("multiple_properties_in_subproject")
- << "Multiple instances of item 'Properties' found where at most one "
- "is allowed.";
- QTest::newRow("importloop1")
- << "Loop detected when importing";
- QTest::newRow("nonexistentouter")
- << "Can't find variable: outer";
- QTest::newRow("invalid_file")
- << "does not exist";
- QTest::newRow("invalid-parameter-rhs")
- << "ReferenceError: Can't find variable: access";
- QTest::newRow("invalid-parameter-type")
- << "Value assigned to property 'stringParameter' does not have type 'string'.";
- QTest::newRow("invalid_property_type")
- << "Unknown type 'nonsense' in property declaration.";
- QTest::newRow("reserved_name_in_import")
- << "Cannot reuse the name of built-in extension 'TextFile'.";
- QTest::newRow("throw_in_property_binding")
- << "something is wrong";
- QTest::newRow("dependency_cycle")
- << "Cyclic dependencies detected.";
- QTest::newRow("dependency_cycle2")
- << "Cyclic dependencies detected.";
- QTest::newRow("dependency_cycle3")
- << "Cyclic dependencies detected.";
- QTest::newRow("dependency_cycle4")
- << "Cyclic dependencies detected.";
- QTest::newRow("references_cycle")
- << "Cycle detected while referencing file 'references_cycle.qbs'.";
- QTest::newRow("subproject_cycle")
- << "Cycle detected while loading subproject file 'subproject_cycle.qbs'.";
- QTest::newRow("invalid_stringlist_element")
- << "Element at index 1 of list property 'files' does not have string type.";
- QTest::newRow("undefined_stringlist_element")
- << "Element at index 1 of list property 'files' is undefined. String expected.";
- QTest::newRow("undeclared_item")
- << "Item 'cpp' is not declared.";
- QTest::newRow("undeclared-parameter1")
- << "Parameter 'prefix2.suffix.nope' is not declared.";
- QTest::newRow("undeclared-parameter2")
- << "Cannot set parameter 'foo.bar', "
- "because 'myproduct' does not have a dependency on 'foo'.";
- QTest::newRow("undeclared_property_wrapper")
- << "Property 'doesntexist' is not declared.";
- QTest::newRow("undeclared_property_in_export_item")
- << "Property 'blubb' is not declared.";
- QTest::newRow("undeclared_property_in_export_item2")
- << "Item 'something' is not declared.";
- QTest::newRow("undeclared_property_in_export_item3")
- << "Property 'blubb' is not declared.";
- QTest::newRow("unknown_item_type")
- << "Unexpected item type 'Narf'";
- QTest::newRow("invalid_child_item_type")
- << "Items of type 'Project' cannot contain items of type 'Depends'.";
- QTest::newRow("conflicting_fileTagsFilter")
- << "Conflicting fileTagsFilter in Group items";
- QTest::newRow("duplicate_sources")
- << "Duplicate source file '.*main.cpp'"
- ".*duplicate_sources.qbs:4:12.*duplicate_sources.qbs:6:16.";
- QTest::newRow("duplicate_sources_wildcards")
- << "Duplicate source file '.*duplicate_sources_wildcards.qbs'"
- ".*duplicate_sources_wildcards.qbs:4:12"
- ".*duplicate_sources_wildcards.qbs:6:16.";
- QTest::newRow("oldQbsVersion")
- << "The project requires at least qbs version \\d+\\.\\d+.\\d+, "
- "but this is qbs version " QBS_VERSION ".";
- QTest::newRow("wrongQbsVersionFormat")
- << "The value '.*' of Project.minimumQbsVersion is not a valid version string.";
- QTest::newRow("properties-item-with-invalid-condition")
- << "TypeError: Result of expression 'cpp.nonexistingproperty'";
- QTest::newRow("misused-inherited-property") << "Binding to non-item property";
- QTest::newRow("undeclared_property_in_Properties_item") << "Item 'blubb' is not declared";
- QTest::newRow("same-module-prefix1") << "The name of module 'prefix1' is equal to the first "
- "component of the name of module 'prefix1.suffix'";
- QTest::newRow("same-module-prefix2") << "The name of module 'prefix2' is equal to the first "
- "component of the name of module 'prefix2.suffix'";
- QTest::newRow("conflicting-properties-in-export-items")
- << "Export item in inherited item redeclares property 'theProp' with different type.";
- QTest::newRow("invalid-property-option")
- << "PropertyOptions item refers to non-existing property 's0meProp'";
- QTest::newRow("missing-colon")
- << "Invalid item 'cpp.dynamicLibraries'. Did you mean to set a module property?";
- QTest::newRow("wrong-toplevel-item")
- << "wrong-toplevel-item.qbs:3:1.*The top-level item must be of type 'Project' or "
- "'Product', but it is of type 'Artifact'.";
- QTest::newRow("module-depends-on-product")
- << "module-with-product-dependency.qbs:4:5.*Modules cannot depend on products.";
- QTest::newRow("overwrite-inherited-readonly-property")
- << "overwrite-inherited-readonly-property.qbs"
- ":4:21.*Cannot set read-only property 'readOnlyString'.";
- QTest::newRow("overwrite-readonly-module-property")
- << "overwrite-readonly-module-property.qbs"
- ":5:30.*Cannot set read-only property 'readOnlyString'.";
- QTest::newRow("mismatching-multiplex-dependency")
- << "mismatching-multiplex-dependency.qbs:9:5 Dependency from product 'b' to "
- "product 'a' not fulfilled.\nNo product 'a' found with a matching multiplex "
- "configuration:\n\tqbs.architecture: mips";
-}
-
-void TestLanguage::erroneousFiles()
-{
- QFETCH(QString, errorMessage);
- QString fileName = QString::fromLocal8Bit(QTest::currentDataTag()) + QLatin1String(".qbs");
- try {
- defaultParameters.setProjectFilePath(testProject("/erroneous/") + fileName);
- loader->loadProject(defaultParameters);
- } catch (const ErrorInfo &e) {
- if (!e.toString().contains(QRegExp(errorMessage))) {
- qDebug() << "Message: " << e.toString();
- qDebug() << "Expected: " << errorMessage;
- QFAIL("Unexpected error message.");
- }
- return;
- }
- QEXPECT_FAIL("undeclared_property_in_Properties_item", "Too expensive to check", Continue);
- QVERIFY(!"No error thrown on invalid input.");
-}
-
-void TestLanguage::exports()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("exports.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 17);
- ResolvedProductPtr product;
- product = products.value("myapp");
- QVERIFY(!!product);
- QStringList propertyName = QStringList() << "modules" << "dummy" << "defines";
- QVariant propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYAPP" << "USE_MYLIB"
- << "USE_MYLIB2");
- propertyName = QStringList() << "modules" << "dummy" << "includePaths";
- QVariantList propertyValues = product->moduleProperties->property(propertyName).toList();
- QCOMPARE(propertyValues.count(), 3);
- QVERIFY(propertyValues.at(0).toString().endsWith("/app"));
- QVERIFY(propertyValues.at(1).toString().endsWith("/subdir/lib"));
- QVERIFY(propertyValues.at(2).toString().endsWith("/subdir2/lib"));
-
- QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
- QString("myapp"));
-
- product = products.value("mylib");
- QVERIFY(!!product);
- propertyName = QStringList() << "modules" << "dummy" << "defines";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYLIB");
-
- product = products.value("mylib2");
- QVERIFY(!!product);
- propertyName = QStringList() << "modules" << "dummy" << "defines";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYLIB2");
-
- product = products.value("A");
- QVERIFY(!!product);
- QVERIFY(product->dependencies.contains(products.value("B")));
- QVERIFY(product->dependencies.contains(products.value("C")));
- QVERIFY(product->dependencies.contains(products.value("D")));
- product = products.value("B");
- QVERIFY(!!product);
- QVERIFY(product->dependencies.isEmpty());
- product = products.value("C");
- QVERIFY(!!product);
- QVERIFY(product->dependencies.isEmpty());
- product = products.value("D");
- QVERIFY(!!product);
- QVERIFY(product->dependencies.isEmpty());
-
- product = products.value("myapp2");
- QVERIFY(!!product);
- propertyName = QStringList() << "modules" << "dummy" << "cFlags";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList()
- << "BASE_PRODUCTWITHINHERITEDEXPORTITEM"
- << "PRODUCT_PRODUCTWITHINHERITEDEXPORTITEM");
- propertyName = QStringList() << "modules" << "dummy" << "cxxFlags";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList() << "-bar");
- propertyName = QStringList() << "modules" << "dummy" << "defines";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList() << "ABC");
- QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
- QString("myapp2"));
- QCOMPARE(product->moduleProperties->moduleProperty("dummy",
- "upperCaseProductName").toString(), QString("MYAPP2"));
-
- // Check whether we're returning incorrect cached values.
- product = products.value("myapp3");
- QVERIFY(!!product);
- QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
- QString("myapp3"));
- QCOMPARE(product->moduleProperties->moduleProperty("dummy",
- "upperCaseProductName").toString(), QString("MYAPP3"));
-
- // Verify we refer to the right "project" variable.
- product = products.value("sub p2");
- QVERIFY(!!product);
- QCOMPARE(product->moduleProperties->moduleProperty("dummy", "someString").toString(),
- QString("sub1"));
-
- product = products.value("libE");
- QVERIFY(!!product);
- propertyName = QStringList() << "modules" << "dummy" << "defines";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(),
- QStringList() << "LIBA" << "LIBB" << "LIBC" << "LIBD");
- propertyName = QStringList() << "modules" << "dummy" << "productName";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toString(), QString("libE"));
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::fileContextProperties()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("filecontextproperties.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value("product1");
- QVERIFY(!!product);
- QVariantMap cfg = product->productProperties;
- QCOMPARE(cfg.value("narf").toString(), defaultParameters.projectFilePath());
- QString dirPath = QFileInfo(defaultParameters.projectFilePath()).absolutePath();
- QCOMPARE(cfg.value("zort").toString(), dirPath);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::getNativeSetting()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("getNativeSetting.qbs"));
- project = loader->loadProject(defaultParameters);
-
- QString expectedTargetName;
- if (HostOsInfo::isMacosHost())
- expectedTargetName = QLatin1String("Mac OS X");
- else if (HostOsInfo::isWindowsHost())
- expectedTargetName = QLatin1String("Windows");
- else
- expectedTargetName = QLatin1String("Unix");
-
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products;
- for (const ResolvedProductPtr &product : project->allProducts())
- products.insert(product->targetName, product);
- ResolvedProductPtr product = products.value(expectedTargetName);
- QVERIFY(!!product);
- ResolvedProductPtr product2 = products.value(QLatin1String("fallback"));
- QVERIFY(!!product2);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::groupConditions_data()
-{
- QTest::addColumn<int>("groupCount");
- QTest::addColumn<QList<bool> >("groupEnabled");
- QTest::newRow("init") << 0 << QList<bool>();
- QTest::newRow("no_condition_no_group")
- << 1 << (QList<bool>() << true);
- QTest::newRow("no_condition")
- << 2 << (QList<bool>() << true << true);
- QTest::newRow("true_condition")
- << 2 << (QList<bool>() << true << true);
- QTest::newRow("false_condition")
- << 2 << (QList<bool>() << true << false);
- QTest::newRow("true_condition_from_product")
- << 2 << (QList<bool>() << true << true);
- QTest::newRow("true_condition_from_project")
- << 2 << (QList<bool>() << true << true);
- QTest::newRow("condition_accessing_module_property")
- << 2 << (QList<bool>() << true << false);
- QTest::newRow("cleanup") << 0 << QList<bool>();
-}
-
-void TestLanguage::groupConditions()
-{
- HANDLE_INIT_CLEANUP_DATATAGS("groupconditions.qbs");
- QFETCH(int, groupCount);
- QFETCH(QList<bool>, groupEnabled);
- QCOMPARE(groupCount, groupEnabled.count());
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
- ResolvedProductPtr product = products.value(productName);
- QVERIFY(!!product);
- QCOMPARE(product->name, productName);
- QCOMPARE(product->groups.count(), groupCount);
- for (int i = 0; i < groupCount; ++i) {
- if (product->groups.at(i)->enabled != groupEnabled.at(i)) {
- QFAIL(qPrintable(
- QString("groups.at(%1)->enabled != %2").arg(i).arg(groupEnabled.at(i))));
- }
- }
-}
-
-void TestLanguage::groupName()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("groupname.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 2);
-
- ResolvedProductPtr product = products.value("MyProduct");
- QVERIFY(!!product);
- QCOMPARE(product->groups.count(), 2);
- GroupConstPtr group = product->groups.at(0);
- QVERIFY(!!group);
- QCOMPARE(group->name, QString("MyProduct"));
- group = product->groups.at(1);
- QVERIFY(!!group);
- QCOMPARE(group->name, QString("MyProduct.MyGroup"));
-
- product = products.value("My2ndProduct");
- QVERIFY(!!product);
- QCOMPARE(product->groups.count(), 3);
- group = product->groups.at(0);
- QVERIFY(!!group);
- QCOMPARE(group->name, QString("My2ndProduct"));
- group = product->groups.at(1);
- QVERIFY(!!group);
- QCOMPARE(group->name, QString("My2ndProduct.MyGroup"));
- group = product->groups.at(2);
- QVERIFY(!!group);
- QCOMPARE(group->name, QString("Group 2"));
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::homeDirectory()
-{
- try {
- defaultParameters.setProjectFilePath(testProject("homeDirectory.qbs"));
- ResolvedProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
-
- ResolvedProductPtr product = products.value("home");
- QVERIFY(!!product);
-
- QDir dir = QDir::home();
- QCOMPARE(product->productProperties.value("home").toString(), dir.path());
- QCOMPARE(product->productProperties.value("homeSlash").toString(), dir.path());
-
- dir.cdUp();
- QCOMPARE(product->productProperties.value("homeUp").toString(), dir.path());
-
- dir = QDir::home();
- QCOMPARE(product->productProperties.value("homeFile").toString(),
- dir.filePath("a"));
-
- QCOMPARE(product->productProperties.value("bogus1").toString(),
- FileInfo::resolvePath(product->sourceDirectory, QLatin1String("a~b")));
- QCOMPARE(product->productProperties.value("bogus2").toString(),
- FileInfo::resolvePath(product->sourceDirectory, QLatin1String("a/~/bb")));
- QCOMPARE(product->productProperties.value("user").toString(),
- FileInfo::resolvePath(product->sourceDirectory, QLatin1String("~foo/bar")));
- }
- catch (const ErrorInfo &e) {
- qDebug() << e.toString();
- }
-}
-
-void TestLanguage::identifierSearch_data()
-{
- QTest::addColumn<bool>("expectedHasNarf");
- QTest::addColumn<bool>("expectedHasZort");
- QTest::addColumn<QString>("sourceCode");
- QTest::newRow("no narf, no zort") << false << false << QString(
- "Product {\n"
- " name: {\n"
- " var foo = 'bar';\n"
- " console.info(foo);\n"
- " return foo;\n"
- " }\n"
- "}\n");
- QTest::newRow("narf, no zort") << true << false << QString(
- "Product {\n"
- " name: {\n"
- " var foo = 'zort';\n"
- " console.info(narf + foo);\n"
- " return foo;\n"
- " }\n"
- "}\n");
- QTest::newRow("no narf, zort") << false << true << QString(
- "Product {\n"
- " name: {\n"
- " var foo = 'narf';\n"
- " console.info(zort + foo);\n"
- " return foo;\n"
- " }\n"
- "}\n");
- QTest::newRow("narf, zort") << true << true << QString(
- "Product {\n"
- " name: {\n"
- " var foo = narf;\n"
- " foo = foo + zort;\n"
- " return foo;\n"
- " }\n"
- "}\n");
- QTest::newRow("2 narfs, 1 zort") << true << true << QString(
- "Product {\n"
- " name: {\n"
- " var foo = narf;\n"
- " foo = narf + foo + zort;\n"
- " return foo;\n"
- " }\n"
- "}\n");
-}
-
-void TestLanguage::identifierSearch()
-{
- QFETCH(bool, expectedHasNarf);
- QFETCH(bool, expectedHasZort);
- QFETCH(QString, sourceCode);
-
- bool hasNarf = !expectedHasNarf;
- bool hasZort = !expectedHasZort;
- IdentifierSearch isearch;
- isearch.add("narf", &hasNarf);
- isearch.add("zort", &hasZort);
-
- QbsQmlJS::Engine engine;
- QbsQmlJS::Lexer lexer(&engine);
- lexer.setCode(sourceCode, 1);
- QbsQmlJS::Parser parser(&engine);
- QVERIFY(parser.parse());
- QVERIFY(parser.ast());
- isearch.start(parser.ast());
- QCOMPARE(hasNarf, expectedHasNarf);
- QCOMPARE(hasZort, expectedHasZort);
-}
-
-void TestLanguage::idUsage()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("idusage.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 4);
- QVERIFY(products.contains("product1_1"));
- QVERIFY(products.contains("product2_2"));
- QVERIFY(products.contains("product3_3"));
- ResolvedProductPtr product4 = products.value("product4_4");
- QVERIFY(!!product4);
- QEXPECT_FAIL("", "QBS-1016", Continue);
- QCOMPARE(product4->productProperties.value("productName").toString(), product4->name);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QVERIFY(!exceptionCaught);
-}
-
-void TestLanguage::idUniqueness()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("id-uniqueness.qbs"));
- loader->loadProject(defaultParameters);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- const QList<ErrorItem> items = e.items();
- QCOMPARE(items.count(), 3);
- QCOMPARE(items.at(0).toString(), QString::fromUtf8("The id 'baseProduct' is not unique."));
- QVERIFY(items.at(1).toString().contains("id-uniqueness.qbs:6:5 First occurrence is here."));
- QVERIFY(items.at(2).toString().contains("id-uniqueness.qbs:9:5 Next occurrence is here."));
- }
- QVERIFY(exceptionCaught);
-}
-
-void TestLanguage::importCollection()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("import-collection/project.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const ResolvedProductConstPtr product = products.value("da product");
- QCOMPARE(product->productProperties.value("targetName").toString(),
- QLatin1String("C1f1C1f2C2f1C2f2"));
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QVERIFY(!exceptionCaught);
-}
-
-void TestLanguage::invalidBindingInDisabledItem()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("invalidBindingInDisabledItem.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 2);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QVERIFY(!exceptionCaught);
-}
-
-class JSSourceValueCreator
-{
- FileContextPtr m_fileContext;
- QList<QString *> m_strings;
-public:
- JSSourceValueCreator(const FileContextPtr &fileContext)
- : m_fileContext(fileContext)
- {
- }
-
- ~JSSourceValueCreator()
- {
- qDeleteAll(m_strings);
- }
-
- JSSourceValuePtr create(const QString &sourceCode)
- {
- JSSourceValuePtr value = JSSourceValue::create();
- value->setFile(m_fileContext);
- QString *str = new QString(sourceCode);
- m_strings += str;
- value->setSourceCode(QStringRef(str));
- return value;
- }
-};
-
-void TestLanguage::itemPrototype()
-{
- FileContextPtr fileContext = FileContext::create();
- fileContext->setFilePath("/dev/null");
- JSSourceValueCreator sourceValueCreator(fileContext);
- ItemPool pool;
- Item *proto = Item::create(&pool, ItemType::Product);
- proto->setProperty("x", sourceValueCreator.create("1"));
- proto->setProperty("y", sourceValueCreator.create("1"));
- Item *item = Item::create(&pool, ItemType::Product);
- item->setPrototype(proto);
- item->setProperty("y", sourceValueCreator.create("x + 1"));
- item->setProperty("z", sourceValueCreator.create("2"));
-
- Evaluator evaluator(m_engine);
- QCOMPARE(evaluator.property(proto, "x").toVariant().toInt(), 1);
- QCOMPARE(evaluator.property(proto, "y").toVariant().toInt(), 1);
- QVERIFY(!evaluator.property(proto, "z").isValid());
- QCOMPARE(evaluator.property(item, "x").toVariant().toInt(), 1);
- QCOMPARE(evaluator.property(item, "y").toVariant().toInt(), 2);
- QCOMPARE(evaluator.property(item, "z").toVariant().toInt(), 2);
-}
-
-void TestLanguage::itemScope()
-{
- FileContextPtr fileContext = FileContext::create();
- fileContext->setFilePath("/dev/null");
- JSSourceValueCreator sourceValueCreator(fileContext);
- ItemPool pool;
- Item *scope1 = Item::create(&pool, ItemType::Scope);
- scope1->setProperty("x", sourceValueCreator.create("1"));
- Item *scope2 = Item::create(&pool, ItemType::Scope);
- scope2->setScope(scope1);
- scope2->setProperty("y", sourceValueCreator.create("x + 1"));
- Item *item = Item::create(&pool, ItemType::Scope);
- item->setScope(scope2);
- item->setProperty("z", sourceValueCreator.create("x + y"));
-
- Evaluator evaluator(m_engine);
- QCOMPARE(evaluator.property(scope1, "x").toVariant().toInt(), 1);
- QCOMPARE(evaluator.property(scope2, "y").toVariant().toInt(), 2);
- QVERIFY(!evaluator.property(scope2, "x").isValid());
- QCOMPARE(evaluator.property(item, "z").toVariant().toInt(), 3);
-}
-
-void TestLanguage::jsExtensions()
-{
- QFile file(testProject("jsextensions.js"));
- QVERIFY(file.open(QFile::ReadOnly));
- QTextStream ts(&file);
- QString code = ts.readAll();
- QVERIFY(!code.isEmpty());
- QScriptValue evaluated = m_engine->evaluate(code, file.fileName(), 1);
- if (m_engine->hasErrorOrException(evaluated)) {
- qDebug() << m_engine->uncaughtExceptionBacktrace();
- QFAIL(qPrintable(m_engine->lastErrorString(evaluated)));
- }
-}
-
-void TestLanguage::jsImportUsedInMultipleScopes_data()
-{
- QTest::addColumn<QString>("buildVariant");
- QTest::addColumn<QString>("expectedProductName");
- QTest::newRow("debug") << QString("debug") << QString("MyProduct_debug");
- QTest::newRow("release") << QString("release") << QString("MyProduct");
-}
-
-void TestLanguage::jsImportUsedInMultipleScopes()
-{
- QFETCH(QString, buildVariant);
- QFETCH(QString, expectedProductName);
-
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("jsimportsinmultiplescopes.qbs"));
- params.setOverriddenValues({std::make_pair(QLatin1String("qbs.buildVariant"),
- buildVariant)});
- params.expandBuildConfiguration();
- TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- ResolvedProductPtr product = products.values().first();
- QVERIFY(!!product);
- QCOMPARE(product->name, expectedProductName);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QVERIFY(!exceptionCaught);
-}
-
-void TestLanguage::moduleProperties_data()
-{
- QTest::addColumn<QString>("propertyName");
- QTest::addColumn<QVariant>("expectedValue");
- QTest::newRow("init") << QString() << QVariant();
- QTest::newRow("merge_lists")
- << "defines"
- << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK");
- QTest::newRow("merge_lists_and_values")
- << "defines"
- << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK");
- QTest::newRow("merge_lists_with_duplicates")
- << "cxxFlags"
- << QVariant(QStringList() << "-foo" << "BAR" << "-foo" << "BAZ");
- QTest::newRow("merge_lists_with_prototype_values")
- << "rpaths"
- << QVariant(QStringList() << "/opt/qt/lib" << "$ORIGIN");
- QTest::newRow("list_property_that_references_product")
- << "listProp"
- << QVariant(QStringList() << "x" << "123");
- QTest::newRow("list_property_depending_on_overridden_property")
- << "listProp2"
- << QVariant(QStringList() << "PRODUCT_STUFF" << "DEFAULT_STUFF" << "EXTRA_STUFF");
- QTest::newRow("overridden_list_property")
- << "listProp"
- << QVariant(QStringList() << "PRODUCT_STUFF");
- QTest::newRow("shadowed-list-property")
- << "defines"
- << QVariant(QStringList() << "MyProject" << "shadowed-list-property");
- QTest::newRow("shadowed-scalar-property")
- << "someString"
- << QVariant(QString("MyProject_shadowed-scalar-property"));
- QTest::newRow("cleanup") << QString() << QVariant();
-}
-
-void TestLanguage::moduleProperties()
-{
- HANDLE_INIT_CLEANUP_DATATAGS("moduleproperties.qbs");
- QFETCH(QString, propertyName);
- QFETCH(QVariant, expectedValue);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
- ResolvedProductPtr product = products.value(productName);
- QVERIFY(!!product);
- const QVariant value = product->moduleProperties->moduleProperty("dummy", propertyName);
- QCOMPARE(value, expectedValue);
-}
-
-void TestLanguage::modulePropertiesInGroups()
-{
- defaultParameters.setProjectFilePath(testProject("modulepropertiesingroups.qbs"));
- bool exceptionCaught = false;
- try {
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const ResolvedProductPtr product = products.value("grouptest");
- QVERIFY(!!product);
- GroupConstPtr g1;
- GroupConstPtr g11;
- GroupConstPtr g12;
- GroupConstPtr g2;
- GroupConstPtr g21;
- GroupConstPtr g211;
- foreach (const GroupConstPtr &g, product->groups) {
- if (g->name == "g1")
- g1= g;
- else if (g->name == "g2")
- g2 = g;
- else if (g->name == "g1.1")
- g11 = g;
- else if (g->name == "g1.2")
- g12 = g;
- else if (g->name == "g2.1")
- g21 = g;
- else if (g->name == "g2.1.1")
- g211 = g;
- }
- QVERIFY(!!g1);
- QVERIFY(!!g2);
- QVERIFY(!!g11);
- QVERIFY(!!g12);
- QVERIFY(!!g21);
- QVERIFY(!!g211);
-
- const QVariantMap productProps = product->moduleProperties->value();
- const auto &productGmod1List1 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(productGmod1List1, QStringList() << "gmod1_list1_proto" << "gmod1_string_proto");
- const auto &productGmod1List2 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(productGmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
- << "gmod1_list2_proto");
- const auto &productGmod1List3 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list3")
- .toStringList();
- QCOMPARE(productGmod1List3, QStringList() << "product" << "gmod1_string_proto");
- const int productP0 = moduleProperty(productProps, "gmod.gmod1", "p0").toInt();
- QCOMPARE(productP0, 1);
- const int productDepProp = moduleProperty(productProps, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(productDepProp, 0);
- const auto &productGmod2String = moduleProperty(productProps, "gmod2", "gmod2_string")
- .toString();
- QCOMPARE(productGmod2String, QString("gmod1_string_proto"));
- const auto &productGmod2List = moduleProperty(productProps, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(productGmod2List, QStringList() << "gmod1_string_proto" << "commonName_in_gmod1"
- << "gmod4_string_proto_gmod3_string_proto" << "gmod3_string_proto"
- << "gmod2_list_proto");
-
- const QVariantMap g1Props = g1->properties->value();
- const auto &g1Gmod1List1 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g1Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1");
- const auto &g1Gmod1List2 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(g1Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
- << "gmod1_list2_proto" << "g1");
- const auto &g1Gmod1List3 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list3")
- .toStringList();
- QCOMPARE(g1Gmod1List3, QStringList() << "product" << "g1");
- const int g1P0 = moduleProperty(g1Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g1P0, 3);
- const int g1DepProp = moduleProperty(g1Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g1DepProp, 1);
- const auto &g1Gmod2String = moduleProperty(g1Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g1Gmod2String, QString("g1"));
- const auto &g1Gmod2List = moduleProperty(g1Props, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(g1Gmod2List, QStringList() << "g1" << "commonName_in_gmod1" << "g1_gmod4_g1_gmod3"
- << "g1_gmod3" << "gmod2_list_proto");
-
- const QVariantMap g11Props = g11->properties->value();
- const auto &g11Gmod1List1 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g11Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1.1");
- const auto &g11Gmod1List2 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(g11Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
- << "gmod1_list2_proto" << "g1" << "g1.1");
- const auto &g11Gmod1List3 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list3")
- .toStringList();
- QCOMPARE(g11Gmod1List3, QStringList() << "product" << "g1.1");
- const int g11P0 = moduleProperty(g11Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g11P0, 5);
- const int g11DepProp = moduleProperty(g11Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g11DepProp, 2);
- const auto &g11Gmod2String = moduleProperty(g11Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g11Gmod2String, QString("g1.1"));
- const auto &g11Gmod2List = moduleProperty(g11Props, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(g11Gmod2List, QStringList() << "g1.1" << "commonName_in_gmod1"
- << "g1.1_gmod4_g1.1_gmod3" << "g1.1_gmod3" << "gmod2_list_proto");
-
- const QVariantMap g12Props = g12->properties->value();
- const auto &g12Gmod1List1 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g12Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1.2");
- const auto &g12Gmod1List2 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(g12Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
- << "gmod1_list2_proto" << "g1" << "g1.2");
- const auto &g12Gmod1List3 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list3")
- .toStringList();
- QCOMPARE(g12Gmod1List3, QStringList() << "product" << "g1.2");
- const int g12P0 = moduleProperty(g12Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g12P0, 9);
- const int g12DepProp = moduleProperty(g12Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g12DepProp, 1);
- const auto &g12Gmod2String = moduleProperty(g12Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g12Gmod2String, QString("g1.2"));
- const auto &g12Gmod2List = moduleProperty(g12Props, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(g12Gmod2List, QStringList() << "g1.2" << "commonName_in_gmod1"
- << "g1_gmod4_g1.2_gmod3" << "g1.2_gmod3" << "gmod2_list_proto");
-
- const QVariantMap g2Props = g2->properties->value();
- const auto &g2Gmod1List1 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g2Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
- const auto &g2Gmod1List2 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(g2Gmod1List2, QStringList() << "grouptest" << "g2" << "gmod1_list2_proto");
- const int g2P0 = moduleProperty(g2Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g2P0, 6);
- const int g2DepProp = moduleProperty(g2Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g2DepProp, 2);
- const auto &g2Gmod2String = moduleProperty(g2Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g2Gmod2String, QString("g2"));
- const auto &g2Gmod2List = moduleProperty(g2Props, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(g2Gmod2List, QStringList() << "g2" << "commonName_in_gmod1" << "g2_gmod4_g2_gmod3"
- << "g2_gmod3" << "gmod2_list_proto");
-
- const QVariantMap g21Props = g21->properties->value();
- const auto &g21Gmod1List1 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g21Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
- const auto &g21Gmod1List2 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QEXPECT_FAIL(0, "no re-eval when no module props set", Continue);
- QCOMPARE(g21Gmod1List2, QStringList() << "grouptest" << "g2.1" << "gmod1_list2_proto");
- const int g21P0 = moduleProperty(g21Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g21P0, 6);
- const int g21DepProp = moduleProperty(g21Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g21DepProp, 2);
- const auto &g21Gmod2String = moduleProperty(g21Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g21Gmod2String, QString("g2"));
- const auto &g21Gmod2List = moduleProperty(g21Props, "gmod2", "gmod2_list")
- .toStringList();
- QEXPECT_FAIL(0, "no re-eval when no module props set", Continue);
- QCOMPARE(g21Gmod2List, QStringList() << "g2" << "commonName_in_gmod1"
- << "g2.1_gmod4_g2.1_gmod3" << "g2.1_gmod3" << "gmod2_list_proto");
-
- const QVariantMap g211Props = g211->properties->value();
- const auto &g211Gmod1List1 = moduleProperty(g211Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g211Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
- const auto &g211Gmod1List2 = moduleProperty(g211Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(g211Gmod1List2, QStringList() << "g2.1.1");
- const int g211P0 = moduleProperty(g211Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g211P0, 17);
- const int g211DepProp = moduleProperty(g211Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g211DepProp, 2);
- const auto &g211Gmod2String
- = moduleProperty(g211Props, "gmod2", "gmod2_string").toString();
- QEXPECT_FAIL(0, "re-eval not triggered", Continue);
- QCOMPARE(g211Gmod2String, QString("g2.1.1"));
- const auto &g211Gmod2List = moduleProperty(g211Props, "gmod2", "gmod2_list")
- .toStringList();
- QEXPECT_FAIL(0, "re-eval not triggered", Continue);
- QCOMPARE(g211Gmod2List, QStringList() << "g2.1.1" << "commonName_in_gmod1"
- << "g2.1.1_gmod4_g2.1.1_gmod3" << "g2.1.1_gmod3" << "gmod2_list_proto");
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::modulePropertyOverridesPerProduct()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setOverriddenValues({
- std::make_pair("modules.dummy.someString", "m"),
- std::make_pair("products.b.dummy.someString", "b"),
- std::make_pair("products.c.dummy.someString", "c")
- });
- params.setProjectFilePath(
- testProject("module-property-overrides-per-product.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 3);
- const ResolvedProductConstPtr a = products.value("a");
- QVERIFY(!!a);
- const ResolvedProductConstPtr b = products.value("b");
- QVERIFY(!!b);
- const ResolvedProductConstPtr c = products.value("c");
- QVERIFY(!!c);
-
- const auto propertyValue = [](const ResolvedProductConstPtr &p) -> QString
- {
- return p->moduleProperties->moduleProperty("dummy", "someString").toString();
- };
-
- QCOMPARE(propertyValue(a), QString("m"));
- QCOMPARE(propertyValue(b), QString("b"));
- QCOMPARE(propertyValue(c), QString("c"));
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::moduleScope()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("modulescope.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- ResolvedProductPtr product = products.value("product1");
- QVERIFY(!!product);
-
- auto intModuleValue = [product] (const QString &name) -> int
- {
- return product->moduleProperties->moduleProperty("scopemod", name).toInt();
- };
-
- QCOMPARE(intModuleValue("a"), 2); // overridden in module instance
- QCOMPARE(intModuleValue("b"), 1); // genuine
- QCOMPARE(intModuleValue("c"), 3); // genuine, dependent on overridden value
- QCOMPARE(intModuleValue("d"), 2); // genuine, dependent on genuine value
- QCOMPARE(intModuleValue("e"), 1); // genuine
- QCOMPARE(intModuleValue("f"), 2); // overridden
- QCOMPARE(intModuleValue("g"), 156); // overridden, dependent on product properties
- QCOMPARE(intModuleValue("h"), 158); // overridden, base dependent on product properties
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-
-}
-
-void TestLanguage::modules_data()
-{
- QTest::addColumn<QStringList>("expectedModulesInProduct");
- QTest::addColumn<QString>("expectedProductProperty");
- QTest::newRow("init") << QStringList();
- QTest::newRow("no_modules")
- << (QStringList() << "qbs")
- << QString();
- QTest::newRow("qt_core")
- << (QStringList() << "qbs" << "dummy" << "dummyqt.core")
- << QString("1.2.3");
- QTest::newRow("qt_gui")
- << (QStringList() << "qbs" << "dummy" << "dummyqt.core" << "dummyqt.gui")
- << QString("guiProperty");
- QTest::newRow("qt_gui_network")
- << (QStringList() << "qbs" << "dummy" << "dummyqt.core" << "dummyqt.gui"
- << "dummyqt.network")
- << QString("guiProperty,networkProperty");
- QTest::newRow("deep_module_name")
- << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
- << QString("abysmal");
- QTest::newRow("deep_module_name_submodule_syntax1")
- << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
- << QString("abysmal");
- QTest::newRow("deep_module_name_submodule_syntax2")
- << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
- << QString("abysmal");
- QTest::newRow("dummy_twice")
- << (QStringList() << "qbs" << "dummy")
- << QString();
- QTest::newRow("cleanup") << QStringList();
-}
-
-void TestLanguage::modules()
-{
- HANDLE_INIT_CLEANUP_DATATAGS("modules.qbs");
- QFETCH(QStringList, expectedModulesInProduct);
- QFETCH(QString, expectedProductProperty);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
- ResolvedProductPtr product = products.value(productName);
- QVERIFY(!!product);
- QCOMPARE(product->name, productName);
- QStringList modulesInProduct;
- foreach (ResolvedModuleConstPtr m, product->modules)
- modulesInProduct += m->name;
- modulesInProduct.sort();
- expectedModulesInProduct.sort();
- QCOMPARE(modulesInProduct, expectedModulesInProduct);
- QCOMPARE(product->productProperties.value("foo").toString(), expectedProductProperty);
-}
-
-void TestLanguage::nonRequiredProducts()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("non-required-products.qbs"));
- QFETCH(bool, subProjectEnabled);
- QFETCH(bool, dependeeEnabled);
- QVariantMap overriddenValues;
- if (!subProjectEnabled)
- overriddenValues.insert("projects.subproject.condition", false);
- else if (!dependeeEnabled)
- overriddenValues.insert("products.dependee.condition", false);
- params.setOverriddenValues(overriddenValues);
- const TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(!!project);
- const auto products = productsFromProject(project);
- QCOMPARE(products.count(), 4 + !!subProjectEnabled);
- const ResolvedProductConstPtr dependee = products.value("dependee");
- QCOMPARE(subProjectEnabled, !!dependee);
- if (dependee)
- QCOMPARE(dependeeEnabled, dependee->enabled);
- const ResolvedProductConstPtr depender = products.value("depender");
- QVERIFY(!!depender);
- const QStringList defines = depender->moduleProperties->moduleProperty("dummy", "defines")
- .toStringList();
- QCOMPARE(subProjectEnabled && dependeeEnabled, defines.contains("WITH_DEPENDEE"));
-
- for (const auto &name : std::vector<const char *>({ "p3", "p2", "p1"})) {
- const ResolvedProductConstPtr &product = products.value(name);
- QVERIFY2(product, name);
- QVERIFY2(!product->enabled, name);
- }
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::nonRequiredProducts_data()
-{
- QTest::addColumn<bool>("subProjectEnabled");
- QTest::addColumn<bool>("dependeeEnabled");
- QTest::newRow("dependee enabled") << true << true;
- QTest::newRow("dependee disabled") << true << false;
- QTest::newRow("sub project disabled") << false << true;
-}
-
-void TestLanguage::outerInGroup()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("outerInGroup.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- ResolvedProductPtr product = products.value("OuterInGroup");
- QVERIFY(!!product);
- QCOMPARE(product->groups.count(), 2);
- GroupPtr group = product->groups.at(0);
- QVERIFY(!!group);
- QCOMPARE(group->name, product->name);
- QCOMPARE(group->files.count(), 1);
- SourceArtifactConstPtr artifact = group->files.first();
- QVariant installDir = artifact->properties->qbsPropertyValue("installDir");
- QCOMPARE(installDir.toString(), QString("/somewhere"));
- group = product->groups.at(1);
- QVERIFY(!!group);
- QCOMPARE(group->name, QString("Special Group"));
- QCOMPARE(group->files.count(), 1);
- artifact = group->files.first();
- installDir = artifact->properties->qbsPropertyValue("installDir");
- QCOMPARE(installDir.toString(), QString("/somewhere/else"));
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::parameterTypes()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("parameter-types.qbs"));
- loader->loadProject(defaultParameters);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::pathProperties()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("pathproperties.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value("product1");
- QVERIFY(!!product);
- QString projectFileDir = QFileInfo(defaultParameters.projectFilePath()).absolutePath();
- const QVariantMap productProps = product->productProperties;
- QCOMPARE(productProps.value("projectFileDir").toString(), projectFileDir);
- QStringList filesInProjectFileDir = QStringList()
- << FileInfo::resolvePath(projectFileDir, "aboutdialog.h")
- << FileInfo::resolvePath(projectFileDir, "aboutdialog.cpp");
- QCOMPARE(productProps.value("filesInProjectFileDir").toStringList(), filesInProjectFileDir);
- QStringList includePaths = product->moduleProperties->property(
- QStringList() << "modules" << "dummy" << "includePaths").toStringList();
- QCOMPARE(includePaths, QStringList() << projectFileDir);
- QCOMPARE(productProps.value("base_fileInProductDir").toString(),
- FileInfo::resolvePath(projectFileDir, QLatin1String("foo")));
- QCOMPARE(productProps.value("base_fileInBaseProductDir").toString(),
- FileInfo::resolvePath(projectFileDir, QLatin1String("subdir/bar")));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::profileValuesAndOverriddenValues()
-{
- bool exceptionCaught = false;
- try {
- TemporaryProfile tp(QLatin1String("tst_lang_profile"), m_settings);
- Profile profile = tp.p;
- profile.setValue("dummy.defines", "IN_PROFILE");
- profile.setValue("dummy.cFlags", "IN_PROFILE");
- profile.setValue("dummy.cxxFlags", "IN_PROFILE");
- profile.setValue("qbs.architecture", "x86");
- SetupProjectParameters parameters = defaultParameters;
- parameters.setTopLevelProfile(profile.name());
- QVariantMap overriddenValues;
- overriddenValues.insert("modules.dummy.cFlags", "OVERRIDDEN");
- parameters.setOverriddenValues(overriddenValues);
- parameters.setProjectFilePath(testProject("profilevaluesandoverriddenvalues.qbs"));
- parameters.expandBuildConfiguration();
- project = loader->loadProject(parameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value("product1");
- QVERIFY(!!product);
- QVariantList values;
- values = product->moduleProperties->moduleProperty("dummy", "cxxFlags").toList();
- QCOMPARE(values.length(), 1);
- QCOMPARE(values.first().toString(), QString("IN_PROFILE"));
- values = product->moduleProperties->moduleProperty("dummy", "defines").toList();
- QCOMPARE(values, QVariantList() << QLatin1String("IN_FILE") << QLatin1String("IN_PROFILE"));
- values = product->moduleProperties->moduleProperty("dummy", "cFlags").toList();
- QCOMPARE(values.length(), 1);
- QCOMPARE(values.first().toString(), QString("OVERRIDDEN"));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::productConditions()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("productconditions.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 6);
- ResolvedProductPtr product;
- product = products.value("product_no_condition");
- QVERIFY(!!product);
- QVERIFY(product->enabled);
-
- product = products.value("product_true_condition");
- QVERIFY(!!product);
- QVERIFY(product->enabled);
-
- product = products.value("product_condition_dependent_of_module");
- QVERIFY(!!product);
- QVERIFY(product->enabled);
-
- product = products.value("product_false_condition");
- QVERIFY(!!product);
- QVERIFY(!product->enabled);
-
- product = products.value("product_probe_condition_false");
- QVERIFY(!!product);
- QVERIFY(!product->enabled);
-
- product = products.value("product_probe_condition_true");
- QVERIFY(!!product);
- QVERIFY(product->enabled);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::productDirectories()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("productdirectories.qbs"));
- ResolvedProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- ResolvedProductPtr product;
- product = products.value("MyApp");
- QVERIFY(!!product);
- const QVariantMap config = product->productProperties;
- QCOMPARE(config.value(QLatin1String("buildDirectory")).toString(),
- product->buildDirectory());
- QCOMPARE(config.value(QLatin1String("sourceDirectory")).toString(), testDataDir());
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::propertiesBlocks_data()
-{
- QTest::addColumn<QString>("propertyName");
- QTest::addColumn<QStringList>("expectedValues");
- QTest::addColumn<QString>("expectedStringValue");
-
- QTest::newRow("init") << QString() << QStringList() << QString();
- QTest::newRow("property_overwrite")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString();
- QTest::newRow("property_set_indirect")
- << QString("dummy.cFlags")
- << QStringList("VAL")
- << QString();
- QTest::newRow("property_overwrite_no_outer")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString();
- QTest::newRow("property_append_to_outer")
- << QString("dummy.defines")
- << (QStringList() << QString("ONE") << QString("TWO"))
- << QString();
-
- QTest::newRow("multiple_exclusive_properties")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString();
- QTest::newRow("multiple_exclusive_properties_no_outer")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString();
- QTest::newRow("multiple_exclusive_properties_append_to_outer")
- << QString("dummy.defines")
- << (QStringList() << QString("ONE") << QString("TWO"))
- << QString();
-
- QTest::newRow("condition_refers_to_product_property")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString("OVERWRITTEN");
- QTest::newRow("condition_refers_to_project_property")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString("OVERWRITTEN");
-
- QTest::newRow("ambiguous_properties")
- << QString("dummy.defines")
- << (QStringList() << QString("ONE") << QString("TWO"))
- << QString();
- QTest::newRow("inheritance_overwrite_in_subitem")
- << QString("dummy.defines")
- << (QStringList() << QString("OVERWRITTEN_IN_SUBITEM"))
- << QString();
- QTest::newRow("inheritance_retain_base1")
- << QString("dummy.defines")
- << (QStringList() << QString("BASE") << QString("SUB"))
- << QString();
- QTest::newRow("inheritance_retain_base2")
- << QString("dummy.defines")
- << (QStringList() << QString("BASE") << QString("SUB"))
- << QString();
- QTest::newRow("inheritance_retain_base3")
- << QString("dummy.defines")
- << (QStringList() << QString("BASE") << QString("SUB"))
- << QString();
- QTest::newRow("inheritance_retain_base4")
- << QString("dummy.defines")
- << (QStringList() << QString("BASE"))
- << QString();
- QTest::newRow("inheritance_condition_in_subitem1")
- << QString("dummy.defines")
- << (QStringList() << QString("SOMETHING") << QString("SUB"))
- << QString();
- QTest::newRow("inheritance_condition_in_subitem2")
- << QString("dummy.defines")
- << (QStringList() << QString("SOMETHING"))
- << QString();
- QTest::newRow("condition_references_id")
- << QString("dummy.defines")
- << (QStringList() << QString("OVERWRITTEN"))
- << QString();
- QTest::newRow("using_derived_Properties_item") << "dummy.defines"
- << (QStringList() << "string from MyProperties") << QString();
- QTest::newRow("conditional-depends")
- << QString("dummy.defines")
- << QStringList()
- << QString();
- QTest::newRow("cleanup") << QString() << QStringList() << QString();
-}
-
-void TestLanguage::propertiesBlocks()
-{
- HANDLE_INIT_CLEANUP_DATATAGS("propertiesblocks.qbs");
- QFETCH(QString, propertyName);
- QFETCH(QStringList, expectedValues);
- QFETCH(QString, expectedStringValue);
- QVERIFY(!!project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
- ResolvedProductPtr product = products.value(productName);
- QVERIFY(!!product);
- QCOMPARE(product->name, productName);
- QVariant v = productPropertyValue(product, propertyName);
- QCOMPARE(v.toStringList(), expectedValues);
- if (!expectedStringValue.isEmpty()) {
- v = productPropertyValue(product, "someString");
- QCOMPARE(v.toString(), expectedStringValue);
- }
-}
-
-void TestLanguage::propertiesBlockInGroup()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("properties-block-in-group.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- QCOMPARE(project->allProducts().count(), 1);
- const ResolvedProductConstPtr product = project->allProducts().first();
- const auto groupIt = std::find_if(product->groups.constBegin(), product->groups.constEnd(),
- [](const GroupConstPtr &g) { return g->name == "the group"; });
- QVERIFY(groupIt != product->groups.constEnd());
- const QVariantMap propertyMap = (*groupIt)->properties->value();
- const QVariantList value = moduleProperty(propertyMap, "dummy", "defines").toList();
- QStringList stringListValue;
- std::transform(value.constBegin(), value.constEnd(), std::back_inserter(stringListValue),
- [](const QVariant &v) { return v.toString(); });
- QCOMPARE(stringListValue, QStringList() << "BASEDEF" << "FEATURE_ENABLED");
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::propertiesItemInModule()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(
- testProject("properties-item-in-module.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 2);
- for (const ResolvedProductConstPtr &p : products) {
- QCOMPARE(p->moduleProperties->moduleProperty("dummy", "productName").toString(),
- p->name);
- }
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::qbsPropertiesInProjectCondition()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(
- testProject("qbs-properties-in-project-condition.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 0);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::relaxedErrorMode()
-{
- m_logSink->setLogLevel(LoggerMinLevel);
- QFETCH(bool, strictMode);
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("relaxed-error-mode/relaxed-error-mode.qbs"));
- params.setProductErrorMode(strictMode ? ErrorHandlingMode::Strict
- : ErrorHandlingMode::Relaxed);
- const TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(!strictMode);
- const auto productMap = productsFromProject(project);
- const ResolvedProductConstPtr brokenProduct = productMap.value("broken");
- QVERIFY(!brokenProduct->enabled);
- QVERIFY(brokenProduct->location.isValid());
- QCOMPARE(brokenProduct->allFiles().count(), 0);
- const ResolvedProductConstPtr dependerRequired = productMap.value("depender required");
- QVERIFY(!dependerRequired->enabled);
- QVERIFY(dependerRequired->location.isValid());
- QCOMPARE(dependerRequired->allFiles().count(), 1);
- const ResolvedProductConstPtr dependerNonRequired
- = productMap.value("depender nonrequired");
- QVERIFY(dependerNonRequired->enabled);
- QCOMPARE(dependerNonRequired->allFiles().count(), 1);
- const ResolvedProductConstPtr recursiveDepender = productMap.value("recursive depender");
- QVERIFY(!recursiveDepender->enabled);
- QVERIFY(recursiveDepender->location.isValid());
- QCOMPARE(recursiveDepender->allFiles().count(), 1);
- const ResolvedProductConstPtr missingFile = productMap.value("missing file");
- QVERIFY(missingFile->enabled);
- QCOMPARE(missingFile->groups.count(), 1);
- QVERIFY(missingFile->groups.first()->enabled);
- QCOMPARE(missingFile->groups.first()->allFiles().count(), 2);
- const ResolvedProductConstPtr fine = productMap.value("fine");
- QVERIFY(fine->enabled);
- QCOMPARE(fine->allFiles().count(), 1);
- } catch (const ErrorInfo &e) {
- QVERIFY2(strictMode, qPrintable(e.toString()));
- }
-}
-
-void TestLanguage::relaxedErrorMode_data()
-{
- QTest::addColumn<bool>("strictMode");
-
- QTest::newRow("strict mode") << true;
- QTest::newRow("relaxed mode") << false;
-}
-
-void TestLanguage::requiredAndNonRequiredDependencies()
-{
- QFETCH(QString, projectFile);
- QFETCH(bool, exceptionExpected);
- try {
- SetupProjectParameters params = defaultParameters;
- const QString projectFilePath = "required-and-nonrequired-dependencies/" + projectFile;
- params.setProjectFilePath(testProject(projectFilePath.toLocal8Bit()));
- const TopLevelProjectConstPtr project = loader->loadProject(params);
- QVERIFY(!!project);
- QVERIFY(!exceptionExpected);
- } catch (const ErrorInfo &e) {
- QVERIFY(exceptionExpected);
- QVERIFY2(e.toString().contains("validation error!"), qPrintable(e.toString()));
- }
-}
-
-void TestLanguage::requiredAndNonRequiredDependencies_data()
-{
- QTest::addColumn<QString>("projectFile");
- QTest::addColumn<bool>("exceptionExpected");
-
- QTest::newRow("same file") << "direct-dependencies.qbs" << true;
- QTest::newRow("dependency via module") << "dependency-via-module.qbs" << true;
- QTest::newRow("dependency via export") << "dependency-via-export.qbs" << true;
- QTest::newRow("more indirection") << "complicated.qbs" << true;
- QTest::newRow("required chain (module)") << "required-chain-module.qbs" << false;
- QTest::newRow("required chain (export)") << "required-chain-export.qbs" << false;
- QTest::newRow("required chain (export indirect)") << "required-chain-export-indirect.qbs"
- << false;
-}
-
-void TestLanguage::throwingProbe()
-{
- QFETCH(bool, enableProbe);
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("throwing-probe.qbs"));
- QVariantMap properties;
- properties.insert(QLatin1String("products.theProduct.enableProbe"), enableProbe);
- params.setOverriddenValues(properties);
- const TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(!!project);
- QVERIFY(!enableProbe);
- } catch (const ErrorInfo &e) {
- QVERIFY2(enableProbe, qPrintable(e.toString()));
- }
-}
-
-void TestLanguage::throwingProbe_data()
-{
- QTest::addColumn<bool>("enableProbe");
-
- QTest::newRow("enabled probe") << true;
- QTest::newRow("disabled probe") << false;
-}
-
-void TestLanguage::qualifiedId()
-{
- QString str = "foo.bar.baz";
- QualifiedId id = QualifiedId::fromString(str);
- QCOMPARE(id.count(), 3);
- QCOMPARE(id.toString(), str);
-
- id = QualifiedId("blubb.di.blubb"); // c'tor does not split
- QCOMPARE(id.count(), 1);
-
- QList<QualifiedId> ids;
- ids << QualifiedId::fromString("a")
- << QualifiedId::fromString("a.a")
- << QualifiedId::fromString("b")
- << QualifiedId::fromString("c.a")
- << QualifiedId::fromString("c.b.a")
- << QualifiedId::fromString("c.c");
- QList<QualifiedId> sorted = ids;
- std::sort(sorted.begin(), sorted.end());
- QCOMPARE(ids, sorted);
-}
-
-void TestLanguage::recursiveProductDependencies()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(
- testProject("recursive-dependencies/recursive-dependencies.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 4);
- const ResolvedProductConstPtr p1 = products.value("p1");
- QVERIFY(!!p1);
- const ResolvedProductConstPtr p2 = products.value("p2");
- QVERIFY(!!p2);
- const ResolvedProductPtr p3 = products.value("p3");
- QVERIFY(!!p3);
- const ResolvedProductPtr p4 = products.value("p4");
- QVERIFY(!!p4);
- QVERIFY(p1->dependencies == Set<ResolvedProductPtr>() << p3 << p4);
- QVERIFY(p2->dependencies == Set<ResolvedProductPtr>() << p3 << p4);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::fileTags_data()
-{
- QTest::addColumn<int>("numberOfGroups");
- QTest::addColumn<QStringList>("expectedFileTags");
-
- QTest::newRow("init") << 0 << QStringList();
- QTest::newRow("filetagger_project_scope") << 1 << (QStringList() << "cpp");
- QTest::newRow("filetagger_product_scope") << 1 << (QStringList() << "asm");
- QTest::newRow("filetagger_static_pattern") << 1 << (QStringList() << "yellow");
- QTest::newRow("unknown_file_tag") << 1 << (QStringList() << "unknown-file-tag");
- QTest::newRow("set_file_tag_via_group") << 2 << (QStringList() << "c++");
- QTest::newRow("override_file_tag_via_group") << 2 << (QStringList() << "c++");
- QTest::newRow("add_file_tag_via_group") << 2 << (QStringList() << "cpp" << "zzz");
- QTest::newRow("cleanup") << 0 << QStringList();
-}
-
-void TestLanguage::fileTags()
-{
- HANDLE_INIT_CLEANUP_DATATAGS("filetags.qbs");
- QFETCH(int, numberOfGroups);
- QFETCH(QStringList, expectedFileTags);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product;
- const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
- QVERIFY(!!(product = products.value(productName)));
- QCOMPARE(product->groups.count(), numberOfGroups);
- GroupPtr group = product->groups.last();
- QVERIFY(!!group);
- QCOMPARE(group->files.count(), 1);
- SourceArtifactConstPtr sourceFile = group->files.first();
- QStringList fileTags = sourceFile->fileTags.toStringList();
- fileTags.sort();
- QCOMPARE(fileTags, expectedFileTags);
-}
-
-void TestLanguage::wildcards_data()
-{
- QTest::addColumn<bool>("useGroup");
- QTest::addColumn<QStringList>("filesToCreate");
- QTest::addColumn<QString>("projectFileSubDir");
- QTest::addColumn<QString>("prefix");
- QTest::addColumn<QStringList>("patterns");
- QTest::addColumn<QStringList>("excludePatterns");
- QTest::addColumn<QStringList>("expected");
-
- const bool useGroup = true;
- for (int i = 0; i <= 1; ++i) {
- const bool useGroup = i;
- const QByteArray dataTagSuffix = useGroup ? " group" : " nogroup";
- QTest::newRow(QByteArray("simple 1") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "*.h")
- << QStringList()
- << (QStringList() << "foo.h" << "bar.h");
- QTest::newRow(QByteArray("simple 2") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "foo.*")
- << QStringList()
- << (QStringList() << "foo.h" << "foo.cpp");
- QTest::newRow(QByteArray("simple 3") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "*.h" << "*.cpp")
- << QStringList()
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp");
- QTest::newRow(QByteArray("exclude 1") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "*.h" << "*.cpp")
- << (QStringList() << "bar*")
- << (QStringList() << "foo.h" << "foo.cpp");
- QTest::newRow(QByteArray("exclude 2") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "*")
- << (QStringList() << "*.qbs")
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp");
- QTest::newRow(QByteArray("non-recursive") + dataTagSuffix)
- << useGroup
- << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "a/*")
- << QStringList()
- << (QStringList() << "a/foo.h" << "a/foo.cpp");
- QTest::newRow(QByteArray("absolute paths") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << m_wildcardsTestDirPath + "/?oo.*")
- << QStringList()
- << (QStringList() << "foo.h" << "foo.cpp");
- QTest::newRow(QByteArray("relative paths with dotdot") + dataTagSuffix)
- << useGroup
- << (QStringList() << "bar.h" << "bar.cpp")
- << QString("TheLaughingLlama")
- << QString()
- << (QStringList() << "../bar.*")
- << QStringList()
- << (QStringList() << "bar.h" << "bar.cpp");
- }
- QTest::newRow(QByteArray("recursive 1"))
- << useGroup
- << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "a/**")
- << QStringList()
- << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp");
- QTest::newRow(QByteArray("recursive 2"))
- << useGroup
- << (QStringList()
- << "d/1.h" << "b/d/1.h" << "b/c/d/1.h"
- << "d/e/1.h" << "b/d/e/1.h" << "b/c/d/e/1.h"
- << "a/d/1.h" << "a/b/d/1.h" << "a/b/c/d/1.h"
- << "a/d/e/1.h" << "a/b/d/e/1.h" << "a/b/c/d/e/1.h"
- << "a/d/1.cpp" << "a/b/d/1.cpp" << "a/b/c/d/1.h"
- << "a/d/e/1.cpp" << "a/b/d/e/1.cpp" << "a/b/c/d/e/1.cpp")
- << QString()
- << QString()
- << (QStringList() << "a/**/d/*.h")
- << QStringList()
- << (QStringList() << "a/d/1.h" << "a/b/d/1.h" << "a/b/c/d/1.h");
- QTest::newRow(QByteArray("recursive 3"))
- << useGroup
- << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "a/**/**/**")
- << QStringList()
- << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp");
- QTest::newRow(QByteArray("prefix"))
- << useGroup
- << (QStringList() << "subdir/foo.h" << "subdir/foo.cpp" << "subdir/bar.h"
- << "subdir/bar.cpp")
- << QString()
- << QString("subdir/")
- << (QStringList() << "*.h")
- << QStringList()
- << (QStringList() << "subdir/foo.h" << "subdir/bar.h");
- QTest::newRow(QByteArray("non-existing absolute path"))
- << useGroup
- << QStringList()
- << QString()
- << QString("/dir")
- << (QStringList() << "*.whatever")
- << QStringList()
- << QStringList();
-}
-
-void TestLanguage::wildcards()
-{
- QFETCH(bool, useGroup);
- QFETCH(QStringList, filesToCreate);
- QFETCH(QString, projectFileSubDir);
- QFETCH(QString, prefix);
- QFETCH(QStringList, patterns);
- QFETCH(QStringList, excludePatterns);
- QFETCH(QStringList, expected);
-
- // create test directory
- QDir::setCurrent(QDir::tempPath());
- {
- QString errorMessage;
- if (QFile::exists(m_wildcardsTestDirPath)) {
- if (!removeDirectoryWithContents(m_wildcardsTestDirPath, &errorMessage)) {
- qDebug() << errorMessage;
- QVERIFY2(false, "removeDirectoryWithContents failed");
- }
- }
- QVERIFY(QDir().mkdir(m_wildcardsTestDirPath));
- }
-
- // create project file
- const QString groupName = "Keks";
- QString dataTag = QString::fromLocal8Bit(QTest::currentDataTag());
- dataTag.replace(' ', '_');
- if (!projectFileSubDir.isEmpty()) {
- if (!projectFileSubDir.startsWith('/'))
- projectFileSubDir.prepend('/');
- if (projectFileSubDir.endsWith('/'))
- projectFileSubDir.chop(1);
- QVERIFY(QDir().mkpath(m_wildcardsTestDirPath + projectFileSubDir));
- }
- const QString projectFilePath = m_wildcardsTestDirPath + projectFileSubDir + "/test_" + dataTag
- + ".qbs";
- {
- QFile projectFile(projectFilePath);
- QVERIFY(projectFile.open(QIODevice::WriteOnly));
- QTextStream s(&projectFile);
- s << "import qbs.base 1.0" << endl << endl
- << "Application {" << endl
- << " name: \"MyProduct\"" << endl;
- if (useGroup) {
- s << " Group {" << endl
- << " name: " << toJSLiteral(groupName) << endl;
- }
- if (!prefix.isEmpty())
- s << " prefix: " << toJSLiteral(prefix) << endl;
- if (!patterns.isEmpty())
- s << " files: " << toJSLiteral(patterns) << endl;
- if (!excludePatterns.isEmpty())
- s << " excludeFiles: " << toJSLiteral(excludePatterns) << endl;
- if (useGroup)
- s << " }" << endl;
- s << "}" << endl << endl;
- }
-
- // create files
- foreach (QString filePath, filesToCreate) {
- filePath.prepend(m_wildcardsTestDirPath + '/');
- QFileInfo fi(filePath);
- if (!QDir(fi.path()).exists())
- QVERIFY(QDir().mkpath(fi.path()));
- QFile file(filePath);
- QVERIFY(file.open(QIODevice::WriteOnly));
- }
-
- // read the project
- bool exceptionCaught = false;
- ResolvedProductPtr product;
- try {
- defaultParameters.setProjectFilePath(projectFilePath);
- project = loader->loadProject(defaultParameters);
- QVERIFY(!!project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- product = products.value("MyProduct");
- QVERIFY(!!product);
- GroupPtr group;
- if (useGroup) {
- QCOMPARE(product->groups.count(), HostOsInfo::isMacosHost() ? 3 : 2);
- foreach (const GroupPtr &rg, product->groups) {
- if (rg->name == groupName) {
- group = rg;
- break;
- }
- }
- } else {
- QCOMPARE(product->groups.count(), HostOsInfo::isMacosHost() ? 2 : 1);
- group = product->groups.first();
- }
- QVERIFY(!!group);
- QCOMPARE(group->files.count(), 0);
- SourceWildCards::Ptr wildcards = group->wildcards;
- QVERIFY(!!wildcards);
- QStringList actualFilePaths;
- foreach (const SourceArtifactConstPtr &artifact, wildcards->files) {
- QString str = artifact->absoluteFilePath;
- int idx = str.indexOf(m_wildcardsTestDirPath);
- if (idx != -1)
- str.remove(0, idx + m_wildcardsTestDirPath.count() + 1);
- actualFilePaths << str;
- }
- actualFilePaths.sort();
- expected.sort();
- QCOMPARE(actualFilePaths, expected);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-} // namespace Internal
-} // namespace qbs
diff --git a/src/lib/corelib/language/value.h b/src/lib/corelib/language/value.h
index ab2c3187a..6b0c98dc9 100644
--- a/src/lib/corelib/language/value.h
+++ b/src/lib/corelib/language/value.h
@@ -109,7 +109,7 @@ class JSSourceValue : public Value
Q_DECLARE_FLAGS(Flags, Flag)
public:
- static JSSourceValuePtr create(bool createdByPropertiesBlock = false);
+ static JSSourceValuePtr QBS_AUTOTEST_EXPORT create(bool createdByPropertiesBlock = false);
~JSSourceValue();
void apply(ValueHandler *handler) { handler->handle(this); }
diff --git a/src/lib/corelib/parser/qmljsastvisitor_p.h b/src/lib/corelib/parser/qmljsastvisitor_p.h
index f0eff5ce7..aa4471c6b 100644
--- a/src/lib/corelib/parser/qmljsastvisitor_p.h
+++ b/src/lib/corelib/parser/qmljsastvisitor_p.h
@@ -53,11 +53,12 @@
#include "qmljsastfwd_p.h"
#include "qmljsglobal_p.h"
+#include <tools/qbs_export.h>
namespace QbsQmlJS {
namespace AST {
-class QML_PARSER_EXPORT Visitor
+class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Visitor
{
public:
Visitor();
diff --git a/src/lib/corelib/parser/qmljsengine_p.h b/src/lib/corelib/parser/qmljsengine_p.h
index be88b917b..2fdd60b30 100644
--- a/src/lib/corelib/parser/qmljsengine_p.h
+++ b/src/lib/corelib/parser/qmljsengine_p.h
@@ -54,6 +54,7 @@
#include "qmljsglobal_p.h"
#include "qmljsastfwd_p.h"
#include "qmljsmemorypool_p.h"
+#include <tools/qbs_export.h>
#include <QtCore/qstring.h>
@@ -87,7 +88,7 @@ public:
QString message;
};
-class QML_PARSER_EXPORT Engine
+class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Engine
{
Lexer *_lexer;
Directives *_directives;
diff --git a/src/lib/corelib/parser/qmljslexer_p.h b/src/lib/corelib/parser/qmljslexer_p.h
index 7a77ddabe..e0d61b226 100644
--- a/src/lib/corelib/parser/qmljslexer_p.h
+++ b/src/lib/corelib/parser/qmljslexer_p.h
@@ -53,6 +53,7 @@
#include "qmljsglobal_p.h"
#include "qmljsgrammar_p.h"
+#include <tools/qbs_export.h>
#include <QtCore/qstring.h>
namespace QbsQmlJS {
@@ -81,7 +82,7 @@ public:
}
};
-class QML_PARSER_EXPORT Lexer: public QmlJSGrammar
+class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Lexer: public QmlJSGrammar
{
public:
enum {
diff --git a/src/lib/corelib/parser/qmljsparser_p.h b/src/lib/corelib/parser/qmljsparser_p.h
index 93c096367..38fc1f5ce 100644
--- a/src/lib/corelib/parser/qmljsparser_p.h
+++ b/src/lib/corelib/parser/qmljsparser_p.h
@@ -61,6 +61,7 @@
#include "qmljsgrammar_p.h"
#include "qmljsast_p.h"
#include "qmljsengine_p.h"
+#include <tools/qbs_export.h>
#include <QtCore/qlist.h>
#include <QtCore/qstring.h>
@@ -69,7 +70,7 @@ namespace QbsQmlJS {
class Engine;
-class QML_PARSER_EXPORT Parser: protected QmlJSGrammar
+class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Parser: protected QmlJSGrammar
{
public:
union Value {
diff --git a/src/lib/corelib/tools/fileinfo.h b/src/lib/corelib/tools/fileinfo.h
index 1655e37d9..71d178265 100644
--- a/src/lib/corelib/tools/fileinfo.h
+++ b/src/lib/corelib/tools/fileinfo.h
@@ -55,7 +55,7 @@ QT_FORWARD_DECLARE_CLASS(QFileInfo)
namespace qbs {
namespace Internal {
-class FileInfo
+class QBS_AUTOTEST_EXPORT FileInfo
{
public:
FileInfo(const QString &fileName);
diff --git a/src/lib/corelib/tools/filetime.h b/src/lib/corelib/tools/filetime.h
index 30687833f..c9b98e9c0 100644
--- a/src/lib/corelib/tools/filetime.h
+++ b/src/lib/corelib/tools/filetime.h
@@ -60,7 +60,7 @@
namespace qbs {
namespace Internal {
-class FileTime
+class QBS_AUTOTEST_EXPORT FileTime
{
public:
#if defined(Q_OS_UNIX)
diff --git a/src/lib/corelib/tools/id.h b/src/lib/corelib/tools/id.h
index 334acc686..aedecd66e 100644
--- a/src/lib/corelib/tools/id.h
+++ b/src/lib/corelib/tools/id.h
@@ -40,6 +40,8 @@
#ifndef QBS_TOOLS_ID_H
#define QBS_TOOLS_ID_H
+#include "qbs_export.h"
+
#include <QtCore/qmetatype.h>
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
@@ -47,7 +49,7 @@
namespace qbs {
namespace Internal {
-class Id
+class QBS_AUTOTEST_EXPORT Id
{
public:
enum { IdsPerPlugin = 10000, ReservedPlugins = 1000 };
diff --git a/src/lib/corelib/tools/processutils.h b/src/lib/corelib/tools/processutils.h
index 5a210289d..14ab13812 100644
--- a/src/lib/corelib/tools/processutils.h
+++ b/src/lib/corelib/tools/processutils.h
@@ -40,13 +40,15 @@
#ifndef QBS_PROCESSUTILS_H
#define QBS_PROCESSUTILS_H
+#include <tools/qbs_export.h>
+
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
namespace qbs {
namespace Internal {
-QString processNameByPid(qint64 pid);
+QString QBS_AUTOTEST_EXPORT processNameByPid(qint64 pid);
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/tools/qbs_export.h b/src/lib/corelib/tools/qbs_export.h
index 5bb28f98d..a92150c63 100644
--- a/src/lib/corelib/tools/qbs_export.h
+++ b/src/lib/corelib/tools/qbs_export.h
@@ -43,11 +43,22 @@
#ifdef QBS_STATIC_LIB
# define QBS_EXPORT
+# define QBS_AUTOTEST_EXPORT
#else
# ifdef QBS_LIBRARY
# define QBS_EXPORT Q_DECL_EXPORT
+# ifdef QBS_ENABLE_UNIT_TESTS
+# define QBS_AUTOTEST_EXPORT Q_DECL_EXPORT
+# else
+# define QBS_AUTOTEST_EXPORT
+# endif
# else
# define QBS_EXPORT Q_DECL_IMPORT
+# ifdef QBS_ENABLE_UNIT_TESTS
+# define QBS_AUTOTEST_EXPORT Q_DECL_IMPORT
+# else
+# define QBS_AUTOTEST_EXPORT
+# endif
# endif
#endif
diff --git a/src/lib/corelib/tools/scripttools.h b/src/lib/corelib/tools/scripttools.h
index 56731c730..8346aea66 100644
--- a/src/lib/corelib/tools/scripttools.h
+++ b/src/lib/corelib/tools/scripttools.h
@@ -63,7 +63,7 @@ QScriptValue toScriptValue(QScriptEngine *scriptEngine, const C &container)
}
void setConfigProperty(QVariantMap &cfg, const QStringList &name, const QVariant &value);
-QVariant getConfigProperty(const QVariantMap &cfg, const QStringList &name);
+QVariant QBS_AUTOTEST_EXPORT getConfigProperty(const QVariantMap &cfg, const QStringList &name);
template <class T>
void attachPointerTo(QScriptValue &scriptValue, T *ptr)
diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri
index ed0942294..301d00d05 100644
--- a/src/lib/corelib/tools/tools.pri
+++ b/src/lib/corelib/tools/tools.pri
@@ -104,11 +104,6 @@ osx {
LIBS += -framework Security
}
-qbs_enable_unit_tests {
- HEADERS += $$PWD/tst_tools.h
- SOURCES += $$PWD/tst_tools.cpp
-}
-
!qbs_no_dev_install {
tools_headers.files = \
$$PWD/architectures.h \
diff --git a/src/lib/corelib/tools/tst_tools.cpp b/src/lib/corelib/tools/tst_tools.cpp
deleted file mode 100644
index a6fb433c9..000000000
--- a/src/lib/corelib/tools/tst_tools.cpp
+++ /dev/null
@@ -1,950 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qbs.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack.
-
-#include "tst_tools.h"
-
-#include "buildoptions.h"
-#include "error.h"
-#include "fileinfo.h"
-#include "hostosinfo.h"
-#include "processutils.h"
-#include "profile.h"
-#include "set.h"
-#include "settings.h"
-#include "setupprojectparameters.h"
-#include "version.h"
-
-#include <QtCore/qdir.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qsettings.h>
-#include <QtCore/qtemporarydir.h>
-#include <QtCore/qtemporaryfile.h>
-
-#include <QtTest/qtest.h>
-
-namespace qbs {
-namespace Internal {
-
-TestTools::TestTools(Settings *settings) : m_settings(settings)
-{
-}
-
-TestTools::~TestTools()
-{
- qDeleteAll(m_tmpDirs);
-}
-
-void TestTools::testFileInfo()
-{
- QCOMPARE(FileInfo::fileName("C:/waffl/copter.exe"), QString("copter.exe"));
- QCOMPARE(FileInfo::baseName("C:/waffl/copter.exe.lib"), QString("copter"));
- QCOMPARE(FileInfo::completeBaseName("C:/waffl/copter.exe.lib"), QString("copter.exe"));
- QCOMPARE(FileInfo::path("abc"), QString("."));
- QCOMPARE(FileInfo::path("/abc/lol"), QString("/abc"));
- QCOMPARE(FileInfo::path("/fileInRoot"), QString(QLatin1Char('/')));
- if (HostOsInfo::isWindowsHost())
- QCOMPARE(FileInfo::path("C:/fileInDriveRoot"), QString("C:/"));
- QVERIFY(!FileInfo::isAbsolute("bla/lol"));
- QVERIFY(FileInfo::isAbsolute("/bla/lol"));
- if (HostOsInfo::isWindowsHost())
- QVERIFY(FileInfo::isAbsolute("C:\\bla\\lol"));
- QCOMPARE(FileInfo::resolvePath("/abc/lol", "waffl"), QString("/abc/lol/waffl"));
- QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../foo/bar"), QString("/abc/def/ghi/foo/bar"));
- QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../../foo/bar"), QString("/abc/def/foo/bar"));
- QCOMPARE(FileInfo::resolvePath("/abc", "../../../foo/bar"), QString("/foo/bar"));
- QCOMPARE(FileInfo("/does/not/exist").lastModified(), FileTime());
-}
-
-void TestTools::fileCaseCheck()
-{
- QTemporaryFile tempFile(QDir::tempPath() + QLatin1String("/CamelCase"));
- QVERIFY2(tempFile.open(), qPrintable(tempFile.errorString()));
- QFileInfo tempFileInfo(tempFile.fileName());
- const QString lowerFilePath = tempFileInfo.absolutePath() + QLatin1Char('/')
- + tempFileInfo.fileName().toLower();
- const QString upperFilePath = tempFileInfo.absolutePath() + QLatin1Char('/')
- + tempFileInfo.fileName().toUpper();
- QVERIFY(FileInfo::isFileCaseCorrect(tempFileInfo.absoluteFilePath()));
- if (QFile::exists(lowerFilePath))
- QVERIFY(!FileInfo::isFileCaseCorrect(lowerFilePath));
- if (QFile::exists(upperFilePath))
- QVERIFY(!FileInfo::isFileCaseCorrect(upperFilePath));
-}
-
-void TestTools::testProfiles()
-{
- TemporaryProfile tpp("parent", m_settings);
- Profile parentProfile = tpp.p;
- TemporaryProfile tpc("child", m_settings);
- Profile childProfile = tpc.p;
- parentProfile.removeBaseProfile();
- parentProfile.remove("testKey");
- QCOMPARE(parentProfile.value("testKey", "none").toString(), QLatin1String("none"));
- parentProfile.setValue("testKey", "testValue");
- QCOMPARE(parentProfile.value("testKey").toString(), QLatin1String("testValue"));
-
- childProfile.remove("testKey");
- childProfile.removeBaseProfile();
- QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("none"));
- childProfile.setBaseProfile("parent");
- QCOMPARE(childProfile.value("testKey").toString(), QLatin1String("testValue"));
-
- // Change base profile and check if the inherited value also changes.
- TemporaryProfile tpf("foo", m_settings);
- Profile fooProfile = tpf.p;
- fooProfile.setValue("testKey", "gnampf");
- childProfile.setBaseProfile("foo");
- QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("gnampf"));
-
- ErrorInfo errorInfo;
- childProfile.setBaseProfile("SmurfAlongWithMe");
- childProfile.value("blubb", QString(), &errorInfo);
- QVERIFY(errorInfo.hasError());
-
- errorInfo.clear();
- childProfile.setBaseProfile("parent");
- parentProfile.setBaseProfile("child");
- QVERIFY(!childProfile.value("blubb", QString(), &errorInfo).isValid());
- QVERIFY(errorInfo.hasError());
-
- QVERIFY(!childProfile.allKeys(Profile::KeySelectionNonRecursive).isEmpty());
-
- errorInfo.clear();
- QVERIFY(childProfile.allKeys(Profile::KeySelectionRecursive, &errorInfo).isEmpty());
- QVERIFY(errorInfo.hasError());
-}
-
-void TestTools::testSettingsMigration()
-{
- QFETCH(QString, baseDir);
- QFETCH(bool, hasOldSettings);
- Settings settings(baseDir);
- if (hasOldSettings) {
- QVERIFY(QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles/right.txt")
- .exists());
- QCOMPARE(settings.value("key").toString(),
- settings.baseDirectory() + "/qbs/" QBS_VERSION "/profilesright");
- } else {
- QVERIFY(!QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles").exists());
- QVERIFY(settings.allKeys().isEmpty());
- }
-}
-
-void TestTools::testSettingsMigration_data()
-{
- QTest::addColumn<QString>("baseDir");
- QTest::addColumn<bool>("hasOldSettings");
- QTest::newRow("settings dir with lots of versions") << setupSettingsDir1() << true;
- QTest::newRow("settings dir with only a fallback") << setupSettingsDir2() << true;
- QTest::newRow("no previous settings") << setupSettingsDir3() << false;
-}
-
-QString TestTools::setupSettingsDir1()
-{
- QTemporaryDir * const baseDir = new QTemporaryDir;
- m_tmpDirs << baseDir;
-
- const Version thisVersion = Version::fromString(QBS_VERSION);
- Version predecessor;
- if (thisVersion.patchLevel() > 0) {
- predecessor.setMajorVersion(thisVersion.majorVersion());
- predecessor.setMinorVersion(thisVersion.minorVersion());
- predecessor.setPatchLevel(thisVersion.patchLevel() - 1);
- } else if (thisVersion.minorVersion() > 0) {
- predecessor.setMajorVersion(thisVersion.majorVersion());
- predecessor.setMinorVersion(thisVersion.minorVersion() - 1);
- predecessor.setPatchLevel(99);
- } else {
- predecessor.setMajorVersion(thisVersion.majorVersion() - 1);
- predecessor.setMajorVersion(99);
- predecessor.setPatchLevel(99);
- }
- const auto versions = QList<Version>() << Version(0, 1, 0) << Version(1, 0, 5) << predecessor
- << Version(thisVersion.majorVersion() + 1, thisVersion.minorVersion(),
- thisVersion.patchLevel())
- << Version(thisVersion.majorVersion(), thisVersion.minorVersion() + 1,
- thisVersion.patchLevel())
- << Version(thisVersion.majorVersion(), thisVersion.minorVersion(),
- thisVersion.patchLevel() + 1)
- << Version(99, 99, 99);
- foreach (const Version &v, versions) {
- const QString settingsDir = baseDir->path() + "/qbs/" + v.toString();
- QSettings s(settingsDir + "/qbs.conf",
- HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat);
- const QString profilesDir = settingsDir + "/profiles";
- QDir::root().mkpath(profilesDir);
- const QString magicString = v == predecessor ? "right" : "wrong";
- QFile f(profilesDir + '/' + magicString + ".txt");
- f.open(QIODevice::WriteOnly);
- s.setValue("org/qt-project/qbs/key", profilesDir + magicString);
- }
-
- return baseDir->path();
-}
-
-QString TestTools::setupSettingsDir2()
-{
- QTemporaryDir * const baseDir = new QTemporaryDir;
- m_tmpDirs << baseDir;
- const QString settingsDir = baseDir->path();
- QSettings s(settingsDir + QLatin1String("/qbs.conf"),
- HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat);
- const QString profilesDir = settingsDir + QLatin1String("/qbs/profiles");
- QDir::root().mkpath(profilesDir);
- QFile f(profilesDir + "/right.txt");
- f.open(QIODevice::WriteOnly);
- s.setValue("org/qt-project/qbs/key", profilesDir + "right");
-
- return baseDir->path();
-}
-
-QString TestTools::setupSettingsDir3()
-{
- auto * const baseDir = new QTemporaryDir;
- m_tmpDirs << baseDir;
- return baseDir->path();
-}
-
-void TestTools::testBuildConfigMerging()
-{
- TemporaryProfile tp(QLatin1String("tst_tools_profile"), m_settings);
- Profile profile = tp.p;
- profile.setValue(QLatin1String("topLevelKey"), QLatin1String("topLevelValue"));
- profile.setValue(QLatin1String("qbs.toolchain"), QLatin1String("gcc"));
- profile.setValue(QLatin1String("qbs.architecture"),
- QLatin1String("Jean-Claude Pillemann"));
- profile.setValue(QLatin1String("cpp.treatWarningsAsErrors"), true);
- QVariantMap overrideMap;
- overrideMap.insert(QLatin1String("qbs.toolchain"), QLatin1String("clang"));
- overrideMap.insert(QLatin1String("qbs.installRoot"), QLatin1String("/blubb"));
- SetupProjectParameters params;
- params.setSettingsDirectory(m_settings->baseDirectory());
- params.setTopLevelProfile(profile.name());
- params.setConfigurationName(QLatin1String("debug"));
- params.setOverriddenValues(overrideMap);
- const ErrorInfo error = params.expandBuildConfiguration();
- QVERIFY2(!error.hasError(), qPrintable(error.toString()));
- const QVariantMap finalMap = params.finalBuildConfigurationTree();
- QCOMPARE(finalMap.count(), 3);
- QCOMPARE(finalMap.value(QLatin1String("topLevelKey")).toString(),
- QString::fromLatin1("topLevelValue"));
- const QVariantMap finalQbsMap = finalMap.value(QLatin1String("qbs")).toMap();
- QCOMPARE(finalQbsMap.count(), 4);
- QCOMPARE(finalQbsMap.value(QLatin1String("toolchain")).toString(),
- QString::fromLatin1("clang"));
- QCOMPARE(finalQbsMap.value(QLatin1String("configurationName")).toString(),
- QString::fromLatin1("debug"));
- QCOMPARE(finalQbsMap.value(QLatin1String("architecture")).toString(),
- QString::fromLatin1("Jean-Claude Pillemann"));
- QCOMPARE(finalQbsMap.value(QLatin1String("installRoot")).toString(), QLatin1String("/blubb"));
- const QVariantMap finalCppMap = finalMap.value(QLatin1String("cpp")).toMap();
- QCOMPARE(finalCppMap.count(), 1);
- QCOMPARE(finalCppMap.value(QLatin1String("treatWarningsAsErrors")).toBool(), true);
-}
-
-void TestTools::testProcessNameByPid()
-{
- QCOMPARE(qAppName(), processNameByPid(QCoreApplication::applicationPid()));
-}
-
-
-int toNumber(const QString &str)
-{
- int res = 0;
- for (int i = 0; i < str.length(); ++i)
- res = (res * 10) + str[i].digitValue();
- return res;
-}
-
-void TestTools::set_operator_eq()
-{
- {
- Set<int> set1, set2;
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set1.insert(1);
- QVERIFY(set1 != set2);
- QVERIFY(!(set1 == set2));
-
- set2.insert(1);
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set2.insert(1);
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set1.insert(2);
- QVERIFY(set1 != set2);
- QVERIFY(!(set1 == set2));
- }
-
- {
- Set<QString> set1, set2;
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set1.insert("one");
- QVERIFY(set1 != set2);
- QVERIFY(!(set1 == set2));
-
- set2.insert("one");
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set2.insert("one");
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set1.insert("two");
- QVERIFY(set1 != set2);
- QVERIFY(!(set1 == set2));
- }
-
- {
- Set<QString> a;
- Set<QString> b;
-
- a += "otto";
- b += "willy";
-
- QVERIFY(a != b);
- QVERIFY(!(a == b));
- }
-
- {
- Set<int> s1, s2;
- s1.reserve(100);
- s2.reserve(4);
- QVERIFY(s1 == s2);
- s1 << 100 << 200 << 300 << 400;
- s2 << 400 << 300 << 200 << 100;
- QVERIFY(s1 == s2);
- }
-}
-
-void TestTools::set_swap()
-{
- Set<int> s1, s2;
- s1.insert(1);
- s2.insert(2);
- s1.swap(s2);
- QCOMPARE(*s1.begin(),2);
- QCOMPARE(*s2.begin(),1);
-}
-
-void TestTools::set_size()
-{
- Set<int> set;
- QVERIFY(set.size() == 0);
- QVERIFY(set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.insert(1);
- QVERIFY(set.size() == 1);
- QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.insert(1);
- QVERIFY(set.size() == 1);
- QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.insert(2);
- QVERIFY(set.size() == 2);
- QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.remove(1);
- QVERIFY(set.size() == 1);
- QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.remove(1);
- QVERIFY(set.size() == 1);
- QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.remove(2);
- QVERIFY(set.size() == 0);
- QVERIFY(set.isEmpty());
- QVERIFY(set.count() == set.size());
-}
-
-void TestTools::set_capacity()
-{
- Set<int> set;
- int n = set.capacity();
- QVERIFY(n == 0);
-
- for (int i = 0; i < 1000; ++i) {
- set.insert(i);
- QVERIFY(set.capacity() >= set.size());
- }
-}
-
-void TestTools::set_reserve()
-{
- Set<int> set;
-
- set.reserve(1000);
- QVERIFY(set.capacity() >= 1000);
-
- for (int i = 0; i < 500; ++i)
- set.insert(i);
-
- QVERIFY(set.capacity() >= 1000);
-
- for (int j = 0; j < 500; ++j)
- set.remove(j);
-
- QVERIFY(set.capacity() >= 1000);
-}
-
-void TestTools::set_clear()
-{
- Set<QString> set1, set2;
- QVERIFY(set1.size() == 0);
-
- set1.clear();
- QVERIFY(set1.size() == 0);
-
- set1.insert("foo");
- QVERIFY(set1.size() != 0);
-
- set2 = set1;
-
- set1.clear();
- QVERIFY(set1.size() == 0);
- QVERIFY(set2.size() != 0);
-
- set2.clear();
- QVERIFY(set1.size() == 0);
- QVERIFY(set2.size() == 0);
-}
-
-void TestTools::set_remove()
-{
- Set<QString> set1;
-
- for (int i = 0; i < 500; ++i)
- set1.insert(QString::number(i));
-
- QCOMPARE(set1.size(), 500);
-
- for (int j = 0; j < 500; ++j) {
- set1.remove(QString::number((j * 17) % 500));
- QCOMPARE(set1.size(), 500 - j - 1);
- }
-}
-
-void TestTools::set_contains()
-{
- Set<QString> set1;
-
- for (int i = 0; i < 500; ++i) {
- QVERIFY(!set1.contains(QString::number(i)));
- set1.insert(QString::number(i));
- QVERIFY(set1.contains(QString::number(i)));
- }
-
- QCOMPARE(set1.size(), 500);
-
- for (int j = 0; j < 500; ++j) {
- int i = (j * 17) % 500;
- QVERIFY(set1.contains(QString::number(i)));
- set1.remove(QString::number(i));
- QVERIFY(!set1.contains(QString::number(i)));
- }
-}
-
-void TestTools::set_containsSet()
-{
- Set<QString> set1;
- Set<QString> set2;
-
- // empty set contains the empty set
- QVERIFY(set1.contains(set2));
-
- for (int i = 0; i < 500; ++i) {
- set1.insert(QString::number(i));
- set2.insert(QString::number(i));
- }
- QVERIFY(set1.contains(set2));
-
- set2.remove(QString::number(19));
- set2.remove(QString::number(82));
- set2.remove(QString::number(7));
- QVERIFY(set1.contains(set2));
-
- set1.remove(QString::number(23));
- QVERIFY(!set1.contains(set2));
-
- // filled set contains the empty set as well
- Set<QString> set3;
- QVERIFY(set1.contains(set3));
-
- // the empty set doesn't contain a filled set
- QVERIFY(!set3.contains(set1));
-
- // verify const signature
- const Set<QString> set4;
- QVERIFY(set3.contains(set4));
-}
-
-void TestTools::set_begin()
-{
- Set<int> set1;
- Set<int> set2 = set1;
-
- {
- Set<int>::const_iterator i = set1.constBegin();
- Set<int>::const_iterator j = set1.cbegin();
- Set<int>::const_iterator k = set2.constBegin();
- Set<int>::const_iterator ell = set2.cbegin();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
- }
-
- set1.insert(44);
-
- {
- Set<int>::const_iterator i = set1.constBegin();
- Set<int>::const_iterator j = set1.cbegin();
- Set<int>::const_iterator k = set2.constBegin();
- Set<int>::const_iterator ell = set2.cbegin();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
- }
-
- set2 = set1;
-
- {
- Set<int>::const_iterator i = set1.constBegin();
- Set<int>::const_iterator j = set1.cbegin();
- Set<int>::const_iterator k = set2.constBegin();
- Set<int>::const_iterator ell = set2.cbegin();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
- }
-}
-
-void TestTools::set_end()
-{
- Set<int> set1;
- Set<int> set2 = set1;
-
- {
- Set<int>::const_iterator i = set1.constEnd();
- Set<int>::const_iterator j = set1.cend();
- Set<int>::const_iterator k = set2.constEnd();
- Set<int>::const_iterator ell = set2.cend();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
-
- QVERIFY(set1.constBegin() == set1.constEnd());
- QVERIFY(set2.constBegin() == set2.constEnd());
- }
-
- set1.insert(44);
-
- {
- Set<int>::const_iterator i = set1.constEnd();
- Set<int>::const_iterator j = set1.cend();
- Set<int>::const_iterator k = set2.constEnd();
- Set<int>::const_iterator ell = set2.cend();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
-
- QVERIFY(set1.constBegin() != set1.constEnd());
- QVERIFY(set2.constBegin() == set2.constEnd());
- }
-
- set2 = set1;
-
- {
- Set<int>::const_iterator i = set1.constEnd();
- Set<int>::const_iterator j = set1.cend();
- Set<int>::const_iterator k = set2.constEnd();
- Set<int>::const_iterator ell = set2.cend();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
-
- QVERIFY(set1.constBegin() != set1.constEnd());
- QVERIFY(set2.constBegin() != set2.constEnd());
- }
-
- set1.clear();
- set2.clear();
- QVERIFY(set1.constBegin() == set1.constEnd());
- QVERIFY(set2.constBegin() == set2.constEnd());
-}
-
-struct IdentityTracker {
- int value, id;
-};
-inline bool operator==(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value == rhs.value; }
-inline bool operator<(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value < rhs.value; }
-
-void TestTools::set_insert()
-{
- {
- Set<int> set1;
- QVERIFY(set1.size() == 0);
- set1.insert(1);
- QVERIFY(set1.size() == 1);
- set1.insert(2);
- QVERIFY(set1.size() == 2);
- set1.insert(2);
- QVERIFY(set1.size() == 2);
- QVERIFY(set1.contains(2));
- set1.remove(2);
- QVERIFY(set1.size() == 1);
- QVERIFY(!set1.contains(2));
- set1.insert(2);
- QVERIFY(set1.size() == 2);
- QVERIFY(set1.contains(2));
- }
-
- {
- Set<int> set1;
- QVERIFY(set1.size() == 0);
- set1 << 1;
- QVERIFY(set1.size() == 1);
- set1 << 2;
- QVERIFY(set1.size() == 2);
- set1 << 2;
- QVERIFY(set1.size() == 2);
- QVERIFY(set1.contains(2));
- set1.remove(2);
- QVERIFY(set1.size() == 1);
- QVERIFY(!set1.contains(2));
- set1 << 2;
- QVERIFY(set1.size() == 2);
- QVERIFY(set1.contains(2));
- }
-
- {
- Set<IdentityTracker> set;
- QCOMPARE(set.size(), 0);
- const int dummy = -1;
- IdentityTracker id00 = {0, 0}, id01 = {0, 1}, searchKey = {0, dummy};
- QCOMPARE(set.insert(id00).first->id, id00.id);
- QCOMPARE(set.size(), 1);
- QCOMPARE(set.insert(id01).first->id, id00.id); // first inserted is kept
- QCOMPARE(set.size(), 1);
- QCOMPARE(set.find(searchKey)->id, id00.id);
- }
-}
-
-void TestTools::set_reverseIterators()
-{
- Set<int> s;
- s << 1 << 17 << 61 << 127 << 911;
- std::vector<int> v(s.begin(), s.end());
- std::reverse(v.begin(), v.end());
- const Set<int> &cs = s;
- QVERIFY(std::equal(v.begin(), v.end(), s.rbegin()));
- QVERIFY(std::equal(v.begin(), v.end(), s.crbegin()));
- QVERIFY(std::equal(v.begin(), v.end(), cs.rbegin()));
- QVERIFY(std::equal(s.rbegin(), s.rend(), v.begin()));
- QVERIFY(std::equal(s.crbegin(), s.crend(), v.begin()));
- QVERIFY(std::equal(cs.rbegin(), cs.rend(), v.begin()));
-}
-
-void TestTools::set_stlIterator()
-{
- Set<QString> set1;
- for (int i = 0; i < 25000; ++i)
- set1.insert(QString::number(i));
-
- {
- int sum = 0;
- Set<QString>::const_iterator i = set1.cbegin();
- while (i != set1.end()) {
- sum += toNumber(*i);
- ++i;
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- int sum = 0;
- Set<QString>::const_iterator i = set1.cend();
- while (i != set1.begin()) {
- --i;
- sum += toNumber(*i);
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-}
-
-void TestTools::set_stlMutableIterator()
-{
- Set<QString> set1;
- for (int i = 0; i < 25000; ++i)
- set1.insert(QString::number(i));
-
- {
- int sum = 0;
- Set<QString>::iterator i = set1.begin();
- while (i != set1.end()) {
- sum += toNumber(*i);
- ++i;
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- int sum = 0;
- Set<QString>::iterator i = set1.end();
- while (i != set1.begin()) {
- --i;
- sum += toNumber(*i);
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- Set<QString> set2 = set1;
- Set<QString> set3 = set2;
-
- Set<QString>::iterator i = set2.begin();
- Set<QString>::iterator j = set3.begin();
-
- while (i != set2.end()) {
- i = set2.erase(i);
- }
- QVERIFY(set2.isEmpty());
- QVERIFY(!set3.isEmpty());
-
- j = set3.end();
- while (j != set3.begin()) {
- j--;
- if (j + 1 != set3.end())
- set3.erase(j + 1);
- }
- if (set3.begin() != set3.end())
- set3.erase(set3.begin());
-
- QVERIFY(set2.isEmpty());
- QVERIFY(set3.isEmpty());
-
- i = set2.insert("foo").first;
- QCOMPARE(*i, QLatin1String("foo"));
- }
-}
-
-void TestTools::set_setOperations()
-{
- Set<QString> set1, set2;
- set1 << "alpha" << "beta" << "gamma" << "delta" << "zeta" << "omega";
- set2 << "beta" << "gamma" << "delta" << "epsilon" << "iota" << "omega";
-
- Set<QString> set3 = set1;
- set3.unite(set2);
- QVERIFY(set3.size() == 8);
- QVERIFY(set3.contains("alpha"));
- QVERIFY(set3.contains("beta"));
- QVERIFY(set3.contains("gamma"));
- QVERIFY(set3.contains("delta"));
- QVERIFY(set3.contains("epsilon"));
- QVERIFY(set3.contains("zeta"));
- QVERIFY(set3.contains("iota"));
- QVERIFY(set3.contains("omega"));
-
- Set<QString> set4 = set2;
- set4.unite(set1);
- QVERIFY(set4.size() == 8);
- QVERIFY(set4.contains("alpha"));
- QVERIFY(set4.contains("beta"));
- QVERIFY(set4.contains("gamma"));
- QVERIFY(set4.contains("delta"));
- QVERIFY(set4.contains("epsilon"));
- QVERIFY(set4.contains("zeta"));
- QVERIFY(set4.contains("iota"));
- QVERIFY(set4.contains("omega"));
-
- QVERIFY(set3 == set4);
-
- Set<QString> set5 = set1;
- set5.intersect(set2);
- QVERIFY(set5.size() == 4);
- QVERIFY(set5.contains("beta"));
- QVERIFY(set5.contains("gamma"));
- QVERIFY(set5.contains("delta"));
- QVERIFY(set5.contains("omega"));
-
- Set<QString> set6 = set2;
- set6.intersect(set1);
- QVERIFY(set6.size() == 4);
- QVERIFY(set6.contains("beta"));
- QVERIFY(set6.contains("gamma"));
- QVERIFY(set6.contains("delta"));
- QVERIFY(set6.contains("omega"));
-
- QVERIFY(set5 == set6);
-
- Set<QString> set7 = set1;
- set7.subtract(set2);
- QVERIFY(set7.size() == 2);
- QVERIFY(set7.contains("alpha"));
- QVERIFY(set7.contains("zeta"));
-
- Set<QString> set8 = set2;
- set8.subtract(set1);
- QVERIFY(set8.size() == 2);
- QVERIFY(set8.contains("epsilon"));
- QVERIFY(set8.contains("iota"));
-
- Set<QString> set9 = set1 | set2;
- QVERIFY(set9 == set3);
-
- Set<QString> set10 = set1 & set2;
- QVERIFY(set10 == set5);
-
- Set<QString> set11 = set1 + set2;
- QVERIFY(set11 == set3);
-
- Set<QString> set12 = set1 - set2;
- QVERIFY(set12 == set7);
-
- Set<QString> set13 = set2 - set1;
- QVERIFY(set13 == set8);
-
- Set<QString> set14 = set1;
- set14 |= set2;
- QVERIFY(set14 == set3);
-
- Set<QString> set15 = set1;
- set15 &= set2;
- QVERIFY(set15 == set5);
-
- Set<QString> set16 = set1;
- set16 += set2;
- QVERIFY(set16 == set3);
-
- Set<QString> set17 = set1;
- set17 -= set2;
- QVERIFY(set17 == set7);
-
- Set<QString> set18 = set2;
- set18 -= set1;
- QVERIFY(set18 == set8);
-}
-
-void TestTools::set_makeSureTheComfortFunctionsCompile()
-{
- Set<int> set1, set2, set3;
- set1 << 5;
- set1 |= set2;
- set1 |= 5;
- set1 &= set2;
- set1 &= 5;
- set1 += set2;
- set1 += 5;
- set1 -= set2;
- set1 -= 5;
- set1 = set2 | set3;
- set1 = set2 & set3;
- set1 = set2 + set3;
- set1 = set2 - set3;
-}
-
-void TestTools::set_initializerList()
-{
- Set<int> set = {1, 1, 2, 3, 4, 5};
- QCOMPARE(set.count(), 5);
- QVERIFY(set.contains(1));
- QVERIFY(set.contains(2));
- QVERIFY(set.contains(3));
- QVERIFY(set.contains(4));
- QVERIFY(set.contains(5));
-
- // check _which_ of the equal elements gets inserted (in the QHash/QMap case, it's the last):
- const Set<IdentityTracker> set2 = {{1, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
- QCOMPARE(set2.count(), 5);
- const int dummy = -1;
- const IdentityTracker searchKey = {1, dummy};
- QCOMPARE(set2.find(searchKey)->id, 0);
-
- Set<int> emptySet{};
- QVERIFY(emptySet.isEmpty());
-
- Set<int> set3{{}, {}, {}};
- QVERIFY(!set3.isEmpty());
-}
-
-void TestTools::set_intersects()
-{
- Set<int> s1;
- Set<int> s2;
-
- QVERIFY(!s1.intersects(s1));
- QVERIFY(!s1.intersects(s2));
-
- s1 << 100;
- QVERIFY(s1.intersects(s1));
- QVERIFY(!s1.intersects(s2));
-
- s2 << 200;
- QVERIFY(!s1.intersects(s2));
-
- s1 << 200;
- QVERIFY(s1.intersects(s2));
-
- Set<int> s3;
- s3 << 500;
- QVERIFY(!s1.intersects(s3));
- s3 << 200;
- QVERIFY(s1.intersects(s3));
-}
-
-} // namespace Internal
-} // namespace qbs
diff --git a/src/lib/corelib/use_corelib.pri b/src/lib/corelib/use_corelib.pri
index 4b0751470..e79fcce04 100644
--- a/src/lib/corelib/use_corelib.pri
+++ b/src/lib/corelib/use_corelib.pri
@@ -45,3 +45,4 @@ CONFIG(static, static|shared) {
DEFINES += QBS_STATIC_LIB
}
qbs_enable_project_file_updates:DEFINES += QBS_ENABLE_PROJECT_FILE_UPDATES
+qbs_enable_unit_tests:DEFINES += QBS_ENABLE_UNIT_TESTS
diff --git a/src/lib/corelib/use_installed_corelib.pri b/src/lib/corelib/use_installed_corelib.pri
index d8bed5038..fefa774ff 100644
--- a/src/lib/corelib/use_installed_corelib.pri
+++ b/src/lib/corelib/use_installed_corelib.pri
@@ -35,3 +35,4 @@ CONFIG(static, static|shared) {
DEFINES += QBS_STATIC_LIB
}
qbs_enable_project_file_updates:DEFINES += QBS_ENABLE_PROJECT_FILE_UPDATES
+qbs_enable_unit_tests:DEFINES += QBS_ENABLE_UNIT_TESTS
diff --git a/src/lib/library.pri b/src/lib/library.pri
index ce7ab7e45..63f48a9a7 100644
--- a/src/lib/library.pri
+++ b/src/lib/library.pri
@@ -13,6 +13,7 @@ CONFIG(static, static|shared) {
DEFINES += QBS_LIBRARY
}
DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_PROCESS_COMBINED_ARGUMENT_START
+qbs_enable_unit_tests:DEFINES += QBS_ENABLE_UNIT_TESTS
INCLUDEPATH += $${PWD}/../
contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
win32:CONFIG(debug, debug|release):TARGET = $${TARGET}d
diff --git a/tests/auto/auto.pri b/tests/auto/auto.pri
index 7ea658313..f0d6e9be4 100644
--- a/tests/auto/auto.pri
+++ b/tests/auto/auto.pri
@@ -1,7 +1,7 @@
TEMPLATE = app
DESTDIR = ../../../bin
DEFINES += SRCDIR=\\\"$$_PRO_FILE_PWD_\\\"
-INCLUDEPATH += $$PWD/../../src
+INCLUDEPATH += $$PWD/../../src $$PWD/../../src/app/shared
QT = core testlib
CONFIG += depend_includepath testcase console
diff --git a/tests/auto/buildgraph/buildgraph.pro b/tests/auto/buildgraph/buildgraph.pro
index 4388aac1e..10f8c071b 100644
--- a/tests/auto/buildgraph/buildgraph.pro
+++ b/tests/auto/buildgraph/buildgraph.pro
@@ -1,6 +1,7 @@
TARGET = tst_buildgraph
SOURCES = tst_buildgraph.cpp
+HEADERS = tst_buildgraph.h
include(../auto.pri)
include(../../../src/app/shared/logging/logging.pri)
diff --git a/tests/auto/buildgraph/buildgraph.qbs b/tests/auto/buildgraph/buildgraph.qbs
index f6c1cd1f7..aa3cdc3f0 100644
--- a/tests/auto/buildgraph/buildgraph.qbs
+++ b/tests/auto/buildgraph/buildgraph.qbs
@@ -3,5 +3,8 @@ import qbs
QbsAutotest {
testName: "buildgraph"
condition: qbsbuildconfig.enableUnitTests
- files: "tst_buildgraph.cpp"
+ files: [
+ "tst_buildgraph.cpp",
+ "tst_buildgraph.h"
+ ]
}
diff --git a/tests/auto/buildgraph/tst_buildgraph.cpp b/tests/auto/buildgraph/tst_buildgraph.cpp
index be45f5f03..04d32c1fd 100644
--- a/tests/auto/buildgraph/tst_buildgraph.cpp
+++ b/tests/auto/buildgraph/tst_buildgraph.cpp
@@ -5,7 +5,7 @@
**
** This file is part of Qbs.
**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -14,26 +14,133 @@
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-#include <app/shared/logging/consolelogger.h>
-#include <buildgraph/tst_buildgraph.h>
+#include "tst_buildgraph.h"
+
+#include <buildgraph/artifact.h>
+#include <buildgraph/buildgraph.h>
+#include <buildgraph/cycledetector.h>
+#include <buildgraph/productbuilddata.h>
+#include <buildgraph/projectbuilddata.h>
+#include <language/language.h>
+#include <logging/logger.h>
+#include <tools/error.h>
+
+#include "../shared/logging/consolelogger.h"
-#include <QtCore/qcoreapplication.h>
#include <QtTest/qtest.h>
+using namespace qbs;
+using namespace qbs::Internal;
+
+const TopLevelProjectPtr project = TopLevelProject::create();
+
+TestBuildGraph::TestBuildGraph(ILogSink *logSink) : m_logSink(logSink)
+{
+ project->buildData.reset(new ProjectBuildData);
+}
+
+void TestBuildGraph::initTestCase()
+{
+}
+
+void TestBuildGraph::cleanupTestCase()
+{
+}
+
+
+bool TestBuildGraph::cycleDetected(const ResolvedProductConstPtr &product)
+{
+ try {
+ CycleDetector(Logger(m_logSink)).visitProduct(product);
+ return false;
+ } catch (const ErrorInfo &) {
+ return true;
+ }
+}
+
+ResolvedProductConstPtr TestBuildGraph::productWithDirectCycle()
+{
+ const ResolvedProductPtr product = ResolvedProduct::create();
+ product->project = project;
+ product->buildData.reset(new ProductBuildData);
+ Artifact * const root = new Artifact;
+ root->product = product;
+ Artifact * const child = new Artifact;
+ child->product = product;
+ product->buildData->roots.insert(root);
+ product->buildData->nodes << root << child;
+ qbs::Internal::connect(root, child);
+ qbs::Internal::connect(child, root);
+ return product;
+}
+
+ResolvedProductConstPtr TestBuildGraph::productWithLessDirectCycle()
+{
+ const ResolvedProductPtr product = ResolvedProduct::create();
+ product->project = project;
+ product->buildData.reset(new ProductBuildData);
+ Artifact * const root = new Artifact;
+ Artifact * const child = new Artifact;
+ Artifact * const grandchild = new Artifact;
+ root->product = product;
+ child->product = product;
+ grandchild->product = product;
+ product->buildData->roots << root;
+ product->buildData->nodes << root << child << grandchild;
+ qbs::Internal::connect(root, child);
+ qbs::Internal::connect(child, grandchild);
+ qbs::Internal::connect(grandchild, root);
+ return product;
+}
+
+// root appears as a child, but in a different tree
+ResolvedProductConstPtr TestBuildGraph::productWithNoCycle()
+{
+ const ResolvedProductPtr product = ResolvedProduct::create();
+ product->project = project;
+ product->buildData.reset(new ProductBuildData);
+ Artifact * const root = new Artifact;
+ Artifact * const root2 = new Artifact;
+ root->product = product;
+ root2->product = product;
+ product->buildData->roots << root << root2;
+ product->buildData->nodes << root << root2;
+ qbs::Internal::connect(root2, root);
+ return product;
+}
+
+void TestBuildGraph::testCycle()
+{
+ QVERIFY(cycleDetected(productWithDirectCycle()));
+ QVERIFY(cycleDetected(productWithLessDirectCycle()));
+ QVERIFY(!cycleDetected(productWithNoCycle()));
+}
+
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
- qbs::Internal::TestBuildGraph tbg(ConsoleLogger::instance().logSink());
+ TestBuildGraph tbg(ConsoleLogger::instance().logSink());
return QTest::qExec(&tbg, argc, argv);
}
diff --git a/src/lib/corelib/buildgraph/tst_buildgraph.h b/tests/auto/buildgraph/tst_buildgraph.h
index e33037b30..756be2f0a 100644
--- a/src/lib/corelib/buildgraph/tst_buildgraph.h
+++ b/tests/auto/buildgraph/tst_buildgraph.h
@@ -42,19 +42,15 @@
#include <buildgraph/forward_decls.h>
#include <language/forward_decls.h>
#include <logging/ilogsink.h>
-#include <tools/qbs_export.h>
#include <QtCore/qlist.h>
#include <QtCore/qobject.h>
-namespace qbs {
-namespace Internal {
-
-class QBS_EXPORT TestBuildGraph : public QObject
+class TestBuildGraph : public QObject
{
Q_OBJECT
public:
- TestBuildGraph(ILogSink *logSink);
+ TestBuildGraph(qbs::ILogSink *logSink);
private slots:
void initTestCase();
@@ -62,15 +58,13 @@ private slots:
void testCycle();
private:
- ResolvedProductConstPtr productWithDirectCycle();
- ResolvedProductConstPtr productWithLessDirectCycle();
- ResolvedProductConstPtr productWithNoCycle();
- bool cycleDetected(const ResolvedProductConstPtr &product);
+ qbs::Internal::ResolvedProductConstPtr productWithDirectCycle();
+ qbs::Internal::ResolvedProductConstPtr productWithLessDirectCycle();
+ qbs::Internal::ResolvedProductConstPtr productWithNoCycle();
+ bool cycleDetected(const qbs::Internal::ResolvedProductConstPtr &product);
- ILogSink * const m_logSink;
+ qbs::ILogSink * const m_logSink;
};
-} // namespace Internal
-} // namespace qbs
-
#endif // TST_BUILDGRAPH_H
+
diff --git a/tests/auto/language/language.pro b/tests/auto/language/language.pro
index 1206bd328..118d0f95c 100644
--- a/tests/auto/language/language.pro
+++ b/tests/auto/language/language.pro
@@ -1,10 +1,13 @@
TARGET = tst_language
SOURCES = tst_language.cpp
+HEADERS = tst_language.h
include(../auto.pri)
include(../../../src/app/shared/logging/logging.pri)
+QT += script
+
DATA_DIRS = testdata
for(data_dir, DATA_DIRS) {
diff --git a/tests/auto/language/language.qbs b/tests/auto/language/language.qbs
index b78c568a6..27f390e94 100644
--- a/tests/auto/language/language.qbs
+++ b/tests/auto/language/language.qbs
@@ -1,9 +1,21 @@
import qbs
QbsAutotest {
+ Depends { name: "qbsversion" }
+ Depends { name: "Qt.script" }
+
testName: "language"
condition: qbsbuildconfig.enableUnitTests
- files: "tst_language.cpp"
+ files: [
+ "tst_language.cpp",
+ "tst_language.h"
+ ]
+
+ // TODO: Use Utilities.cStringQuote
+ cpp.defines: base.concat([
+ 'QBS_VERSION="' + qbsversion.version + '"',
+ "SRCDIR=\"" + path + "\""
+ ])
Group {
name: "testdata"
diff --git a/tests/auto/language/tst_language.cpp b/tests/auto/language/tst_language.cpp
index 688b20089..3b076032c 100644
--- a/tests/auto/language/tst_language.cpp
+++ b/tests/auto/language/tst_language.cpp
@@ -5,7 +5,7 @@
**
** This file is part of Qbs.
**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -14,33 +14,2440 @@
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
+#undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack.
+
+#include "tst_language.h"
+
#include "../shared.h"
-#include <language/tst_language.h>
+#include <language/evaluator.h>
+#include <language/filecontext.h>
+#include <language/identifiersearch.h>
+#include <language/item.h>
+#include <language/itempool.h>
+#include <language/language.h>
+#include <language/propertymapinternal.h>
+#include <language/scriptengine.h>
+#include <language/value.h>
+#include <parser/qmljslexer_p.h>
+#include <parser/qmljsparser_p.h>
+#include <tools/scripttools.h>
+#include <tools/error.h>
+#include <tools/fileinfo.h>
+#include <tools/hostosinfo.h>
+#include <tools/jsliterals.h>
+#include <tools/profile.h>
+#include <tools/settings.h>
+
+#include "../shared/logging/consolelogger.h"
-#include <app/shared/logging/consolelogger.h>
+#include <QtCore/qprocess.h>
-#include <QtCore/qcoreapplication.h>
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+Q_DECLARE_METATYPE(QList<bool>)
+
+using namespace qbs;
+using namespace qbs::Internal;
+
+static QString testDataDir() {
+ return FileInfo::resolvePath(QLatin1String(SRCDIR),
+ QLatin1String("../../../tests/auto/language/testdata"));
+}
+static QString testProject(const char *fileName) {
+ return testDataDir() + QLatin1Char('/') + QLatin1String(fileName);
+}
-#include <QtTest/qtest.h>
+TestLanguage::TestLanguage(ILogSink *logSink, Settings *settings)
+ : m_logSink(logSink)
+ , m_settings(settings)
+ , m_wildcardsTestDirPath(QDir::tempPath() + QLatin1String("/_wildcards_test_dir_"))
+{
+ qsrand(QTime::currentTime().msec());
+ qRegisterMetaType<QList<bool> >("QList<bool>");
+ defaultParameters.setBuildRoot("/some/build/directory");
+ defaultParameters.setPropertyCheckingMode(ErrorHandlingMode::Strict);
+ defaultParameters.setSettingsDirectory(m_settings->baseDirectory());
+}
+
+TestLanguage::~TestLanguage()
+{
+}
+
+QHash<QString, ResolvedProductPtr> TestLanguage::productsFromProject(ResolvedProjectPtr project)
+{
+ QHash<QString, ResolvedProductPtr> result;
+ foreach (const ResolvedProductPtr &product, project->allProducts())
+ result.insert(product->name, product);
+ return result;
+}
+
+ResolvedModuleConstPtr TestLanguage::findModuleByName(ResolvedProductPtr product, const QString &name)
+{
+ foreach (const ResolvedModuleConstPtr &module, product->modules)
+ if (module->name == name)
+ return module;
+ return ResolvedModuleConstPtr();
+}
+
+QVariant TestLanguage::productPropertyValue(ResolvedProductPtr product, QString propertyName)
+{
+ QStringList propertyNameComponents = propertyName.split(QLatin1Char('.'));
+ if (propertyNameComponents.count() > 1) {
+ propertyNameComponents.prepend(QLatin1String("modules"));
+ return product->moduleProperties->property(propertyNameComponents);
+ }
+ return getConfigProperty(product->productProperties, propertyNameComponents);
+}
+
+void TestLanguage::handleInitCleanupDataTags(const char *projectFileName, bool *handled)
+{
+ const QByteArray dataTag = QTest::currentDataTag();
+ if (dataTag == "init") {
+ *handled = true;
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject(projectFileName));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+ } else if (dataTag == "cleanup") {
+ *handled = true;
+ project.reset();
+ } else {
+ *handled = false;
+ }
+}
+
+void TestLanguage::init()
+{
+ m_logSink->setLogLevel(LoggerInfo);
+}
+
+#define HANDLE_INIT_CLEANUP_DATATAGS(fn) {\
+ bool handled;\
+ handleInitCleanupDataTags(fn, &handled);\
+ if (handled)\
+ return;\
+ QVERIFY(!!project);\
+}
+
+void TestLanguage::initTestCase()
+{
+ m_logger = Logger(m_logSink);
+ m_engine = new ScriptEngine(m_logger, EvalContext::PropertyEvaluation, this);
+ loader = new Loader(m_engine, m_logger);
+ loader->setSearchPaths(QStringList()
+ << QLatin1String(SRCDIR "/../../../share/qbs"));
+ defaultParameters.setTopLevelProfile(profileName());
+ defaultParameters.setConfigurationName("default");
+ defaultParameters.expandBuildConfiguration();
+ defaultParameters.setEnvironment(QProcessEnvironment::systemEnvironment());
+ QVERIFY(QFileInfo(m_wildcardsTestDirPath).isAbsolute());
+}
+
+void TestLanguage::cleanupTestCase()
+{
+ delete loader;
+}
+
+void TestLanguage::baseProperty()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("baseproperty.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(!!product);
+ QVariantMap cfg = product->productProperties;
+ QCOMPARE(cfg.value("narf").toStringList(), QStringList() << "boo");
+ QCOMPARE(cfg.value("zort").toStringList(), QStringList() << "bar" << "boo");
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::baseValidation()
+{
+ qbs::SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("base-validate/base-validate.qbs"));
+ try {
+ project = loader->loadProject(params);
+ QVERIFY2(false, "exception expected");
+ } catch (const qbs::ErrorInfo &e) {
+ QVERIFY2(e.toString().contains("Parent succeeded, child failed."),
+ qPrintable(e.toString()));
+ }
+}
+
+void TestLanguage::buildConfigStringListSyntax()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters parameters = defaultParameters;
+ QVariantMap overriddenValues;
+ overriddenValues.insert("project.someStrings", "foo,bar,baz");
+ parameters.setOverriddenValues(overriddenValues);
+ parameters.setProjectFilePath(testProject("buildconfigstringlistsyntax.qbs"));
+ project = loader->loadProject(parameters);
+ QVERIFY(!!project);
+ QCOMPARE(project->projectProperties().value("someStrings").toStringList(),
+ QStringList() << "foo" << "bar" << "baz");
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::builtinFunctionInSearchPathsProperty()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters parameters = defaultParameters;
+ parameters.setProjectFilePath(testProject("builtinFunctionInSearchPathsProperty.qbs"));
+ QVERIFY(!!loader->loadProject(parameters));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::chainedProbes()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters parameters = defaultParameters;
+ parameters.setProjectFilePath(testProject("chained-probes/chained-probes.qbs"));
+ const TopLevelProjectConstPtr project = loader->loadProject(parameters);
+ QVERIFY(!!project);
+ QCOMPARE(project->products.count(), 1);
+ const QString prop2Val = project->products.first()->moduleProperties
+ ->moduleProperty("m", "prop2").toString();
+ QCOMPARE(prop2Val, QLatin1String("probe1Valprobe2Val"));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+
+}
+
+void TestLanguage::versionCompare()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters parameters = defaultParameters;
+ parameters.setProjectFilePath(testProject("versionCompare.qbs"));
+ QVERIFY(!!loader->loadProject(parameters));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::canonicalArchitecture()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("canonicalArchitecture.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value(QLatin1String("x86"));
+ QVERIFY(!!product);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::rfc1034Identifier()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("rfc1034identifier.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value(QLatin1String("this-has-special-characters-"
+ "uh-oh-Undersc0r3s-Are.Bad"));
+ QVERIFY(!!product);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::conditionalDepends()
+{
+ bool exceptionCaught = false;
+ ResolvedProductPtr product;
+ ResolvedModuleConstPtr dependency;
+ try {
+ defaultParameters.setProjectFilePath(testProject("conditionaldepends.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+
+ product = products.value("conditionaldepends_derived");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("conditionaldepends_derived_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QCOMPARE(dependency, ResolvedModuleConstPtr());
+
+ product = products.value("product_props_true");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("product_props_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QCOMPARE(dependency, ResolvedModuleConstPtr());
+
+ product = products.value("project_props_true");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("project_props_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QCOMPARE(dependency, ResolvedModuleConstPtr());
+
+ product = products.value("module_props_true");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy2");
+ QVERIFY(!!dependency);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("module_props_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy2");
+ QVERIFY(!!dependency);
+ dependency = findModuleByName(product, "dummy");
+ QCOMPARE(dependency, ResolvedModuleConstPtr());
+
+ product = products.value("contradictory_conditions1");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("contradictory_conditions2");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("unknown_dependency_condition_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "doesonlyexistifhellfreezesover");
+ QVERIFY(!dependency);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::delayedError()
+{
+ QFETCH(bool, productEnabled);
+ try {
+ QFETCH(QString, projectFileName);
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject(projectFileName.toLatin1()));
+ QVariantMap overriddenValues;
+ overriddenValues.insert("project.enableProduct", productEnabled);
+ params.setOverriddenValues(overriddenValues);
+ project = loader->loadProject(params);
+ QCOMPARE(productEnabled, false);
+ QVERIFY(!!project);
+ QCOMPARE(project->products.count(), 1);
+ const ResolvedProductConstPtr theProduct = productsFromProject(project).value("theProduct");
+ QVERIFY(!!theProduct);
+ QCOMPARE(theProduct->enabled, false);
+ } catch (const ErrorInfo &e) {
+ if (!productEnabled)
+ qDebug() << e.toString();
+ QCOMPARE(productEnabled, true);
+ }
+}
+
+void TestLanguage::delayedError_data()
+{
+ QTest::addColumn<QString>("projectFileName");
+ QTest::addColumn<bool>("productEnabled");
+ QTest::newRow("product enabled, module validation error")
+ << "delayed-error/validation.qbs" << true;
+ QTest::newRow("product disabled, module validation error")
+ << "delayed-error/validation.qbs" << false;
+ QTest::newRow("product enabled, module not found")
+ << "delayed-error/nonexisting.qbs" << true;
+ QTest::newRow("product disabled, module not found")
+ << "delayed-error/nonexisting.qbs" << false;
+}
+
+void TestLanguage::dependencyOnAllProfiles()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("dependencyOnAllProfiles.qbs"));
+ TemporaryProfile p1("p1", m_settings);
+ p1.p.setValue("qbs.architecture", "arch1");
+ TemporaryProfile p2("p2", m_settings);
+ p2.p.setValue("qbs.architecture", "arch2");
+ QVariantMap overriddenValues;
+ overriddenValues.insert("project.profile1", "p1");
+ overriddenValues.insert("project.profile2", "p2");
+ params.setOverriddenValues(overriddenValues);
+ project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QCOMPARE(project->products.count(), 3);
+ const ResolvedProductConstPtr mainProduct = productsFromProject(project).value("main");
+ QVERIFY(!!mainProduct);
+ QCOMPARE(mainProduct->dependencies.count(), 2);
+ foreach (const ResolvedProductConstPtr &p, mainProduct->dependencies) {
+ QCOMPARE(p->name, QLatin1String("dep"));
+ QVERIFY(p->profile == "p1" || p->profile == "p2");
+ }
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::derivedSubProject()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("derived-sub-project/project.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::enumerateProjectProperties()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("enum-project-props.qbs"));
+ auto project = loader->loadProject(params);
+ QVERIFY(!!project);
+ auto products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ auto product = products.values().first();
+ auto files = product->groups.first()->allFiles();
+ QCOMPARE(product->groups.count(), 1);
+ QCOMPARE(files.count(), 1);
+ auto fileName = FileInfo::fileName(files.first()->absoluteFilePath);
+ QCOMPARE(fileName, QString("dummy.txt"));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::defaultValue()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("defaultvalue/egon.qbs"));
+ QFETCH(QString, prop1Value);
+ QVariantMap overridden;
+ if (!prop1Value.isEmpty())
+ overridden.insert("modules.lower.prop1", prop1Value);
+ params.setOverriddenValues(overridden);
+ TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 2);
+ const ResolvedProductPtr product = products.value("egon");
+ QVERIFY(!!product);
+ QStringList propertyName = QStringList() << "modules" << "lower" << "prop2";
+ QVariant propertyValue = product->moduleProperties->property(propertyName);
+ QFETCH(QVariant, expectedProp2Value);
+ QCOMPARE(propertyValue, expectedProp2Value);
+ propertyName = QStringList() << "modules" << "lower" << "listProp";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QFETCH(QVariant, expectedListPropValue);
+ QCOMPARE(propertyValue.toStringList(), expectedListPropValue.toStringList());
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::defaultValue_data()
+{
+ QTest::addColumn<QString>("prop1Value");
+ QTest::addColumn<QVariant>("expectedProp2Value");
+ QTest::addColumn<QVariant>("expectedListPropValue");
+ QTest::newRow("controlling property with random value") << "random" << QVariant("withoutBlubb")
+ << QVariant(QStringList({"other"}));
+ QTest::newRow("controlling property with blubb value") << "blubb" << QVariant("withBlubb")
+ << QVariant(QStringList({"blubb", "other"}));
+ QTest::newRow("controlling property with egon value") << "egon" << QVariant("withEgon")
+ << QVariant(QStringList({"egon", "other"}));
+ QTest::newRow("controlling property not overwritten") << "" << QVariant("withBlubb")
+ << QVariant(QStringList({"blubb", "other"}));
+}
+
+void TestLanguage::environmentVariable()
+{
+ bool exceptionCaught = false;
+ try {
+ // Create new environment:
+ const QString varName = QLatin1String("PRODUCT_NAME");
+ const QString productName = QLatin1String("MyApp") + QString::number(qrand());
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert(varName, productName);
+
+ QProcessEnvironment origEnv = defaultParameters.environment(); // store orig environment
+
+ defaultParameters.setEnvironment(env);
+ defaultParameters.setProjectFilePath(testProject("environmentvariable.qbs"));
+ project = loader->loadProject(defaultParameters);
+
+ defaultParameters.setEnvironment(origEnv); // reset environment
+
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value(productName);
+ QVERIFY(!!product);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::erroneousFiles_data()
+{
+ QTest::addColumn<QString>("errorMessage");
+ QTest::newRow("unknown_module")
+ << "Dependency 'neitherModuleNorProduct' not found";
+ QTest::newRow("multiple_exports")
+ << "Multiple Export items in one product are prohibited.";
+ QTest::newRow("multiple_properties_in_subproject")
+ << "Multiple instances of item 'Properties' found where at most one "
+ "is allowed.";
+ QTest::newRow("importloop1")
+ << "Loop detected when importing";
+ QTest::newRow("nonexistentouter")
+ << "Can't find variable: outer";
+ QTest::newRow("invalid_file")
+ << "does not exist";
+ QTest::newRow("invalid-parameter-rhs")
+ << "ReferenceError: Can't find variable: access";
+ QTest::newRow("invalid-parameter-type")
+ << "Value assigned to property 'stringParameter' does not have type 'string'.";
+ QTest::newRow("invalid_property_type")
+ << "Unknown type 'nonsense' in property declaration.";
+ QTest::newRow("reserved_name_in_import")
+ << "Cannot reuse the name of built-in extension 'TextFile'.";
+ QTest::newRow("throw_in_property_binding")
+ << "something is wrong";
+ QTest::newRow("dependency_cycle")
+ << "Cyclic dependencies detected.";
+ QTest::newRow("dependency_cycle2")
+ << "Cyclic dependencies detected.";
+ QTest::newRow("dependency_cycle3")
+ << "Cyclic dependencies detected.";
+ QTest::newRow("dependency_cycle4")
+ << "Cyclic dependencies detected.";
+ QTest::newRow("references_cycle")
+ << "Cycle detected while referencing file 'references_cycle.qbs'.";
+ QTest::newRow("subproject_cycle")
+ << "Cycle detected while loading subproject file 'subproject_cycle.qbs'.";
+ QTest::newRow("invalid_stringlist_element")
+ << "Element at index 1 of list property 'files' does not have string type.";
+ QTest::newRow("undefined_stringlist_element")
+ << "Element at index 1 of list property 'files' is undefined. String expected.";
+ QTest::newRow("undeclared_item")
+ << "Item 'cpp' is not declared.";
+ QTest::newRow("undeclared-parameter1")
+ << "Parameter 'prefix2.suffix.nope' is not declared.";
+ QTest::newRow("undeclared-parameter2")
+ << "Cannot set parameter 'foo.bar', "
+ "because 'myproduct' does not have a dependency on 'foo'.";
+ QTest::newRow("undeclared_property_wrapper")
+ << "Property 'doesntexist' is not declared.";
+ QTest::newRow("undeclared_property_in_export_item")
+ << "Property 'blubb' is not declared.";
+ QTest::newRow("undeclared_property_in_export_item2")
+ << "Item 'something' is not declared.";
+ QTest::newRow("undeclared_property_in_export_item3")
+ << "Property 'blubb' is not declared.";
+ QTest::newRow("unknown_item_type")
+ << "Unexpected item type 'Narf'";
+ QTest::newRow("invalid_child_item_type")
+ << "Items of type 'Project' cannot contain items of type 'Depends'.";
+ QTest::newRow("conflicting_fileTagsFilter")
+ << "Conflicting fileTagsFilter in Group items";
+ QTest::newRow("duplicate_sources")
+ << "Duplicate source file '.*main.cpp'"
+ ".*duplicate_sources.qbs:4:12.*duplicate_sources.qbs:6:16.";
+ QTest::newRow("duplicate_sources_wildcards")
+ << "Duplicate source file '.*duplicate_sources_wildcards.qbs'"
+ ".*duplicate_sources_wildcards.qbs:4:12"
+ ".*duplicate_sources_wildcards.qbs:6:16.";
+ QTest::newRow("oldQbsVersion")
+ << "The project requires at least qbs version \\d+\\.\\d+.\\d+, "
+ "but this is qbs version " QBS_VERSION ".";
+ QTest::newRow("wrongQbsVersionFormat")
+ << "The value '.*' of Project.minimumQbsVersion is not a valid version string.";
+ QTest::newRow("properties-item-with-invalid-condition")
+ << "TypeError: Result of expression 'cpp.nonexistingproperty'";
+ QTest::newRow("misused-inherited-property") << "Binding to non-item property";
+ QTest::newRow("undeclared_property_in_Properties_item") << "Item 'blubb' is not declared";
+ QTest::newRow("same-module-prefix1") << "The name of module 'prefix1' is equal to the first "
+ "component of the name of module 'prefix1.suffix'";
+ QTest::newRow("same-module-prefix2") << "The name of module 'prefix2' is equal to the first "
+ "component of the name of module 'prefix2.suffix'";
+ QTest::newRow("conflicting-properties-in-export-items")
+ << "Export item in inherited item redeclares property 'theProp' with different type.";
+ QTest::newRow("invalid-property-option")
+ << "PropertyOptions item refers to non-existing property 's0meProp'";
+ QTest::newRow("missing-colon")
+ << "Invalid item 'cpp.dynamicLibraries'. Did you mean to set a module property?";
+ QTest::newRow("wrong-toplevel-item")
+ << "wrong-toplevel-item.qbs:3:1.*The top-level item must be of type 'Project' or "
+ "'Product', but it is of type 'Artifact'.";
+ QTest::newRow("module-depends-on-product")
+ << "module-with-product-dependency.qbs:4:5.*Modules cannot depend on products.";
+ QTest::newRow("overwrite-inherited-readonly-property")
+ << "overwrite-inherited-readonly-property.qbs"
+ ":4:21.*Cannot set read-only property 'readOnlyString'.";
+ QTest::newRow("overwrite-readonly-module-property")
+ << "overwrite-readonly-module-property.qbs"
+ ":5:30.*Cannot set read-only property 'readOnlyString'.";
+ QTest::newRow("mismatching-multiplex-dependency")
+ << "mismatching-multiplex-dependency.qbs:9:5 Dependency from product 'b' to "
+ "product 'a' not fulfilled.\nNo product 'a' found with a matching multiplex "
+ "configuration:\n\tqbs.architecture: mips";
+}
+
+void TestLanguage::erroneousFiles()
+{
+ QFETCH(QString, errorMessage);
+ QString fileName = QString::fromLocal8Bit(QTest::currentDataTag()) + QLatin1String(".qbs");
+ try {
+ defaultParameters.setProjectFilePath(testProject("/erroneous/") + fileName);
+ loader->loadProject(defaultParameters);
+ } catch (const ErrorInfo &e) {
+ if (!e.toString().contains(QRegExp(errorMessage))) {
+ qDebug() << "Message: " << e.toString();
+ qDebug() << "Expected: " << errorMessage;
+ QFAIL("Unexpected error message.");
+ }
+ return;
+ }
+ QEXPECT_FAIL("undeclared_property_in_Properties_item", "Too expensive to check", Continue);
+ QVERIFY(!"No error thrown on invalid input.");
+}
+
+void TestLanguage::exports()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("exports.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 17);
+ ResolvedProductPtr product;
+ product = products.value("myapp");
+ QVERIFY(!!product);
+ QStringList propertyName = QStringList() << "modules" << "dummy" << "defines";
+ QVariant propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYAPP" << "USE_MYLIB"
+ << "USE_MYLIB2");
+ propertyName = QStringList() << "modules" << "dummy" << "includePaths";
+ QVariantList propertyValues = product->moduleProperties->property(propertyName).toList();
+ QCOMPARE(propertyValues.count(), 3);
+ QVERIFY(propertyValues.at(0).toString().endsWith("/app"));
+ QVERIFY(propertyValues.at(1).toString().endsWith("/subdir/lib"));
+ QVERIFY(propertyValues.at(2).toString().endsWith("/subdir2/lib"));
+
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
+ QString("myapp"));
+
+ product = products.value("mylib");
+ QVERIFY(!!product);
+ propertyName = QStringList() << "modules" << "dummy" << "defines";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYLIB");
+
+ product = products.value("mylib2");
+ QVERIFY(!!product);
+ propertyName = QStringList() << "modules" << "dummy" << "defines";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYLIB2");
+
+ product = products.value("A");
+ QVERIFY(!!product);
+ QVERIFY(product->dependencies.contains(products.value("B")));
+ QVERIFY(product->dependencies.contains(products.value("C")));
+ QVERIFY(product->dependencies.contains(products.value("D")));
+ product = products.value("B");
+ QVERIFY(!!product);
+ QVERIFY(product->dependencies.isEmpty());
+ product = products.value("C");
+ QVERIFY(!!product);
+ QVERIFY(product->dependencies.isEmpty());
+ product = products.value("D");
+ QVERIFY(!!product);
+ QVERIFY(product->dependencies.isEmpty());
+
+ product = products.value("myapp2");
+ QVERIFY(!!product);
+ propertyName = QStringList() << "modules" << "dummy" << "cFlags";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList()
+ << "BASE_PRODUCTWITHINHERITEDEXPORTITEM"
+ << "PRODUCT_PRODUCTWITHINHERITEDEXPORTITEM");
+ propertyName = QStringList() << "modules" << "dummy" << "cxxFlags";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList() << "-bar");
+ propertyName = QStringList() << "modules" << "dummy" << "defines";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList() << "ABC");
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
+ QString("myapp2"));
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy",
+ "upperCaseProductName").toString(), QString("MYAPP2"));
+
+ // Check whether we're returning incorrect cached values.
+ product = products.value("myapp3");
+ QVERIFY(!!product);
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
+ QString("myapp3"));
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy",
+ "upperCaseProductName").toString(), QString("MYAPP3"));
+
+ // Verify we refer to the right "project" variable.
+ product = products.value("sub p2");
+ QVERIFY(!!product);
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy", "someString").toString(),
+ QString("sub1"));
+
+ product = products.value("libE");
+ QVERIFY(!!product);
+ propertyName = QStringList() << "modules" << "dummy" << "defines";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(),
+ QStringList() << "LIBA" << "LIBB" << "LIBC" << "LIBD");
+ propertyName = QStringList() << "modules" << "dummy" << "productName";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toString(), QString("libE"));
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::fileContextProperties()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("filecontextproperties.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(!!product);
+ QVariantMap cfg = product->productProperties;
+ QCOMPARE(cfg.value("narf").toString(), defaultParameters.projectFilePath());
+ QString dirPath = QFileInfo(defaultParameters.projectFilePath()).absolutePath();
+ QCOMPARE(cfg.value("zort").toString(), dirPath);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::getNativeSetting()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("getNativeSetting.qbs"));
+ project = loader->loadProject(defaultParameters);
+
+ QString expectedTargetName;
+ if (HostOsInfo::isMacosHost())
+ expectedTargetName = QLatin1String("Mac OS X");
+ else if (HostOsInfo::isWindowsHost())
+ expectedTargetName = QLatin1String("Windows");
+ else
+ expectedTargetName = QLatin1String("Unix");
+
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products;
+ for (const ResolvedProductPtr &product : project->allProducts())
+ products.insert(product->targetName, product);
+ ResolvedProductPtr product = products.value(expectedTargetName);
+ QVERIFY(!!product);
+ ResolvedProductPtr product2 = products.value(QLatin1String("fallback"));
+ QVERIFY(!!product2);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::groupConditions_data()
+{
+ QTest::addColumn<int>("groupCount");
+ QTest::addColumn<QList<bool> >("groupEnabled");
+ QTest::newRow("init") << 0 << QList<bool>();
+ QTest::newRow("no_condition_no_group")
+ << 1 << (QList<bool>() << true);
+ QTest::newRow("no_condition")
+ << 2 << (QList<bool>() << true << true);
+ QTest::newRow("true_condition")
+ << 2 << (QList<bool>() << true << true);
+ QTest::newRow("false_condition")
+ << 2 << (QList<bool>() << true << false);
+ QTest::newRow("true_condition_from_product")
+ << 2 << (QList<bool>() << true << true);
+ QTest::newRow("true_condition_from_project")
+ << 2 << (QList<bool>() << true << true);
+ QTest::newRow("condition_accessing_module_property")
+ << 2 << (QList<bool>() << true << false);
+ QTest::newRow("cleanup") << 0 << QList<bool>();
+}
+
+void TestLanguage::groupConditions()
+{
+ HANDLE_INIT_CLEANUP_DATATAGS("groupconditions.qbs");
+ QFETCH(int, groupCount);
+ QFETCH(QList<bool>, groupEnabled);
+ QCOMPARE(groupCount, groupEnabled.count());
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
+ ResolvedProductPtr product = products.value(productName);
+ QVERIFY(!!product);
+ QCOMPARE(product->name, productName);
+ QCOMPARE(product->groups.count(), groupCount);
+ for (int i = 0; i < groupCount; ++i) {
+ if (product->groups.at(i)->enabled != groupEnabled.at(i)) {
+ QFAIL(qPrintable(
+ QString("groups.at(%1)->enabled != %2").arg(i).arg(groupEnabled.at(i))));
+ }
+ }
+}
+
+void TestLanguage::groupName()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("groupname.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 2);
+
+ ResolvedProductPtr product = products.value("MyProduct");
+ QVERIFY(!!product);
+ QCOMPARE(product->groups.count(), 2);
+ GroupConstPtr group = product->groups.at(0);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("MyProduct"));
+ group = product->groups.at(1);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("MyProduct.MyGroup"));
+
+ product = products.value("My2ndProduct");
+ QVERIFY(!!product);
+ QCOMPARE(product->groups.count(), 3);
+ group = product->groups.at(0);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("My2ndProduct"));
+ group = product->groups.at(1);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("My2ndProduct.MyGroup"));
+ group = product->groups.at(2);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("Group 2"));
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::homeDirectory()
+{
+ try {
+ defaultParameters.setProjectFilePath(testProject("homeDirectory.qbs"));
+ ResolvedProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+
+ ResolvedProductPtr product = products.value("home");
+ QVERIFY(!!product);
+
+ QDir dir = QDir::home();
+ QCOMPARE(product->productProperties.value("home").toString(), dir.path());
+ QCOMPARE(product->productProperties.value("homeSlash").toString(), dir.path());
+
+ dir.cdUp();
+ QCOMPARE(product->productProperties.value("homeUp").toString(), dir.path());
+
+ dir = QDir::home();
+ QCOMPARE(product->productProperties.value("homeFile").toString(),
+ dir.filePath("a"));
+
+ QCOMPARE(product->productProperties.value("bogus1").toString(),
+ FileInfo::resolvePath(product->sourceDirectory, QLatin1String("a~b")));
+ QCOMPARE(product->productProperties.value("bogus2").toString(),
+ FileInfo::resolvePath(product->sourceDirectory, QLatin1String("a/~/bb")));
+ QCOMPARE(product->productProperties.value("user").toString(),
+ FileInfo::resolvePath(product->sourceDirectory, QLatin1String("~foo/bar")));
+ }
+ catch (const ErrorInfo &e) {
+ qDebug() << e.toString();
+ }
+}
+
+void TestLanguage::identifierSearch_data()
+{
+ QTest::addColumn<bool>("expectedHasNarf");
+ QTest::addColumn<bool>("expectedHasZort");
+ QTest::addColumn<QString>("sourceCode");
+ QTest::newRow("no narf, no zort") << false << false << QString(
+ "Product {\n"
+ " name: {\n"
+ " var foo = 'bar';\n"
+ " console.info(foo);\n"
+ " return foo;\n"
+ " }\n"
+ "}\n");
+ QTest::newRow("narf, no zort") << true << false << QString(
+ "Product {\n"
+ " name: {\n"
+ " var foo = 'zort';\n"
+ " console.info(narf + foo);\n"
+ " return foo;\n"
+ " }\n"
+ "}\n");
+ QTest::newRow("no narf, zort") << false << true << QString(
+ "Product {\n"
+ " name: {\n"
+ " var foo = 'narf';\n"
+ " console.info(zort + foo);\n"
+ " return foo;\n"
+ " }\n"
+ "}\n");
+ QTest::newRow("narf, zort") << true << true << QString(
+ "Product {\n"
+ " name: {\n"
+ " var foo = narf;\n"
+ " foo = foo + zort;\n"
+ " return foo;\n"
+ " }\n"
+ "}\n");
+ QTest::newRow("2 narfs, 1 zort") << true << true << QString(
+ "Product {\n"
+ " name: {\n"
+ " var foo = narf;\n"
+ " foo = narf + foo + zort;\n"
+ " return foo;\n"
+ " }\n"
+ "}\n");
+}
+
+void TestLanguage::identifierSearch()
+{
+ QFETCH(bool, expectedHasNarf);
+ QFETCH(bool, expectedHasZort);
+ QFETCH(QString, sourceCode);
+
+ bool hasNarf = !expectedHasNarf;
+ bool hasZort = !expectedHasZort;
+ IdentifierSearch isearch;
+ isearch.add("narf", &hasNarf);
+ isearch.add("zort", &hasZort);
+
+ QbsQmlJS::Engine engine;
+ QbsQmlJS::Lexer lexer(&engine);
+ lexer.setCode(sourceCode, 1);
+ QbsQmlJS::Parser parser(&engine);
+ QVERIFY(parser.parse());
+ QVERIFY(parser.ast());
+ isearch.start(parser.ast());
+ QCOMPARE(hasNarf, expectedHasNarf);
+ QCOMPARE(hasZort, expectedHasZort);
+}
+
+void TestLanguage::idUsage()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("idusage.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 4);
+ QVERIFY(products.contains("product1_1"));
+ QVERIFY(products.contains("product2_2"));
+ QVERIFY(products.contains("product3_3"));
+ ResolvedProductPtr product4 = products.value("product4_4");
+ QVERIFY(!!product4);
+ QEXPECT_FAIL("", "QBS-1016", Continue);
+ QCOMPARE(product4->productProperties.value("productName").toString(), product4->name);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QVERIFY(!exceptionCaught);
+}
+
+void TestLanguage::idUniqueness()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("id-uniqueness.qbs"));
+ loader->loadProject(defaultParameters);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ const QList<ErrorItem> items = e.items();
+ QCOMPARE(items.count(), 3);
+ QCOMPARE(items.at(0).toString(), QString::fromUtf8("The id 'baseProduct' is not unique."));
+ QVERIFY(items.at(1).toString().contains("id-uniqueness.qbs:6:5 First occurrence is here."));
+ QVERIFY(items.at(2).toString().contains("id-uniqueness.qbs:9:5 Next occurrence is here."));
+ }
+ QVERIFY(exceptionCaught);
+}
+
+void TestLanguage::importCollection()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("import-collection/project.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const ResolvedProductConstPtr product = products.value("da product");
+ QCOMPARE(product->productProperties.value("targetName").toString(),
+ QLatin1String("C1f1C1f2C2f1C2f2"));
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QVERIFY(!exceptionCaught);
+}
+
+void TestLanguage::invalidBindingInDisabledItem()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("invalidBindingInDisabledItem.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 2);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QVERIFY(!exceptionCaught);
+}
+
+class JSSourceValueCreator
+{
+ FileContextPtr m_fileContext;
+ QList<QString *> m_strings;
+public:
+ JSSourceValueCreator(const FileContextPtr &fileContext)
+ : m_fileContext(fileContext)
+ {
+ }
+
+ ~JSSourceValueCreator()
+ {
+ qDeleteAll(m_strings);
+ }
+
+ JSSourceValuePtr create(const QString &sourceCode)
+ {
+ JSSourceValuePtr value = JSSourceValue::create();
+ value->setFile(m_fileContext);
+ QString *str = new QString(sourceCode);
+ m_strings += str;
+ value->setSourceCode(QStringRef(str));
+ return value;
+ }
+};
+
+void TestLanguage::itemPrototype()
+{
+ FileContextPtr fileContext = FileContext::create();
+ fileContext->setFilePath("/dev/null");
+ JSSourceValueCreator sourceValueCreator(fileContext);
+ ItemPool pool;
+ Item *proto = Item::create(&pool, ItemType::Product);
+ proto->setProperty("x", sourceValueCreator.create("1"));
+ proto->setProperty("y", sourceValueCreator.create("1"));
+ Item *item = Item::create(&pool, ItemType::Product);
+ item->setPrototype(proto);
+ item->setProperty("y", sourceValueCreator.create("x + 1"));
+ item->setProperty("z", sourceValueCreator.create("2"));
+
+ Evaluator evaluator(m_engine);
+ QCOMPARE(evaluator.property(proto, "x").toVariant().toInt(), 1);
+ QCOMPARE(evaluator.property(proto, "y").toVariant().toInt(), 1);
+ QVERIFY(!evaluator.property(proto, "z").isValid());
+ QCOMPARE(evaluator.property(item, "x").toVariant().toInt(), 1);
+ QCOMPARE(evaluator.property(item, "y").toVariant().toInt(), 2);
+ QCOMPARE(evaluator.property(item, "z").toVariant().toInt(), 2);
+}
+
+void TestLanguage::itemScope()
+{
+ FileContextPtr fileContext = FileContext::create();
+ fileContext->setFilePath("/dev/null");
+ JSSourceValueCreator sourceValueCreator(fileContext);
+ ItemPool pool;
+ Item *scope1 = Item::create(&pool, ItemType::Scope);
+ scope1->setProperty("x", sourceValueCreator.create("1"));
+ Item *scope2 = Item::create(&pool, ItemType::Scope);
+ scope2->setScope(scope1);
+ scope2->setProperty("y", sourceValueCreator.create("x + 1"));
+ Item *item = Item::create(&pool, ItemType::Scope);
+ item->setScope(scope2);
+ item->setProperty("z", sourceValueCreator.create("x + y"));
+
+ Evaluator evaluator(m_engine);
+ QCOMPARE(evaluator.property(scope1, "x").toVariant().toInt(), 1);
+ QCOMPARE(evaluator.property(scope2, "y").toVariant().toInt(), 2);
+ QVERIFY(!evaluator.property(scope2, "x").isValid());
+ QCOMPARE(evaluator.property(item, "z").toVariant().toInt(), 3);
+}
+
+void TestLanguage::jsExtensions()
+{
+ QFile file(testProject("jsextensions.js"));
+ QVERIFY(file.open(QFile::ReadOnly));
+ QTextStream ts(&file);
+ QString code = ts.readAll();
+ QVERIFY(!code.isEmpty());
+ QScriptValue evaluated = m_engine->evaluate(code, file.fileName(), 1);
+ if (m_engine->hasErrorOrException(evaluated)) {
+ qDebug() << m_engine->uncaughtExceptionBacktrace();
+ QFAIL(qPrintable(m_engine->lastErrorString(evaluated)));
+ }
+}
+
+void TestLanguage::jsImportUsedInMultipleScopes_data()
+{
+ QTest::addColumn<QString>("buildVariant");
+ QTest::addColumn<QString>("expectedProductName");
+ QTest::newRow("debug") << QString("debug") << QString("MyProduct_debug");
+ QTest::newRow("release") << QString("release") << QString("MyProduct");
+}
+
+void TestLanguage::jsImportUsedInMultipleScopes()
+{
+ QFETCH(QString, buildVariant);
+ QFETCH(QString, expectedProductName);
+
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("jsimportsinmultiplescopes.qbs"));
+ params.setOverriddenValues({std::make_pair(QLatin1String("qbs.buildVariant"),
+ buildVariant)});
+ params.expandBuildConfiguration();
+ TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ ResolvedProductPtr product = products.values().first();
+ QVERIFY(!!product);
+ QCOMPARE(product->name, expectedProductName);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QVERIFY(!exceptionCaught);
+}
+
+void TestLanguage::moduleProperties_data()
+{
+ QTest::addColumn<QString>("propertyName");
+ QTest::addColumn<QVariant>("expectedValue");
+ QTest::newRow("init") << QString() << QVariant();
+ QTest::newRow("merge_lists")
+ << "defines"
+ << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK");
+ QTest::newRow("merge_lists_and_values")
+ << "defines"
+ << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK");
+ QTest::newRow("merge_lists_with_duplicates")
+ << "cxxFlags"
+ << QVariant(QStringList() << "-foo" << "BAR" << "-foo" << "BAZ");
+ QTest::newRow("merge_lists_with_prototype_values")
+ << "rpaths"
+ << QVariant(QStringList() << "/opt/qt/lib" << "$ORIGIN");
+ QTest::newRow("list_property_that_references_product")
+ << "listProp"
+ << QVariant(QStringList() << "x" << "123");
+ QTest::newRow("list_property_depending_on_overridden_property")
+ << "listProp2"
+ << QVariant(QStringList() << "PRODUCT_STUFF" << "DEFAULT_STUFF" << "EXTRA_STUFF");
+ QTest::newRow("overridden_list_property")
+ << "listProp"
+ << QVariant(QStringList() << "PRODUCT_STUFF");
+ QTest::newRow("shadowed-list-property")
+ << "defines"
+ << QVariant(QStringList() << "MyProject" << "shadowed-list-property");
+ QTest::newRow("shadowed-scalar-property")
+ << "someString"
+ << QVariant(QString("MyProject_shadowed-scalar-property"));
+ QTest::newRow("cleanup") << QString() << QVariant();
+}
+
+void TestLanguage::moduleProperties()
+{
+ HANDLE_INIT_CLEANUP_DATATAGS("moduleproperties.qbs");
+ QFETCH(QString, propertyName);
+ QFETCH(QVariant, expectedValue);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
+ ResolvedProductPtr product = products.value(productName);
+ QVERIFY(!!product);
+ const QVariant value = product->moduleProperties->moduleProperty("dummy", propertyName);
+ QCOMPARE(value, expectedValue);
+}
+
+void TestLanguage::modulePropertiesInGroups()
+{
+ defaultParameters.setProjectFilePath(testProject("modulepropertiesingroups.qbs"));
+ bool exceptionCaught = false;
+ try {
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const ResolvedProductPtr product = products.value("grouptest");
+ QVERIFY(!!product);
+ GroupConstPtr g1;
+ GroupConstPtr g11;
+ GroupConstPtr g12;
+ GroupConstPtr g2;
+ GroupConstPtr g21;
+ GroupConstPtr g211;
+ foreach (const GroupConstPtr &g, product->groups) {
+ if (g->name == "g1")
+ g1= g;
+ else if (g->name == "g2")
+ g2 = g;
+ else if (g->name == "g1.1")
+ g11 = g;
+ else if (g->name == "g1.2")
+ g12 = g;
+ else if (g->name == "g2.1")
+ g21 = g;
+ else if (g->name == "g2.1.1")
+ g211 = g;
+ }
+ QVERIFY(!!g1);
+ QVERIFY(!!g2);
+ QVERIFY(!!g11);
+ QVERIFY(!!g12);
+ QVERIFY(!!g21);
+ QVERIFY(!!g211);
+
+ const QVariantMap productProps = product->moduleProperties->value();
+ const auto &productGmod1List1 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(productGmod1List1, QStringList() << "gmod1_list1_proto" << "gmod1_string_proto");
+ const auto &productGmod1List2 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(productGmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
+ << "gmod1_list2_proto");
+ const auto &productGmod1List3 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list3")
+ .toStringList();
+ QCOMPARE(productGmod1List3, QStringList() << "product" << "gmod1_string_proto");
+ const int productP0 = moduleProperty(productProps, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(productP0, 1);
+ const int productDepProp = moduleProperty(productProps, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(productDepProp, 0);
+ const auto &productGmod2String = moduleProperty(productProps, "gmod2", "gmod2_string")
+ .toString();
+ QCOMPARE(productGmod2String, QString("gmod1_string_proto"));
+ const auto &productGmod2List = moduleProperty(productProps, "gmod2", "gmod2_list")
+ .toStringList();
+ QCOMPARE(productGmod2List, QStringList() << "gmod1_string_proto" << "commonName_in_gmod1"
+ << "gmod4_string_proto_gmod3_string_proto" << "gmod3_string_proto"
+ << "gmod2_list_proto");
+
+ const QVariantMap g1Props = g1->properties->value();
+ const auto &g1Gmod1List1 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g1Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1");
+ const auto &g1Gmod1List2 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(g1Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
+ << "gmod1_list2_proto" << "g1");
+ const auto &g1Gmod1List3 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list3")
+ .toStringList();
+ QCOMPARE(g1Gmod1List3, QStringList() << "product" << "g1");
+ const int g1P0 = moduleProperty(g1Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g1P0, 3);
+ const int g1DepProp = moduleProperty(g1Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g1DepProp, 1);
+ const auto &g1Gmod2String = moduleProperty(g1Props, "gmod2", "gmod2_string").toString();
+ QCOMPARE(g1Gmod2String, QString("g1"));
+ const auto &g1Gmod2List = moduleProperty(g1Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QCOMPARE(g1Gmod2List, QStringList() << "g1" << "commonName_in_gmod1" << "g1_gmod4_g1_gmod3"
+ << "g1_gmod3" << "gmod2_list_proto");
+
+ const QVariantMap g11Props = g11->properties->value();
+ const auto &g11Gmod1List1 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g11Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1.1");
+ const auto &g11Gmod1List2 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(g11Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
+ << "gmod1_list2_proto" << "g1" << "g1.1");
+ const auto &g11Gmod1List3 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list3")
+ .toStringList();
+ QCOMPARE(g11Gmod1List3, QStringList() << "product" << "g1.1");
+ const int g11P0 = moduleProperty(g11Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g11P0, 5);
+ const int g11DepProp = moduleProperty(g11Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g11DepProp, 2);
+ const auto &g11Gmod2String = moduleProperty(g11Props, "gmod2", "gmod2_string").toString();
+ QCOMPARE(g11Gmod2String, QString("g1.1"));
+ const auto &g11Gmod2List = moduleProperty(g11Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QCOMPARE(g11Gmod2List, QStringList() << "g1.1" << "commonName_in_gmod1"
+ << "g1.1_gmod4_g1.1_gmod3" << "g1.1_gmod3" << "gmod2_list_proto");
+
+ const QVariantMap g12Props = g12->properties->value();
+ const auto &g12Gmod1List1 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g12Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1.2");
+ const auto &g12Gmod1List2 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(g12Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
+ << "gmod1_list2_proto" << "g1" << "g1.2");
+ const auto &g12Gmod1List3 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list3")
+ .toStringList();
+ QCOMPARE(g12Gmod1List3, QStringList() << "product" << "g1.2");
+ const int g12P0 = moduleProperty(g12Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g12P0, 9);
+ const int g12DepProp = moduleProperty(g12Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g12DepProp, 1);
+ const auto &g12Gmod2String = moduleProperty(g12Props, "gmod2", "gmod2_string").toString();
+ QCOMPARE(g12Gmod2String, QString("g1.2"));
+ const auto &g12Gmod2List = moduleProperty(g12Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QCOMPARE(g12Gmod2List, QStringList() << "g1.2" << "commonName_in_gmod1"
+ << "g1_gmod4_g1.2_gmod3" << "g1.2_gmod3" << "gmod2_list_proto");
+
+ const QVariantMap g2Props = g2->properties->value();
+ const auto &g2Gmod1List1 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g2Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
+ const auto &g2Gmod1List2 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(g2Gmod1List2, QStringList() << "grouptest" << "g2" << "gmod1_list2_proto");
+ const int g2P0 = moduleProperty(g2Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g2P0, 6);
+ const int g2DepProp = moduleProperty(g2Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g2DepProp, 2);
+ const auto &g2Gmod2String = moduleProperty(g2Props, "gmod2", "gmod2_string").toString();
+ QCOMPARE(g2Gmod2String, QString("g2"));
+ const auto &g2Gmod2List = moduleProperty(g2Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QCOMPARE(g2Gmod2List, QStringList() << "g2" << "commonName_in_gmod1" << "g2_gmod4_g2_gmod3"
+ << "g2_gmod3" << "gmod2_list_proto");
+
+ const QVariantMap g21Props = g21->properties->value();
+ const auto &g21Gmod1List1 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g21Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
+ const auto &g21Gmod1List2 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QEXPECT_FAIL(0, "no re-eval when no module props set", Continue);
+ QCOMPARE(g21Gmod1List2, QStringList() << "grouptest" << "g2.1" << "gmod1_list2_proto");
+ const int g21P0 = moduleProperty(g21Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g21P0, 6);
+ const int g21DepProp = moduleProperty(g21Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g21DepProp, 2);
+ const auto &g21Gmod2String = moduleProperty(g21Props, "gmod2", "gmod2_string").toString();
+ QCOMPARE(g21Gmod2String, QString("g2"));
+ const auto &g21Gmod2List = moduleProperty(g21Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QEXPECT_FAIL(0, "no re-eval when no module props set", Continue);
+ QCOMPARE(g21Gmod2List, QStringList() << "g2" << "commonName_in_gmod1"
+ << "g2.1_gmod4_g2.1_gmod3" << "g2.1_gmod3" << "gmod2_list_proto");
+
+ const QVariantMap g211Props = g211->properties->value();
+ const auto &g211Gmod1List1 = moduleProperty(g211Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g211Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
+ const auto &g211Gmod1List2 = moduleProperty(g211Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(g211Gmod1List2, QStringList() << "g2.1.1");
+ const int g211P0 = moduleProperty(g211Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g211P0, 17);
+ const int g211DepProp = moduleProperty(g211Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g211DepProp, 2);
+ const auto &g211Gmod2String
+ = moduleProperty(g211Props, "gmod2", "gmod2_string").toString();
+ QEXPECT_FAIL(0, "re-eval not triggered", Continue);
+ QCOMPARE(g211Gmod2String, QString("g2.1.1"));
+ const auto &g211Gmod2List = moduleProperty(g211Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QEXPECT_FAIL(0, "re-eval not triggered", Continue);
+ QCOMPARE(g211Gmod2List, QStringList() << "g2.1.1" << "commonName_in_gmod1"
+ << "g2.1.1_gmod4_g2.1.1_gmod3" << "g2.1.1_gmod3" << "gmod2_list_proto");
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::modulePropertyOverridesPerProduct()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setOverriddenValues({
+ std::make_pair("modules.dummy.someString", "m"),
+ std::make_pair("products.b.dummy.someString", "b"),
+ std::make_pair("products.c.dummy.someString", "c")
+ });
+ params.setProjectFilePath(
+ testProject("module-property-overrides-per-product.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 3);
+ const ResolvedProductConstPtr a = products.value("a");
+ QVERIFY(!!a);
+ const ResolvedProductConstPtr b = products.value("b");
+ QVERIFY(!!b);
+ const ResolvedProductConstPtr c = products.value("c");
+ QVERIFY(!!c);
+
+ const auto propertyValue = [](const ResolvedProductConstPtr &p) -> QString
+ {
+ return p->moduleProperties->moduleProperty("dummy", "someString").toString();
+ };
+
+ QCOMPARE(propertyValue(a), QString("m"));
+ QCOMPARE(propertyValue(b), QString("b"));
+ QCOMPARE(propertyValue(c), QString("c"));
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::moduleScope()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("modulescope.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(!!product);
+
+ auto intModuleValue = [product] (const QString &name) -> int
+ {
+ return product->moduleProperties->moduleProperty("scopemod", name).toInt();
+ };
+
+ QCOMPARE(intModuleValue("a"), 2); // overridden in module instance
+ QCOMPARE(intModuleValue("b"), 1); // genuine
+ QCOMPARE(intModuleValue("c"), 3); // genuine, dependent on overridden value
+ QCOMPARE(intModuleValue("d"), 2); // genuine, dependent on genuine value
+ QCOMPARE(intModuleValue("e"), 1); // genuine
+ QCOMPARE(intModuleValue("f"), 2); // overridden
+ QCOMPARE(intModuleValue("g"), 156); // overridden, dependent on product properties
+ QCOMPARE(intModuleValue("h"), 158); // overridden, base dependent on product properties
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+
+}
+
+void TestLanguage::modules_data()
+{
+ QTest::addColumn<QStringList>("expectedModulesInProduct");
+ QTest::addColumn<QString>("expectedProductProperty");
+ QTest::newRow("init") << QStringList();
+ QTest::newRow("no_modules")
+ << (QStringList() << "qbs")
+ << QString();
+ QTest::newRow("qt_core")
+ << (QStringList() << "qbs" << "dummy" << "dummyqt.core")
+ << QString("1.2.3");
+ QTest::newRow("qt_gui")
+ << (QStringList() << "qbs" << "dummy" << "dummyqt.core" << "dummyqt.gui")
+ << QString("guiProperty");
+ QTest::newRow("qt_gui_network")
+ << (QStringList() << "qbs" << "dummy" << "dummyqt.core" << "dummyqt.gui"
+ << "dummyqt.network")
+ << QString("guiProperty,networkProperty");
+ QTest::newRow("deep_module_name")
+ << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
+ << QString("abysmal");
+ QTest::newRow("deep_module_name_submodule_syntax1")
+ << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
+ << QString("abysmal");
+ QTest::newRow("deep_module_name_submodule_syntax2")
+ << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
+ << QString("abysmal");
+ QTest::newRow("dummy_twice")
+ << (QStringList() << "qbs" << "dummy")
+ << QString();
+ QTest::newRow("cleanup") << QStringList();
+}
+
+void TestLanguage::modules()
+{
+ HANDLE_INIT_CLEANUP_DATATAGS("modules.qbs");
+ QFETCH(QStringList, expectedModulesInProduct);
+ QFETCH(QString, expectedProductProperty);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
+ ResolvedProductPtr product = products.value(productName);
+ QVERIFY(!!product);
+ QCOMPARE(product->name, productName);
+ QStringList modulesInProduct;
+ foreach (ResolvedModuleConstPtr m, product->modules)
+ modulesInProduct += m->name;
+ modulesInProduct.sort();
+ expectedModulesInProduct.sort();
+ QCOMPARE(modulesInProduct, expectedModulesInProduct);
+ QCOMPARE(product->productProperties.value("foo").toString(), expectedProductProperty);
+}
+
+void TestLanguage::nonRequiredProducts()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("non-required-products.qbs"));
+ QFETCH(bool, subProjectEnabled);
+ QFETCH(bool, dependeeEnabled);
+ QVariantMap overriddenValues;
+ if (!subProjectEnabled)
+ overriddenValues.insert("projects.subproject.condition", false);
+ else if (!dependeeEnabled)
+ overriddenValues.insert("products.dependee.condition", false);
+ params.setOverriddenValues(overriddenValues);
+ const TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ const auto products = productsFromProject(project);
+ QCOMPARE(products.count(), 4 + !!subProjectEnabled);
+ const ResolvedProductConstPtr dependee = products.value("dependee");
+ QCOMPARE(subProjectEnabled, !!dependee);
+ if (dependee)
+ QCOMPARE(dependeeEnabled, dependee->enabled);
+ const ResolvedProductConstPtr depender = products.value("depender");
+ QVERIFY(!!depender);
+ const QStringList defines = depender->moduleProperties->moduleProperty("dummy", "defines")
+ .toStringList();
+ QCOMPARE(subProjectEnabled && dependeeEnabled, defines.contains("WITH_DEPENDEE"));
+
+ for (const auto &name : std::vector<const char *>({ "p3", "p2", "p1"})) {
+ const ResolvedProductConstPtr &product = products.value(name);
+ QVERIFY2(product, name);
+ QVERIFY2(!product->enabled, name);
+ }
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::nonRequiredProducts_data()
+{
+ QTest::addColumn<bool>("subProjectEnabled");
+ QTest::addColumn<bool>("dependeeEnabled");
+ QTest::newRow("dependee enabled") << true << true;
+ QTest::newRow("dependee disabled") << true << false;
+ QTest::newRow("sub project disabled") << false << true;
+}
+
+void TestLanguage::outerInGroup()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("outerInGroup.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ ResolvedProductPtr product = products.value("OuterInGroup");
+ QVERIFY(!!product);
+ QCOMPARE(product->groups.count(), 2);
+ GroupPtr group = product->groups.at(0);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, product->name);
+ QCOMPARE(group->files.count(), 1);
+ SourceArtifactConstPtr artifact = group->files.first();
+ QVariant installDir = artifact->properties->qbsPropertyValue("installDir");
+ QCOMPARE(installDir.toString(), QString("/somewhere"));
+ group = product->groups.at(1);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("Special Group"));
+ QCOMPARE(group->files.count(), 1);
+ artifact = group->files.first();
+ installDir = artifact->properties->qbsPropertyValue("installDir");
+ QCOMPARE(installDir.toString(), QString("/somewhere/else"));
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::parameterTypes()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("parameter-types.qbs"));
+ loader->loadProject(defaultParameters);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::pathProperties()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("pathproperties.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(!!product);
+ QString projectFileDir = QFileInfo(defaultParameters.projectFilePath()).absolutePath();
+ const QVariantMap productProps = product->productProperties;
+ QCOMPARE(productProps.value("projectFileDir").toString(), projectFileDir);
+ QStringList filesInProjectFileDir = QStringList()
+ << FileInfo::resolvePath(projectFileDir, "aboutdialog.h")
+ << FileInfo::resolvePath(projectFileDir, "aboutdialog.cpp");
+ QCOMPARE(productProps.value("filesInProjectFileDir").toStringList(), filesInProjectFileDir);
+ QStringList includePaths = product->moduleProperties->property(
+ QStringList() << "modules" << "dummy" << "includePaths").toStringList();
+ QCOMPARE(includePaths, QStringList() << projectFileDir);
+ QCOMPARE(productProps.value("base_fileInProductDir").toString(),
+ FileInfo::resolvePath(projectFileDir, QLatin1String("foo")));
+ QCOMPARE(productProps.value("base_fileInBaseProductDir").toString(),
+ FileInfo::resolvePath(projectFileDir, QLatin1String("subdir/bar")));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::profileValuesAndOverriddenValues()
+{
+ bool exceptionCaught = false;
+ try {
+ TemporaryProfile tp(QLatin1String("tst_lang_profile"), m_settings);
+ Profile profile = tp.p;
+ profile.setValue("dummy.defines", "IN_PROFILE");
+ profile.setValue("dummy.cFlags", "IN_PROFILE");
+ profile.setValue("dummy.cxxFlags", "IN_PROFILE");
+ profile.setValue("qbs.architecture", "x86");
+ SetupProjectParameters parameters = defaultParameters;
+ parameters.setTopLevelProfile(profile.name());
+ QVariantMap overriddenValues;
+ overriddenValues.insert("modules.dummy.cFlags", "OVERRIDDEN");
+ parameters.setOverriddenValues(overriddenValues);
+ parameters.setProjectFilePath(testProject("profilevaluesandoverriddenvalues.qbs"));
+ parameters.expandBuildConfiguration();
+ project = loader->loadProject(parameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(!!product);
+ QVariantList values;
+ values = product->moduleProperties->moduleProperty("dummy", "cxxFlags").toList();
+ QCOMPARE(values.length(), 1);
+ QCOMPARE(values.first().toString(), QString("IN_PROFILE"));
+ values = product->moduleProperties->moduleProperty("dummy", "defines").toList();
+ QCOMPARE(values, QVariantList() << QLatin1String("IN_FILE") << QLatin1String("IN_PROFILE"));
+ values = product->moduleProperties->moduleProperty("dummy", "cFlags").toList();
+ QCOMPARE(values.length(), 1);
+ QCOMPARE(values.first().toString(), QString("OVERRIDDEN"));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::productConditions()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("productconditions.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 6);
+ ResolvedProductPtr product;
+ product = products.value("product_no_condition");
+ QVERIFY(!!product);
+ QVERIFY(product->enabled);
+
+ product = products.value("product_true_condition");
+ QVERIFY(!!product);
+ QVERIFY(product->enabled);
+
+ product = products.value("product_condition_dependent_of_module");
+ QVERIFY(!!product);
+ QVERIFY(product->enabled);
+
+ product = products.value("product_false_condition");
+ QVERIFY(!!product);
+ QVERIFY(!product->enabled);
+
+ product = products.value("product_probe_condition_false");
+ QVERIFY(!!product);
+ QVERIFY(!product->enabled);
+
+ product = products.value("product_probe_condition_true");
+ QVERIFY(!!product);
+ QVERIFY(product->enabled);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::productDirectories()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("productdirectories.qbs"));
+ ResolvedProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ ResolvedProductPtr product;
+ product = products.value("MyApp");
+ QVERIFY(!!product);
+ const QVariantMap config = product->productProperties;
+ QCOMPARE(config.value(QLatin1String("buildDirectory")).toString(),
+ product->buildDirectory());
+ QCOMPARE(config.value(QLatin1String("sourceDirectory")).toString(), testDataDir());
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::propertiesBlocks_data()
+{
+ QTest::addColumn<QString>("propertyName");
+ QTest::addColumn<QStringList>("expectedValues");
+ QTest::addColumn<QString>("expectedStringValue");
+
+ QTest::newRow("init") << QString() << QStringList() << QString();
+ QTest::newRow("property_overwrite")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString();
+ QTest::newRow("property_set_indirect")
+ << QString("dummy.cFlags")
+ << QStringList("VAL")
+ << QString();
+ QTest::newRow("property_overwrite_no_outer")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString();
+ QTest::newRow("property_append_to_outer")
+ << QString("dummy.defines")
+ << (QStringList() << QString("ONE") << QString("TWO"))
+ << QString();
+
+ QTest::newRow("multiple_exclusive_properties")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString();
+ QTest::newRow("multiple_exclusive_properties_no_outer")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString();
+ QTest::newRow("multiple_exclusive_properties_append_to_outer")
+ << QString("dummy.defines")
+ << (QStringList() << QString("ONE") << QString("TWO"))
+ << QString();
+
+ QTest::newRow("condition_refers_to_product_property")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString("OVERWRITTEN");
+ QTest::newRow("condition_refers_to_project_property")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString("OVERWRITTEN");
+
+ QTest::newRow("ambiguous_properties")
+ << QString("dummy.defines")
+ << (QStringList() << QString("ONE") << QString("TWO"))
+ << QString();
+ QTest::newRow("inheritance_overwrite_in_subitem")
+ << QString("dummy.defines")
+ << (QStringList() << QString("OVERWRITTEN_IN_SUBITEM"))
+ << QString();
+ QTest::newRow("inheritance_retain_base1")
+ << QString("dummy.defines")
+ << (QStringList() << QString("BASE") << QString("SUB"))
+ << QString();
+ QTest::newRow("inheritance_retain_base2")
+ << QString("dummy.defines")
+ << (QStringList() << QString("BASE") << QString("SUB"))
+ << QString();
+ QTest::newRow("inheritance_retain_base3")
+ << QString("dummy.defines")
+ << (QStringList() << QString("BASE") << QString("SUB"))
+ << QString();
+ QTest::newRow("inheritance_retain_base4")
+ << QString("dummy.defines")
+ << (QStringList() << QString("BASE"))
+ << QString();
+ QTest::newRow("inheritance_condition_in_subitem1")
+ << QString("dummy.defines")
+ << (QStringList() << QString("SOMETHING") << QString("SUB"))
+ << QString();
+ QTest::newRow("inheritance_condition_in_subitem2")
+ << QString("dummy.defines")
+ << (QStringList() << QString("SOMETHING"))
+ << QString();
+ QTest::newRow("condition_references_id")
+ << QString("dummy.defines")
+ << (QStringList() << QString("OVERWRITTEN"))
+ << QString();
+ QTest::newRow("using_derived_Properties_item") << "dummy.defines"
+ << (QStringList() << "string from MyProperties") << QString();
+ QTest::newRow("conditional-depends")
+ << QString("dummy.defines")
+ << QStringList()
+ << QString();
+ QTest::newRow("cleanup") << QString() << QStringList() << QString();
+}
+
+void TestLanguage::propertiesBlocks()
+{
+ HANDLE_INIT_CLEANUP_DATATAGS("propertiesblocks.qbs");
+ QFETCH(QString, propertyName);
+ QFETCH(QStringList, expectedValues);
+ QFETCH(QString, expectedStringValue);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
+ ResolvedProductPtr product = products.value(productName);
+ QVERIFY(!!product);
+ QCOMPARE(product->name, productName);
+ QVariant v = productPropertyValue(product, propertyName);
+ QCOMPARE(v.toStringList(), expectedValues);
+ if (!expectedStringValue.isEmpty()) {
+ v = productPropertyValue(product, "someString");
+ QCOMPARE(v.toString(), expectedStringValue);
+ }
+}
+
+void TestLanguage::propertiesBlockInGroup()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("properties-block-in-group.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QCOMPARE(project->allProducts().count(), 1);
+ const ResolvedProductConstPtr product = project->allProducts().first();
+ const auto groupIt = std::find_if(product->groups.constBegin(), product->groups.constEnd(),
+ [](const GroupConstPtr &g) { return g->name == "the group"; });
+ QVERIFY(groupIt != product->groups.constEnd());
+ const QVariantMap propertyMap = (*groupIt)->properties->value();
+ const QVariantList value = moduleProperty(propertyMap, "dummy", "defines").toList();
+ QStringList stringListValue;
+ std::transform(value.constBegin(), value.constEnd(), std::back_inserter(stringListValue),
+ [](const QVariant &v) { return v.toString(); });
+ QCOMPARE(stringListValue, QStringList() << "BASEDEF" << "FEATURE_ENABLED");
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::propertiesItemInModule()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(
+ testProject("properties-item-in-module.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 2);
+ for (const ResolvedProductConstPtr &p : products) {
+ QCOMPARE(p->moduleProperties->moduleProperty("dummy", "productName").toString(),
+ p->name);
+ }
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::qbsPropertiesInProjectCondition()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(
+ testProject("qbs-properties-in-project-condition.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 0);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::relaxedErrorMode()
+{
+ m_logSink->setLogLevel(LoggerMinLevel);
+ QFETCH(bool, strictMode);
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("relaxed-error-mode/relaxed-error-mode.qbs"));
+ params.setProductErrorMode(strictMode ? ErrorHandlingMode::Strict
+ : ErrorHandlingMode::Relaxed);
+ const TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!strictMode);
+ const auto productMap = productsFromProject(project);
+ const ResolvedProductConstPtr brokenProduct = productMap.value("broken");
+ QVERIFY(!brokenProduct->enabled);
+ QVERIFY(brokenProduct->location.isValid());
+ QCOMPARE(brokenProduct->allFiles().count(), 0);
+ const ResolvedProductConstPtr dependerRequired = productMap.value("depender required");
+ QVERIFY(!dependerRequired->enabled);
+ QVERIFY(dependerRequired->location.isValid());
+ QCOMPARE(dependerRequired->allFiles().count(), 1);
+ const ResolvedProductConstPtr dependerNonRequired
+ = productMap.value("depender nonrequired");
+ QVERIFY(dependerNonRequired->enabled);
+ QCOMPARE(dependerNonRequired->allFiles().count(), 1);
+ const ResolvedProductConstPtr recursiveDepender = productMap.value("recursive depender");
+ QVERIFY(!recursiveDepender->enabled);
+ QVERIFY(recursiveDepender->location.isValid());
+ QCOMPARE(recursiveDepender->allFiles().count(), 1);
+ const ResolvedProductConstPtr missingFile = productMap.value("missing file");
+ QVERIFY(missingFile->enabled);
+ QCOMPARE(missingFile->groups.count(), 1);
+ QVERIFY(missingFile->groups.first()->enabled);
+ QCOMPARE(missingFile->groups.first()->allFiles().count(), 2);
+ const ResolvedProductConstPtr fine = productMap.value("fine");
+ QVERIFY(fine->enabled);
+ QCOMPARE(fine->allFiles().count(), 1);
+ } catch (const ErrorInfo &e) {
+ QVERIFY2(strictMode, qPrintable(e.toString()));
+ }
+}
+
+void TestLanguage::relaxedErrorMode_data()
+{
+ QTest::addColumn<bool>("strictMode");
+
+ QTest::newRow("strict mode") << true;
+ QTest::newRow("relaxed mode") << false;
+}
+
+void TestLanguage::requiredAndNonRequiredDependencies()
+{
+ QFETCH(QString, projectFile);
+ QFETCH(bool, exceptionExpected);
+ try {
+ SetupProjectParameters params = defaultParameters;
+ const QString projectFilePath = "required-and-nonrequired-dependencies/" + projectFile;
+ params.setProjectFilePath(testProject(projectFilePath.toLocal8Bit()));
+ const TopLevelProjectConstPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QVERIFY(!exceptionExpected);
+ } catch (const ErrorInfo &e) {
+ QVERIFY(exceptionExpected);
+ QVERIFY2(e.toString().contains("validation error!"), qPrintable(e.toString()));
+ }
+}
+
+void TestLanguage::requiredAndNonRequiredDependencies_data()
+{
+ QTest::addColumn<QString>("projectFile");
+ QTest::addColumn<bool>("exceptionExpected");
+
+ QTest::newRow("same file") << "direct-dependencies.qbs" << true;
+ QTest::newRow("dependency via module") << "dependency-via-module.qbs" << true;
+ QTest::newRow("dependency via export") << "dependency-via-export.qbs" << true;
+ QTest::newRow("more indirection") << "complicated.qbs" << true;
+ QTest::newRow("required chain (module)") << "required-chain-module.qbs" << false;
+ QTest::newRow("required chain (export)") << "required-chain-export.qbs" << false;
+ QTest::newRow("required chain (export indirect)") << "required-chain-export-indirect.qbs"
+ << false;
+}
+
+void TestLanguage::throwingProbe()
+{
+ QFETCH(bool, enableProbe);
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("throwing-probe.qbs"));
+ QVariantMap properties;
+ properties.insert(QLatin1String("products.theProduct.enableProbe"), enableProbe);
+ params.setOverriddenValues(properties);
+ const TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QVERIFY(!enableProbe);
+ } catch (const ErrorInfo &e) {
+ QVERIFY2(enableProbe, qPrintable(e.toString()));
+ }
+}
+
+void TestLanguage::throwingProbe_data()
+{
+ QTest::addColumn<bool>("enableProbe");
+
+ QTest::newRow("enabled probe") << true;
+ QTest::newRow("disabled probe") << false;
+}
+
+void TestLanguage::qualifiedId()
+{
+ QString str = "foo.bar.baz";
+ QualifiedId id = QualifiedId::fromString(str);
+ QCOMPARE(id.count(), 3);
+ QCOMPARE(id.toString(), str);
+
+ id = QualifiedId("blubb.di.blubb"); // c'tor does not split
+ QCOMPARE(id.count(), 1);
+
+ QList<QualifiedId> ids;
+ ids << QualifiedId::fromString("a")
+ << QualifiedId::fromString("a.a")
+ << QualifiedId::fromString("b")
+ << QualifiedId::fromString("c.a")
+ << QualifiedId::fromString("c.b.a")
+ << QualifiedId::fromString("c.c");
+ QList<QualifiedId> sorted = ids;
+ std::sort(sorted.begin(), sorted.end());
+ QCOMPARE(ids, sorted);
+}
+
+void TestLanguage::recursiveProductDependencies()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(
+ testProject("recursive-dependencies/recursive-dependencies.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 4);
+ const ResolvedProductConstPtr p1 = products.value("p1");
+ QVERIFY(!!p1);
+ const ResolvedProductConstPtr p2 = products.value("p2");
+ QVERIFY(!!p2);
+ const ResolvedProductPtr p3 = products.value("p3");
+ QVERIFY(!!p3);
+ const ResolvedProductPtr p4 = products.value("p4");
+ QVERIFY(!!p4);
+ QVERIFY(p1->dependencies == Set<ResolvedProductPtr>() << p3 << p4);
+ QVERIFY(p2->dependencies == Set<ResolvedProductPtr>() << p3 << p4);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::fileTags_data()
+{
+ QTest::addColumn<int>("numberOfGroups");
+ QTest::addColumn<QStringList>("expectedFileTags");
+
+ QTest::newRow("init") << 0 << QStringList();
+ QTest::newRow("filetagger_project_scope") << 1 << (QStringList() << "cpp");
+ QTest::newRow("filetagger_product_scope") << 1 << (QStringList() << "asm");
+ QTest::newRow("filetagger_static_pattern") << 1 << (QStringList() << "yellow");
+ QTest::newRow("unknown_file_tag") << 1 << (QStringList() << "unknown-file-tag");
+ QTest::newRow("set_file_tag_via_group") << 2 << (QStringList() << "c++");
+ QTest::newRow("override_file_tag_via_group") << 2 << (QStringList() << "c++");
+ QTest::newRow("add_file_tag_via_group") << 2 << (QStringList() << "cpp" << "zzz");
+ QTest::newRow("cleanup") << 0 << QStringList();
+}
+
+void TestLanguage::fileTags()
+{
+ HANDLE_INIT_CLEANUP_DATATAGS("filetags.qbs");
+ QFETCH(int, numberOfGroups);
+ QFETCH(QStringList, expectedFileTags);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product;
+ const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
+ QVERIFY(!!(product = products.value(productName)));
+ QCOMPARE(product->groups.count(), numberOfGroups);
+ GroupPtr group = product->groups.last();
+ QVERIFY(!!group);
+ QCOMPARE(group->files.count(), 1);
+ SourceArtifactConstPtr sourceFile = group->files.first();
+ QStringList fileTags = sourceFile->fileTags.toStringList();
+ fileTags.sort();
+ QCOMPARE(fileTags, expectedFileTags);
+}
+
+void TestLanguage::wildcards_data()
+{
+ QTest::addColumn<bool>("useGroup");
+ QTest::addColumn<QStringList>("filesToCreate");
+ QTest::addColumn<QString>("projectFileSubDir");
+ QTest::addColumn<QString>("prefix");
+ QTest::addColumn<QStringList>("patterns");
+ QTest::addColumn<QStringList>("excludePatterns");
+ QTest::addColumn<QStringList>("expected");
+
+ const bool useGroup = true;
+ for (int i = 0; i <= 1; ++i) {
+ const bool useGroup = i;
+ const QByteArray dataTagSuffix = useGroup ? " group" : " nogroup";
+ QTest::newRow(QByteArray("simple 1") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "*.h")
+ << QStringList()
+ << (QStringList() << "foo.h" << "bar.h");
+ QTest::newRow(QByteArray("simple 2") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "foo.*")
+ << QStringList()
+ << (QStringList() << "foo.h" << "foo.cpp");
+ QTest::newRow(QByteArray("simple 3") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "*.h" << "*.cpp")
+ << QStringList()
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp");
+ QTest::newRow(QByteArray("exclude 1") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "*.h" << "*.cpp")
+ << (QStringList() << "bar*")
+ << (QStringList() << "foo.h" << "foo.cpp");
+ QTest::newRow(QByteArray("exclude 2") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "*")
+ << (QStringList() << "*.qbs")
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp");
+ QTest::newRow(QByteArray("non-recursive") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "a/*")
+ << QStringList()
+ << (QStringList() << "a/foo.h" << "a/foo.cpp");
+ QTest::newRow(QByteArray("absolute paths") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << m_wildcardsTestDirPath + "/?oo.*")
+ << QStringList()
+ << (QStringList() << "foo.h" << "foo.cpp");
+ QTest::newRow(QByteArray("relative paths with dotdot") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "bar.h" << "bar.cpp")
+ << QString("TheLaughingLlama")
+ << QString()
+ << (QStringList() << "../bar.*")
+ << QStringList()
+ << (QStringList() << "bar.h" << "bar.cpp");
+ }
+ QTest::newRow(QByteArray("recursive 1"))
+ << useGroup
+ << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "a/**")
+ << QStringList()
+ << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp");
+ QTest::newRow(QByteArray("recursive 2"))
+ << useGroup
+ << (QStringList()
+ << "d/1.h" << "b/d/1.h" << "b/c/d/1.h"
+ << "d/e/1.h" << "b/d/e/1.h" << "b/c/d/e/1.h"
+ << "a/d/1.h" << "a/b/d/1.h" << "a/b/c/d/1.h"
+ << "a/d/e/1.h" << "a/b/d/e/1.h" << "a/b/c/d/e/1.h"
+ << "a/d/1.cpp" << "a/b/d/1.cpp" << "a/b/c/d/1.h"
+ << "a/d/e/1.cpp" << "a/b/d/e/1.cpp" << "a/b/c/d/e/1.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "a/**/d/*.h")
+ << QStringList()
+ << (QStringList() << "a/d/1.h" << "a/b/d/1.h" << "a/b/c/d/1.h");
+ QTest::newRow(QByteArray("recursive 3"))
+ << useGroup
+ << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "a/**/**/**")
+ << QStringList()
+ << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp");
+ QTest::newRow(QByteArray("prefix"))
+ << useGroup
+ << (QStringList() << "subdir/foo.h" << "subdir/foo.cpp" << "subdir/bar.h"
+ << "subdir/bar.cpp")
+ << QString()
+ << QString("subdir/")
+ << (QStringList() << "*.h")
+ << QStringList()
+ << (QStringList() << "subdir/foo.h" << "subdir/bar.h");
+ QTest::newRow(QByteArray("non-existing absolute path"))
+ << useGroup
+ << QStringList()
+ << QString()
+ << QString("/dir")
+ << (QStringList() << "*.whatever")
+ << QStringList()
+ << QStringList();
+}
+
+void TestLanguage::wildcards()
+{
+ QFETCH(bool, useGroup);
+ QFETCH(QStringList, filesToCreate);
+ QFETCH(QString, projectFileSubDir);
+ QFETCH(QString, prefix);
+ QFETCH(QStringList, patterns);
+ QFETCH(QStringList, excludePatterns);
+ QFETCH(QStringList, expected);
+
+ // create test directory
+ QDir::setCurrent(QDir::tempPath());
+ {
+ QString errorMessage;
+ if (QFile::exists(m_wildcardsTestDirPath)) {
+ if (!removeDirectoryWithContents(m_wildcardsTestDirPath, &errorMessage)) {
+ qDebug() << errorMessage;
+ QVERIFY2(false, "removeDirectoryWithContents failed");
+ }
+ }
+ QVERIFY(QDir().mkdir(m_wildcardsTestDirPath));
+ }
+
+ // create project file
+ const QString groupName = "Keks";
+ QString dataTag = QString::fromLocal8Bit(QTest::currentDataTag());
+ dataTag.replace(' ', '_');
+ if (!projectFileSubDir.isEmpty()) {
+ if (!projectFileSubDir.startsWith('/'))
+ projectFileSubDir.prepend('/');
+ if (projectFileSubDir.endsWith('/'))
+ projectFileSubDir.chop(1);
+ QVERIFY(QDir().mkpath(m_wildcardsTestDirPath + projectFileSubDir));
+ }
+ const QString projectFilePath = m_wildcardsTestDirPath + projectFileSubDir + "/test_" + dataTag
+ + ".qbs";
+ {
+ QFile projectFile(projectFilePath);
+ QVERIFY(projectFile.open(QIODevice::WriteOnly));
+ QTextStream s(&projectFile);
+ s << "import qbs.base 1.0" << endl << endl
+ << "Application {" << endl
+ << " name: \"MyProduct\"" << endl;
+ if (useGroup) {
+ s << " Group {" << endl
+ << " name: " << toJSLiteral(groupName) << endl;
+ }
+ if (!prefix.isEmpty())
+ s << " prefix: " << toJSLiteral(prefix) << endl;
+ if (!patterns.isEmpty())
+ s << " files: " << toJSLiteral(patterns) << endl;
+ if (!excludePatterns.isEmpty())
+ s << " excludeFiles: " << toJSLiteral(excludePatterns) << endl;
+ if (useGroup)
+ s << " }" << endl;
+ s << "}" << endl << endl;
+ }
+
+ // create files
+ foreach (QString filePath, filesToCreate) {
+ filePath.prepend(m_wildcardsTestDirPath + '/');
+ QFileInfo fi(filePath);
+ if (!QDir(fi.path()).exists())
+ QVERIFY(QDir().mkpath(fi.path()));
+ QFile file(filePath);
+ QVERIFY(file.open(QIODevice::WriteOnly));
+ }
+
+ // read the project
+ bool exceptionCaught = false;
+ ResolvedProductPtr product;
+ try {
+ defaultParameters.setProjectFilePath(projectFilePath);
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ product = products.value("MyProduct");
+ QVERIFY(!!product);
+ GroupPtr group;
+ if (useGroup) {
+ QCOMPARE(product->groups.count(), HostOsInfo::isMacosHost() ? 3 : 2);
+ foreach (const GroupPtr &rg, product->groups) {
+ if (rg->name == groupName) {
+ group = rg;
+ break;
+ }
+ }
+ } else {
+ QCOMPARE(product->groups.count(), HostOsInfo::isMacosHost() ? 2 : 1);
+ group = product->groups.first();
+ }
+ QVERIFY(!!group);
+ QCOMPARE(group->files.count(), 0);
+ SourceWildCards::Ptr wildcards = group->wildcards;
+ QVERIFY(!!wildcards);
+ QStringList actualFilePaths;
+ foreach (const SourceArtifactConstPtr &artifact, wildcards->files) {
+ QString str = artifact->absoluteFilePath;
+ int idx = str.indexOf(m_wildcardsTestDirPath);
+ if (idx != -1)
+ str.remove(0, idx + m_wildcardsTestDirPath.count() + 1);
+ actualFilePaths << str;
+ }
+ actualFilePaths.sort();
+ expected.sort();
+ QCOMPARE(actualFilePaths, expected);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
const SettingsPtr s = settings();
- qbs::Internal::TestLanguage tl(ConsoleLogger::instance().logSink(), s.get());
+ TestLanguage tl(ConsoleLogger::instance().logSink(), s.get());
return QTest::qExec(&tl, argc, argv);
}
diff --git a/src/lib/corelib/language/tst_language.h b/tests/auto/language/tst_language.h
index e77c1f360..9d63414a5 100644
--- a/src/lib/corelib/language/tst_language.h
+++ b/tests/auto/language/tst_language.h
@@ -44,32 +44,31 @@
#include <language/loader.h>
#include <logging/ilogsink.h>
#include <tools/setupprojectparameters.h>
-#include <tools/qbs_export.h>
-#include <QtTest/qtest.h>
-namespace qbs {
-namespace Internal {
+#include <QtTest/qtest.h>
-class QBS_EXPORT TestLanguage : public QObject
+class TestLanguage : public QObject
{
Q_OBJECT
public:
- TestLanguage(ILogSink *logSink, Settings *settings);
+ TestLanguage(qbs::ILogSink *logSink, qbs::Settings *settings);
~TestLanguage();
private:
- ILogSink *m_logSink;
- Settings * const m_settings;
- Logger m_logger;
- ScriptEngine *m_engine;
- Loader *loader;
- TopLevelProjectPtr project;
- SetupProjectParameters defaultParameters;
+ qbs::ILogSink *m_logSink;
+ qbs::Settings * const m_settings;
+ qbs::Internal::Logger m_logger;
+ qbs::Internal::ScriptEngine *m_engine;
+ qbs::Internal::Loader *loader;
+ qbs::Internal::TopLevelProjectPtr project;
+ qbs::SetupProjectParameters defaultParameters;
const QString m_wildcardsTestDirPath;
- QHash<QString, ResolvedProductPtr> productsFromProject(ResolvedProjectPtr project);
- ResolvedModuleConstPtr findModuleByName(ResolvedProductPtr product, const QString &name);
- QVariant productPropertyValue(ResolvedProductPtr product, QString propertyName);
+ QHash<QString, qbs::Internal::ResolvedProductPtr> productsFromProject(
+ qbs::Internal::ResolvedProjectPtr project);
+ qbs::Internal::ResolvedModuleConstPtr findModuleByName(
+ qbs::Internal::ResolvedProductPtr product, const QString &name);
+ QVariant productPropertyValue(qbs::Internal::ResolvedProductPtr product, QString propertyName);
void handleInitCleanupDataTags(const char *projectFileName, bool *handled);
private slots:
@@ -148,7 +147,5 @@ private slots:
void wildcards();
};
-} // namespace Internal
-} // namespace qbs
-
#endif // TST_LANGUAGE_H
+
diff --git a/tests/auto/tools/tools.pro b/tests/auto/tools/tools.pro
index 0ee10216e..ba293f417 100644
--- a/tests/auto/tools/tools.pro
+++ b/tests/auto/tools/tools.pro
@@ -1,5 +1,6 @@
TARGET = tst_tools
SOURCES = tst_tools.cpp ../../../src/app/qbs/qbstool.cpp
+HEADERS = tst_tools.h
include(../auto.pri)
diff --git a/tests/auto/tools/tools.qbs b/tests/auto/tools/tools.qbs
index 612a70a40..c626c7704 100644
--- a/tests/auto/tools/tools.qbs
+++ b/tests/auto/tools/tools.qbs
@@ -1,7 +1,15 @@
import qbs
QbsAutotest {
+ Depends { name: "qbsversion" }
+
testName: "tools"
condition: qbsbuildconfig.enableUnitTests
- files: ["tst_tools.cpp"]
+ files: [
+ "tst_tools.cpp",
+ "tst_tools.h"
+ ]
+
+ // TODO: Use Utilities.cStringQuote
+ cpp.defines: ['QBS_VERSION="' + qbsversion.version + '"']
}
diff --git a/tests/auto/tools/tst_tools.cpp b/tests/auto/tools/tst_tools.cpp
index 88337787e..13bc18b36 100644
--- a/tests/auto/tools/tst_tools.cpp
+++ b/tests/auto/tools/tst_tools.cpp
@@ -5,7 +5,7 @@
**
** This file is part of Qbs.
**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -14,30 +14,944 @@
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
+#undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack.
+
+#include "tst_tools.h"
#include "../shared.h"
-#include <tools/tst_tools.h>
-#include <QtCore/qcoreapplication.h>
+#include <tools/buildoptions.h>
+#include <tools/error.h>
+#include <tools/fileinfo.h>
+#include <tools/hostosinfo.h>
+#include <tools/processutils.h>
+#include <tools/profile.h>
+#include <tools/set.h>
+#include <tools/settings.h>
+#include <tools/setupprojectparameters.h>
+#include <tools/version.h>
+
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qtemporarydir.h>
+#include <QtCore/qtemporaryfile.h>
#include <QtTest/qtest.h>
+using namespace qbs;
+using namespace qbs::Internal;
+
+TestTools::TestTools(Settings *settings) : m_settings(settings)
+{
+}
+
+TestTools::~TestTools()
+{
+ qDeleteAll(m_tmpDirs);
+}
+
+void TestTools::testFileInfo()
+{
+ QCOMPARE(FileInfo::fileName("C:/waffl/copter.exe"), QString("copter.exe"));
+ QCOMPARE(FileInfo::baseName("C:/waffl/copter.exe.lib"), QString("copter"));
+ QCOMPARE(FileInfo::completeBaseName("C:/waffl/copter.exe.lib"), QString("copter.exe"));
+ QCOMPARE(FileInfo::path("abc"), QString("."));
+ QCOMPARE(FileInfo::path("/abc/lol"), QString("/abc"));
+ QCOMPARE(FileInfo::path("/fileInRoot"), QString(QLatin1Char('/')));
+ if (HostOsInfo::isWindowsHost())
+ QCOMPARE(FileInfo::path("C:/fileInDriveRoot"), QString("C:/"));
+ QVERIFY(!FileInfo::isAbsolute("bla/lol"));
+ QVERIFY(FileInfo::isAbsolute("/bla/lol"));
+ if (HostOsInfo::isWindowsHost())
+ QVERIFY(FileInfo::isAbsolute("C:\\bla\\lol"));
+ QCOMPARE(FileInfo::resolvePath("/abc/lol", "waffl"), QString("/abc/lol/waffl"));
+ QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../foo/bar"), QString("/abc/def/ghi/foo/bar"));
+ QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../../foo/bar"), QString("/abc/def/foo/bar"));
+ QCOMPARE(FileInfo::resolvePath("/abc", "../../../foo/bar"), QString("/foo/bar"));
+ QCOMPARE(FileInfo("/does/not/exist").lastModified(), FileTime());
+}
+
+void TestTools::fileCaseCheck()
+{
+ QTemporaryFile tempFile(QDir::tempPath() + QLatin1String("/CamelCase"));
+ QVERIFY2(tempFile.open(), qPrintable(tempFile.errorString()));
+ QFileInfo tempFileInfo(tempFile.fileName());
+ const QString lowerFilePath = tempFileInfo.absolutePath() + QLatin1Char('/')
+ + tempFileInfo.fileName().toLower();
+ const QString upperFilePath = tempFileInfo.absolutePath() + QLatin1Char('/')
+ + tempFileInfo.fileName().toUpper();
+ QVERIFY(FileInfo::isFileCaseCorrect(tempFileInfo.absoluteFilePath()));
+ if (QFile::exists(lowerFilePath))
+ QVERIFY(!FileInfo::isFileCaseCorrect(lowerFilePath));
+ if (QFile::exists(upperFilePath))
+ QVERIFY(!FileInfo::isFileCaseCorrect(upperFilePath));
+}
+
+void TestTools::testProfiles()
+{
+ TemporaryProfile tpp("parent", m_settings);
+ Profile parentProfile = tpp.p;
+ TemporaryProfile tpc("child", m_settings);
+ Profile childProfile = tpc.p;
+ parentProfile.removeBaseProfile();
+ parentProfile.remove("testKey");
+ QCOMPARE(parentProfile.value("testKey", "none").toString(), QLatin1String("none"));
+ parentProfile.setValue("testKey", "testValue");
+ QCOMPARE(parentProfile.value("testKey").toString(), QLatin1String("testValue"));
+
+ childProfile.remove("testKey");
+ childProfile.removeBaseProfile();
+ QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("none"));
+ childProfile.setBaseProfile("parent");
+ QCOMPARE(childProfile.value("testKey").toString(), QLatin1String("testValue"));
+
+ // Change base profile and check if the inherited value also changes.
+ TemporaryProfile tpf("foo", m_settings);
+ Profile fooProfile = tpf.p;
+ fooProfile.setValue("testKey", "gnampf");
+ childProfile.setBaseProfile("foo");
+ QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("gnampf"));
+
+ ErrorInfo errorInfo;
+ childProfile.setBaseProfile("SmurfAlongWithMe");
+ childProfile.value("blubb", QString(), &errorInfo);
+ QVERIFY(errorInfo.hasError());
+
+ errorInfo.clear();
+ childProfile.setBaseProfile("parent");
+ parentProfile.setBaseProfile("child");
+ QVERIFY(!childProfile.value("blubb", QString(), &errorInfo).isValid());
+ QVERIFY(errorInfo.hasError());
+
+ QVERIFY(!childProfile.allKeys(Profile::KeySelectionNonRecursive).isEmpty());
+
+ errorInfo.clear();
+ QVERIFY(childProfile.allKeys(Profile::KeySelectionRecursive, &errorInfo).isEmpty());
+ QVERIFY(errorInfo.hasError());
+}
+
+void TestTools::testSettingsMigration()
+{
+ QFETCH(QString, baseDir);
+ QFETCH(bool, hasOldSettings);
+ Settings settings(baseDir);
+ if (hasOldSettings) {
+ QVERIFY(QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles/right.txt")
+ .exists());
+ QCOMPARE(settings.value("key").toString(),
+ settings.baseDirectory() + "/qbs/" QBS_VERSION "/profilesright");
+ } else {
+ QVERIFY(!QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles").exists());
+ QVERIFY(settings.allKeys().isEmpty());
+ }
+}
+
+void TestTools::testSettingsMigration_data()
+{
+ QTest::addColumn<QString>("baseDir");
+ QTest::addColumn<bool>("hasOldSettings");
+ QTest::newRow("settings dir with lots of versions") << setupSettingsDir1() << true;
+ QTest::newRow("settings dir with only a fallback") << setupSettingsDir2() << true;
+ QTest::newRow("no previous settings") << setupSettingsDir3() << false;
+}
+
+QString TestTools::setupSettingsDir1()
+{
+ QTemporaryDir * const baseDir = new QTemporaryDir;
+ m_tmpDirs << baseDir;
+
+ const Version thisVersion = Version::fromString(QBS_VERSION);
+ Version predecessor;
+ if (thisVersion.patchLevel() > 0) {
+ predecessor.setMajorVersion(thisVersion.majorVersion());
+ predecessor.setMinorVersion(thisVersion.minorVersion());
+ predecessor.setPatchLevel(thisVersion.patchLevel() - 1);
+ } else if (thisVersion.minorVersion() > 0) {
+ predecessor.setMajorVersion(thisVersion.majorVersion());
+ predecessor.setMinorVersion(thisVersion.minorVersion() - 1);
+ predecessor.setPatchLevel(99);
+ } else {
+ predecessor.setMajorVersion(thisVersion.majorVersion() - 1);
+ predecessor.setMajorVersion(99);
+ predecessor.setPatchLevel(99);
+ }
+ const auto versions = QList<Version>() << Version(0, 1, 0) << Version(1, 0, 5) << predecessor
+ << Version(thisVersion.majorVersion() + 1, thisVersion.minorVersion(),
+ thisVersion.patchLevel())
+ << Version(thisVersion.majorVersion(), thisVersion.minorVersion() + 1,
+ thisVersion.patchLevel())
+ << Version(thisVersion.majorVersion(), thisVersion.minorVersion(),
+ thisVersion.patchLevel() + 1)
+ << Version(99, 99, 99);
+ foreach (const Version &v, versions) {
+ const QString settingsDir = baseDir->path() + "/qbs/" + v.toString();
+ QSettings s(settingsDir + "/qbs.conf",
+ HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat);
+ const QString profilesDir = settingsDir + "/profiles";
+ QDir::root().mkpath(profilesDir);
+ const QString magicString = v == predecessor ? "right" : "wrong";
+ QFile f(profilesDir + '/' + magicString + ".txt");
+ f.open(QIODevice::WriteOnly);
+ s.setValue("org/qt-project/qbs/key", profilesDir + magicString);
+ }
+
+ return baseDir->path();
+}
+
+QString TestTools::setupSettingsDir2()
+{
+ QTemporaryDir * const baseDir = new QTemporaryDir;
+ m_tmpDirs << baseDir;
+ const QString settingsDir = baseDir->path();
+ QSettings s(settingsDir + QLatin1String("/qbs.conf"),
+ HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat);
+ const QString profilesDir = settingsDir + QLatin1String("/qbs/profiles");
+ QDir::root().mkpath(profilesDir);
+ QFile f(profilesDir + "/right.txt");
+ f.open(QIODevice::WriteOnly);
+ s.setValue("org/qt-project/qbs/key", profilesDir + "right");
+
+ return baseDir->path();
+}
+
+QString TestTools::setupSettingsDir3()
+{
+ auto * const baseDir = new QTemporaryDir;
+ m_tmpDirs << baseDir;
+ return baseDir->path();
+}
+
+void TestTools::testBuildConfigMerging()
+{
+ TemporaryProfile tp(QLatin1String("tst_tools_profile"), m_settings);
+ Profile profile = tp.p;
+ profile.setValue(QLatin1String("topLevelKey"), QLatin1String("topLevelValue"));
+ profile.setValue(QLatin1String("qbs.toolchain"), QLatin1String("gcc"));
+ profile.setValue(QLatin1String("qbs.architecture"),
+ QLatin1String("Jean-Claude Pillemann"));
+ profile.setValue(QLatin1String("cpp.treatWarningsAsErrors"), true);
+ QVariantMap overrideMap;
+ overrideMap.insert(QLatin1String("qbs.toolchain"), QLatin1String("clang"));
+ overrideMap.insert(QLatin1String("qbs.installRoot"), QLatin1String("/blubb"));
+ SetupProjectParameters params;
+ params.setSettingsDirectory(m_settings->baseDirectory());
+ params.setTopLevelProfile(profile.name());
+ params.setConfigurationName(QLatin1String("debug"));
+ params.setOverriddenValues(overrideMap);
+ const ErrorInfo error = params.expandBuildConfiguration();
+ QVERIFY2(!error.hasError(), qPrintable(error.toString()));
+ const QVariantMap finalMap = params.finalBuildConfigurationTree();
+ QCOMPARE(finalMap.count(), 3);
+ QCOMPARE(finalMap.value(QLatin1String("topLevelKey")).toString(),
+ QString::fromLatin1("topLevelValue"));
+ const QVariantMap finalQbsMap = finalMap.value(QLatin1String("qbs")).toMap();
+ QCOMPARE(finalQbsMap.count(), 4);
+ QCOMPARE(finalQbsMap.value(QLatin1String("toolchain")).toString(),
+ QString::fromLatin1("clang"));
+ QCOMPARE(finalQbsMap.value(QLatin1String("configurationName")).toString(),
+ QString::fromLatin1("debug"));
+ QCOMPARE(finalQbsMap.value(QLatin1String("architecture")).toString(),
+ QString::fromLatin1("Jean-Claude Pillemann"));
+ QCOMPARE(finalQbsMap.value(QLatin1String("installRoot")).toString(), QLatin1String("/blubb"));
+ const QVariantMap finalCppMap = finalMap.value(QLatin1String("cpp")).toMap();
+ QCOMPARE(finalCppMap.count(), 1);
+ QCOMPARE(finalCppMap.value(QLatin1String("treatWarningsAsErrors")).toBool(), true);
+}
+
+void TestTools::testProcessNameByPid()
+{
+ QCOMPARE(qAppName(), processNameByPid(QCoreApplication::applicationPid()));
+}
+
+
+int toNumber(const QString &str)
+{
+ int res = 0;
+ for (int i = 0; i < str.length(); ++i)
+ res = (res * 10) + str[i].digitValue();
+ return res;
+}
+
+void TestTools::set_operator_eq()
+{
+ {
+ Set<int> set1, set2;
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set1.insert(1);
+ QVERIFY(set1 != set2);
+ QVERIFY(!(set1 == set2));
+
+ set2.insert(1);
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set2.insert(1);
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set1.insert(2);
+ QVERIFY(set1 != set2);
+ QVERIFY(!(set1 == set2));
+ }
+
+ {
+ Set<QString> set1, set2;
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set1.insert("one");
+ QVERIFY(set1 != set2);
+ QVERIFY(!(set1 == set2));
+
+ set2.insert("one");
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set2.insert("one");
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set1.insert("two");
+ QVERIFY(set1 != set2);
+ QVERIFY(!(set1 == set2));
+ }
+
+ {
+ Set<QString> a;
+ Set<QString> b;
+
+ a += "otto";
+ b += "willy";
+
+ QVERIFY(a != b);
+ QVERIFY(!(a == b));
+ }
+
+ {
+ Set<int> s1, s2;
+ s1.reserve(100);
+ s2.reserve(4);
+ QVERIFY(s1 == s2);
+ s1 << 100 << 200 << 300 << 400;
+ s2 << 400 << 300 << 200 << 100;
+ QVERIFY(s1 == s2);
+ }
+}
+
+void TestTools::set_swap()
+{
+ Set<int> s1, s2;
+ s1.insert(1);
+ s2.insert(2);
+ s1.swap(s2);
+ QCOMPARE(*s1.begin(),2);
+ QCOMPARE(*s2.begin(),1);
+}
+
+void TestTools::set_size()
+{
+ Set<int> set;
+ QVERIFY(set.size() == 0);
+ QVERIFY(set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.insert(1);
+ QVERIFY(set.size() == 1);
+ QVERIFY(!set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.insert(1);
+ QVERIFY(set.size() == 1);
+ QVERIFY(!set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.insert(2);
+ QVERIFY(set.size() == 2);
+ QVERIFY(!set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.remove(1);
+ QVERIFY(set.size() == 1);
+ QVERIFY(!set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.remove(1);
+ QVERIFY(set.size() == 1);
+ QVERIFY(!set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.remove(2);
+ QVERIFY(set.size() == 0);
+ QVERIFY(set.isEmpty());
+ QVERIFY(set.count() == set.size());
+}
+
+void TestTools::set_capacity()
+{
+ Set<int> set;
+ int n = set.capacity();
+ QVERIFY(n == 0);
+
+ for (int i = 0; i < 1000; ++i) {
+ set.insert(i);
+ QVERIFY(set.capacity() >= set.size());
+ }
+}
+
+void TestTools::set_reserve()
+{
+ Set<int> set;
+
+ set.reserve(1000);
+ QVERIFY(set.capacity() >= 1000);
+
+ for (int i = 0; i < 500; ++i)
+ set.insert(i);
+
+ QVERIFY(set.capacity() >= 1000);
+
+ for (int j = 0; j < 500; ++j)
+ set.remove(j);
+
+ QVERIFY(set.capacity() >= 1000);
+}
+
+void TestTools::set_clear()
+{
+ Set<QString> set1, set2;
+ QVERIFY(set1.size() == 0);
+
+ set1.clear();
+ QVERIFY(set1.size() == 0);
+
+ set1.insert("foo");
+ QVERIFY(set1.size() != 0);
+
+ set2 = set1;
+
+ set1.clear();
+ QVERIFY(set1.size() == 0);
+ QVERIFY(set2.size() != 0);
+
+ set2.clear();
+ QVERIFY(set1.size() == 0);
+ QVERIFY(set2.size() == 0);
+}
+
+void TestTools::set_remove()
+{
+ Set<QString> set1;
+
+ for (int i = 0; i < 500; ++i)
+ set1.insert(QString::number(i));
+
+ QCOMPARE(set1.size(), 500);
+
+ for (int j = 0; j < 500; ++j) {
+ set1.remove(QString::number((j * 17) % 500));
+ QCOMPARE(set1.size(), 500 - j - 1);
+ }
+}
+
+void TestTools::set_contains()
+{
+ Set<QString> set1;
+
+ for (int i = 0; i < 500; ++i) {
+ QVERIFY(!set1.contains(QString::number(i)));
+ set1.insert(QString::number(i));
+ QVERIFY(set1.contains(QString::number(i)));
+ }
+
+ QCOMPARE(set1.size(), 500);
+
+ for (int j = 0; j < 500; ++j) {
+ int i = (j * 17) % 500;
+ QVERIFY(set1.contains(QString::number(i)));
+ set1.remove(QString::number(i));
+ QVERIFY(!set1.contains(QString::number(i)));
+ }
+}
+
+void TestTools::set_containsSet()
+{
+ Set<QString> set1;
+ Set<QString> set2;
+
+ // empty set contains the empty set
+ QVERIFY(set1.contains(set2));
+
+ for (int i = 0; i < 500; ++i) {
+ set1.insert(QString::number(i));
+ set2.insert(QString::number(i));
+ }
+ QVERIFY(set1.contains(set2));
+
+ set2.remove(QString::number(19));
+ set2.remove(QString::number(82));
+ set2.remove(QString::number(7));
+ QVERIFY(set1.contains(set2));
+
+ set1.remove(QString::number(23));
+ QVERIFY(!set1.contains(set2));
+
+ // filled set contains the empty set as well
+ Set<QString> set3;
+ QVERIFY(set1.contains(set3));
+
+ // the empty set doesn't contain a filled set
+ QVERIFY(!set3.contains(set1));
+
+ // verify const signature
+ const Set<QString> set4;
+ QVERIFY(set3.contains(set4));
+}
+
+void TestTools::set_begin()
+{
+ Set<int> set1;
+ Set<int> set2 = set1;
+
+ {
+ Set<int>::const_iterator i = set1.constBegin();
+ Set<int>::const_iterator j = set1.cbegin();
+ Set<int>::const_iterator k = set2.constBegin();
+ Set<int>::const_iterator ell = set2.cbegin();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+ }
+
+ set1.insert(44);
+
+ {
+ Set<int>::const_iterator i = set1.constBegin();
+ Set<int>::const_iterator j = set1.cbegin();
+ Set<int>::const_iterator k = set2.constBegin();
+ Set<int>::const_iterator ell = set2.cbegin();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+ }
+
+ set2 = set1;
+
+ {
+ Set<int>::const_iterator i = set1.constBegin();
+ Set<int>::const_iterator j = set1.cbegin();
+ Set<int>::const_iterator k = set2.constBegin();
+ Set<int>::const_iterator ell = set2.cbegin();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+ }
+}
+
+void TestTools::set_end()
+{
+ Set<int> set1;
+ Set<int> set2 = set1;
+
+ {
+ Set<int>::const_iterator i = set1.constEnd();
+ Set<int>::const_iterator j = set1.cend();
+ Set<int>::const_iterator k = set2.constEnd();
+ Set<int>::const_iterator ell = set2.cend();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+
+ QVERIFY(set1.constBegin() == set1.constEnd());
+ QVERIFY(set2.constBegin() == set2.constEnd());
+ }
+
+ set1.insert(44);
+
+ {
+ Set<int>::const_iterator i = set1.constEnd();
+ Set<int>::const_iterator j = set1.cend();
+ Set<int>::const_iterator k = set2.constEnd();
+ Set<int>::const_iterator ell = set2.cend();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+
+ QVERIFY(set1.constBegin() != set1.constEnd());
+ QVERIFY(set2.constBegin() == set2.constEnd());
+ }
+
+ set2 = set1;
+
+ {
+ Set<int>::const_iterator i = set1.constEnd();
+ Set<int>::const_iterator j = set1.cend();
+ Set<int>::const_iterator k = set2.constEnd();
+ Set<int>::const_iterator ell = set2.cend();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+
+ QVERIFY(set1.constBegin() != set1.constEnd());
+ QVERIFY(set2.constBegin() != set2.constEnd());
+ }
+
+ set1.clear();
+ set2.clear();
+ QVERIFY(set1.constBegin() == set1.constEnd());
+ QVERIFY(set2.constBegin() == set2.constEnd());
+}
+
+struct IdentityTracker {
+ int value, id;
+};
+inline bool operator==(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value == rhs.value; }
+inline bool operator<(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value < rhs.value; }
+
+void TestTools::set_insert()
+{
+ {
+ Set<int> set1;
+ QVERIFY(set1.size() == 0);
+ set1.insert(1);
+ QVERIFY(set1.size() == 1);
+ set1.insert(2);
+ QVERIFY(set1.size() == 2);
+ set1.insert(2);
+ QVERIFY(set1.size() == 2);
+ QVERIFY(set1.contains(2));
+ set1.remove(2);
+ QVERIFY(set1.size() == 1);
+ QVERIFY(!set1.contains(2));
+ set1.insert(2);
+ QVERIFY(set1.size() == 2);
+ QVERIFY(set1.contains(2));
+ }
+
+ {
+ Set<int> set1;
+ QVERIFY(set1.size() == 0);
+ set1 << 1;
+ QVERIFY(set1.size() == 1);
+ set1 << 2;
+ QVERIFY(set1.size() == 2);
+ set1 << 2;
+ QVERIFY(set1.size() == 2);
+ QVERIFY(set1.contains(2));
+ set1.remove(2);
+ QVERIFY(set1.size() == 1);
+ QVERIFY(!set1.contains(2));
+ set1 << 2;
+ QVERIFY(set1.size() == 2);
+ QVERIFY(set1.contains(2));
+ }
+
+ {
+ Set<IdentityTracker> set;
+ QCOMPARE(set.size(), 0);
+ const int dummy = -1;
+ IdentityTracker id00 = {0, 0}, id01 = {0, 1}, searchKey = {0, dummy};
+ QCOMPARE(set.insert(id00).first->id, id00.id);
+ QCOMPARE(set.size(), 1);
+ QCOMPARE(set.insert(id01).first->id, id00.id); // first inserted is kept
+ QCOMPARE(set.size(), 1);
+ QCOMPARE(set.find(searchKey)->id, id00.id);
+ }
+}
+
+void TestTools::set_reverseIterators()
+{
+ Set<int> s;
+ s << 1 << 17 << 61 << 127 << 911;
+ std::vector<int> v(s.begin(), s.end());
+ std::reverse(v.begin(), v.end());
+ const Set<int> &cs = s;
+ QVERIFY(std::equal(v.begin(), v.end(), s.rbegin()));
+ QVERIFY(std::equal(v.begin(), v.end(), s.crbegin()));
+ QVERIFY(std::equal(v.begin(), v.end(), cs.rbegin()));
+ QVERIFY(std::equal(s.rbegin(), s.rend(), v.begin()));
+ QVERIFY(std::equal(s.crbegin(), s.crend(), v.begin()));
+ QVERIFY(std::equal(cs.rbegin(), cs.rend(), v.begin()));
+}
+
+void TestTools::set_stlIterator()
+{
+ Set<QString> set1;
+ for (int i = 0; i < 25000; ++i)
+ set1.insert(QString::number(i));
+
+ {
+ int sum = 0;
+ Set<QString>::const_iterator i = set1.cbegin();
+ while (i != set1.end()) {
+ sum += toNumber(*i);
+ ++i;
+ }
+ QVERIFY(sum == 24999 * 25000 / 2);
+ }
+
+ {
+ int sum = 0;
+ Set<QString>::const_iterator i = set1.cend();
+ while (i != set1.begin()) {
+ --i;
+ sum += toNumber(*i);
+ }
+ QVERIFY(sum == 24999 * 25000 / 2);
+ }
+}
+
+void TestTools::set_stlMutableIterator()
+{
+ Set<QString> set1;
+ for (int i = 0; i < 25000; ++i)
+ set1.insert(QString::number(i));
+
+ {
+ int sum = 0;
+ Set<QString>::iterator i = set1.begin();
+ while (i != set1.end()) {
+ sum += toNumber(*i);
+ ++i;
+ }
+ QVERIFY(sum == 24999 * 25000 / 2);
+ }
+
+ {
+ int sum = 0;
+ Set<QString>::iterator i = set1.end();
+ while (i != set1.begin()) {
+ --i;
+ sum += toNumber(*i);
+ }
+ QVERIFY(sum == 24999 * 25000 / 2);
+ }
+
+ {
+ Set<QString> set2 = set1;
+ Set<QString> set3 = set2;
+
+ Set<QString>::iterator i = set2.begin();
+ Set<QString>::iterator j = set3.begin();
+
+ while (i != set2.end()) {
+ i = set2.erase(i);
+ }
+ QVERIFY(set2.isEmpty());
+ QVERIFY(!set3.isEmpty());
+
+ j = set3.end();
+ while (j != set3.begin()) {
+ j--;
+ if (j + 1 != set3.end())
+ set3.erase(j + 1);
+ }
+ if (set3.begin() != set3.end())
+ set3.erase(set3.begin());
+
+ QVERIFY(set2.isEmpty());
+ QVERIFY(set3.isEmpty());
+
+ i = set2.insert("foo").first;
+ QCOMPARE(*i, QLatin1String("foo"));
+ }
+}
+
+void TestTools::set_setOperations()
+{
+ Set<QString> set1, set2;
+ set1 << "alpha" << "beta" << "gamma" << "delta" << "zeta" << "omega";
+ set2 << "beta" << "gamma" << "delta" << "epsilon" << "iota" << "omega";
+
+ Set<QString> set3 = set1;
+ set3.unite(set2);
+ QVERIFY(set3.size() == 8);
+ QVERIFY(set3.contains("alpha"));
+ QVERIFY(set3.contains("beta"));
+ QVERIFY(set3.contains("gamma"));
+ QVERIFY(set3.contains("delta"));
+ QVERIFY(set3.contains("epsilon"));
+ QVERIFY(set3.contains("zeta"));
+ QVERIFY(set3.contains("iota"));
+ QVERIFY(set3.contains("omega"));
+
+ Set<QString> set4 = set2;
+ set4.unite(set1);
+ QVERIFY(set4.size() == 8);
+ QVERIFY(set4.contains("alpha"));
+ QVERIFY(set4.contains("beta"));
+ QVERIFY(set4.contains("gamma"));
+ QVERIFY(set4.contains("delta"));
+ QVERIFY(set4.contains("epsilon"));
+ QVERIFY(set4.contains("zeta"));
+ QVERIFY(set4.contains("iota"));
+ QVERIFY(set4.contains("omega"));
+
+ QVERIFY(set3 == set4);
+
+ Set<QString> set5 = set1;
+ set5.intersect(set2);
+ QVERIFY(set5.size() == 4);
+ QVERIFY(set5.contains("beta"));
+ QVERIFY(set5.contains("gamma"));
+ QVERIFY(set5.contains("delta"));
+ QVERIFY(set5.contains("omega"));
+
+ Set<QString> set6 = set2;
+ set6.intersect(set1);
+ QVERIFY(set6.size() == 4);
+ QVERIFY(set6.contains("beta"));
+ QVERIFY(set6.contains("gamma"));
+ QVERIFY(set6.contains("delta"));
+ QVERIFY(set6.contains("omega"));
+
+ QVERIFY(set5 == set6);
+
+ Set<QString> set7 = set1;
+ set7.subtract(set2);
+ QVERIFY(set7.size() == 2);
+ QVERIFY(set7.contains("alpha"));
+ QVERIFY(set7.contains("zeta"));
+
+ Set<QString> set8 = set2;
+ set8.subtract(set1);
+ QVERIFY(set8.size() == 2);
+ QVERIFY(set8.contains("epsilon"));
+ QVERIFY(set8.contains("iota"));
+
+ Set<QString> set9 = set1 | set2;
+ QVERIFY(set9 == set3);
+
+ Set<QString> set10 = set1 & set2;
+ QVERIFY(set10 == set5);
+
+ Set<QString> set11 = set1 + set2;
+ QVERIFY(set11 == set3);
+
+ Set<QString> set12 = set1 - set2;
+ QVERIFY(set12 == set7);
+
+ Set<QString> set13 = set2 - set1;
+ QVERIFY(set13 == set8);
+
+ Set<QString> set14 = set1;
+ set14 |= set2;
+ QVERIFY(set14 == set3);
+
+ Set<QString> set15 = set1;
+ set15 &= set2;
+ QVERIFY(set15 == set5);
+
+ Set<QString> set16 = set1;
+ set16 += set2;
+ QVERIFY(set16 == set3);
+
+ Set<QString> set17 = set1;
+ set17 -= set2;
+ QVERIFY(set17 == set7);
+
+ Set<QString> set18 = set2;
+ set18 -= set1;
+ QVERIFY(set18 == set8);
+}
+
+void TestTools::set_makeSureTheComfortFunctionsCompile()
+{
+ Set<int> set1, set2, set3;
+ set1 << 5;
+ set1 |= set2;
+ set1 |= 5;
+ set1 &= set2;
+ set1 &= 5;
+ set1 += set2;
+ set1 += 5;
+ set1 -= set2;
+ set1 -= 5;
+ set1 = set2 | set3;
+ set1 = set2 & set3;
+ set1 = set2 + set3;
+ set1 = set2 - set3;
+}
+
+void TestTools::set_initializerList()
+{
+ Set<int> set = {1, 1, 2, 3, 4, 5};
+ QCOMPARE(set.count(), 5);
+ QVERIFY(set.contains(1));
+ QVERIFY(set.contains(2));
+ QVERIFY(set.contains(3));
+ QVERIFY(set.contains(4));
+ QVERIFY(set.contains(5));
+
+ // check _which_ of the equal elements gets inserted (in the QHash/QMap case, it's the last):
+ const Set<IdentityTracker> set2 = {{1, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ QCOMPARE(set2.count(), 5);
+ const int dummy = -1;
+ const IdentityTracker searchKey = {1, dummy};
+ QCOMPARE(set2.find(searchKey)->id, 0);
+
+ Set<int> emptySet{};
+ QVERIFY(emptySet.isEmpty());
+
+ Set<int> set3{{}, {}, {}};
+ QVERIFY(!set3.isEmpty());
+}
+
+void TestTools::set_intersects()
+{
+ Set<int> s1;
+ Set<int> s2;
+
+ QVERIFY(!s1.intersects(s1));
+ QVERIFY(!s1.intersects(s2));
+
+ s1 << 100;
+ QVERIFY(s1.intersects(s1));
+ QVERIFY(!s1.intersects(s2));
+
+ s2 << 200;
+ QVERIFY(!s1.intersects(s2));
+
+ s1 << 200;
+ QVERIFY(s1.intersects(s2));
+
+ Set<int> s3;
+ s3 << 500;
+ QVERIFY(!s1.intersects(s3));
+ s3 << 200;
+ QVERIFY(s1.intersects(s3));
+}
+
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
const SettingsPtr s = settings();
- qbs::Internal::TestTools tt(s.get());
+ TestTools tt(s.get());
return QTest::qExec(&tt, argc, argv);
}
diff --git a/src/lib/corelib/tools/tst_tools.h b/tests/auto/tools/tst_tools.h
index 27a6b5da0..cb6828ee8 100644
--- a/src/lib/corelib/tools/tst_tools.h
+++ b/tests/auto/tools/tst_tools.h
@@ -36,7 +36,6 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include "qbs_export.h"
#include <QtCore/qlist.h>
#include <QtCore/qobject.h>
@@ -47,15 +46,14 @@ QT_END_NAMESPACE
namespace qbs {
class Settings;
+}
-namespace Internal {
-
-class QBS_EXPORT TestTools : public QObject
+class TestTools : public QObject
{
Q_OBJECT
public:
- TestTools(Settings *settings);
+ TestTools(qbs::Settings *settings);
~TestTools();
private slots:
@@ -92,9 +90,6 @@ private:
QString setupSettingsDir2();
QString setupSettingsDir3();
- Settings * const m_settings;
+ qbs::Settings * const m_settings;
QList<QTemporaryDir *> m_tmpDirs;
};
-
-} // namespace Internal
-} // namespace qbs