forked from qt-creator/qt-creator
QmlProjectManager: Generate .qmlproject file based on qmldir (McuModuleProjectItem)
Task-number: QDS-13811 Change-Id: I187f04fbc4ba7752e9e1d7eb634c0904abae3a2f Reviewed-by: Marco Bubke <marco.bubke@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -53,6 +53,13 @@ extend_qtc_plugin(QmlProjectManager
|
|||||||
boilerplate.qrc
|
boilerplate.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
extend_qtc_plugin(QmlProjectManager
|
||||||
|
PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/qmldirtoqmlproject
|
||||||
|
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/qmldirtoqmlproject
|
||||||
|
SOURCES
|
||||||
|
mcumoduleprojectitem.cpp mcumoduleprojectitem.h
|
||||||
|
)
|
||||||
|
|
||||||
add_qtc_library(QmlProjectManagerLib OBJECT
|
add_qtc_library(QmlProjectManagerLib OBJECT
|
||||||
CONDITION WITH_TESTS AND Qt6_VERSION VERSION_GREATER_EQUAL 6.4.3
|
CONDITION WITH_TESTS AND Qt6_VERSION VERSION_GREATER_EQUAL 6.4.3
|
||||||
EXCLUDE_FROM_INSTALL
|
EXCLUDE_FROM_INSTALL
|
||||||
@@ -66,4 +73,5 @@ add_qtc_library(QmlProjectManagerLib OBJECT
|
|||||||
buildsystem/projectitem/qmlprojectitem.cpp buildsystem/projectitem/qmlprojectitem.h
|
buildsystem/projectitem/qmlprojectitem.cpp buildsystem/projectitem/qmlprojectitem.h
|
||||||
buildsystem/projectitem/converters.cpp buildsystem/projectitem/converters.h
|
buildsystem/projectitem/converters.cpp buildsystem/projectitem/converters.h
|
||||||
qmlprojectexporter/filetypes.cpp qmlprojectexporter/filetypes.h
|
qmlprojectexporter/filetypes.cpp qmlprojectexporter/filetypes.h
|
||||||
|
qmldirtoqmlproject/mcumoduleprojectitem.cpp qmldirtoqmlproject/mcumoduleprojectitem.h
|
||||||
)
|
)
|
||||||
|
@@ -0,0 +1,261 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "mcumoduleprojectitem.h"
|
||||||
|
|
||||||
|
#include <qmljs/qmljssimplereader.h>
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
using namespace Qt::Literals::StringLiterals;
|
||||||
|
|
||||||
|
namespace Constants {
|
||||||
|
namespace QmlDir {
|
||||||
|
constexpr auto QMLDIR = "qmldir"_L1;
|
||||||
|
constexpr auto MODULE = "module"_L1;
|
||||||
|
constexpr auto QML_FILE_FILTER = "*.qml"_L1;
|
||||||
|
} // namespace QmlDir
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
constexpr auto MODULE_URI = "moduleUri"_L1;
|
||||||
|
constexpr auto QML_FILES = "qmlFiles"_L1;
|
||||||
|
constexpr auto QMLPROJECT_PATH = "qmlProjectPath"_L1;
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
namespace QmlProject {
|
||||||
|
constexpr auto QMLPROJECT_EXTENSION = ".qmlproject"_L1;
|
||||||
|
constexpr auto MCU_MODULE = "MCU.Module"_L1;
|
||||||
|
constexpr auto URI = "uri"_L1;
|
||||||
|
constexpr auto QML_FILES = "QmlFiles"_L1;
|
||||||
|
constexpr auto FILES = "files"_L1;
|
||||||
|
|
||||||
|
const auto QMLPROJECT_TEMPLATE = QString(R"(/* File generated by Qt Design Studio */
|
||||||
|
|
||||||
|
import QmlProject 1.3
|
||||||
|
Project {
|
||||||
|
MCU.Module {
|
||||||
|
uri: %1
|
||||||
|
}
|
||||||
|
QmlFiles {
|
||||||
|
files: [
|
||||||
|
%2
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
} // namespace QmlProject
|
||||||
|
} // namespace Constants
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Q_LOGGING_CATEGORY(log, "QmlProjectManager.McuModuleProjectItem")
|
||||||
|
|
||||||
|
bool isValidQmlProjectPath(const Utils::FilePath &path)
|
||||||
|
{
|
||||||
|
return path.endsWith(Constants::QmlProject::QMLPROJECT_EXTENSION)
|
||||||
|
&& (path.ensureExistingFile() || path.parentDir().isWritableDir());
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject parseQmlProjectFile(const Utils::FilePath &qmlproject)
|
||||||
|
{
|
||||||
|
auto qmlprojectPathStr = qmlproject.toFSPathString();
|
||||||
|
|
||||||
|
if (!qmlproject.exists()) {
|
||||||
|
qCCritical(log) << "qmlproject file not found:" << qmlprojectPathStr;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlJS::SimpleReader reader;
|
||||||
|
QmlJS::SimpleReaderNode::Ptr rootNode = reader.readFile(qmlprojectPathStr);
|
||||||
|
if (!reader.errors().isEmpty() || !rootNode->isValid()) {
|
||||||
|
qCCritical(log) << "Unable to parse:" << qmlprojectPathStr;
|
||||||
|
qCCritical(log) << reader.errors();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject result;
|
||||||
|
result.insert(Constants::Json::QMLPROJECT_PATH, qmlprojectPathStr);
|
||||||
|
|
||||||
|
auto checkNodeName = [](const QString &node, const QString &expecedName) {
|
||||||
|
return node.compare(expecedName, Qt::CaseInsensitive) == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//expected just two nodes: MCU.Module and QmlFiles
|
||||||
|
for (const auto &childNode : rootNode->children()) {
|
||||||
|
auto nodeName = childNode->name();
|
||||||
|
if (checkNodeName(nodeName, Constants::QmlProject::MCU_MODULE)) {
|
||||||
|
result.insert(Constants::Json::MODULE_URI,
|
||||||
|
childNode->property(Constants::QmlProject::URI).value.toString());
|
||||||
|
} else if (checkNodeName(nodeName, Constants::QmlProject::QML_FILES)) {
|
||||||
|
result.insert(Constants::Json::QML_FILES,
|
||||||
|
childNode->property(Constants::QmlProject::FILES).value.toJsonArray());
|
||||||
|
} else {
|
||||||
|
qCWarning(log) << "Unsupported node:" << nodeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace QmlProjectManager {
|
||||||
|
McuModuleProjectItem::McuModuleProjectItem(const QJsonObject &project)
|
||||||
|
: m_project(project)
|
||||||
|
{}
|
||||||
|
|
||||||
|
McuModuleProjectItem::McuModuleProjectItem(const Utils::FilePath &qmlprojectFile)
|
||||||
|
: m_qmlProjectFile(qmlprojectFile)
|
||||||
|
, m_project(parseQmlProjectFile(m_qmlProjectFile))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<McuModuleProjectItem> McuModuleProjectItem::fromQmldirModule(const Utils::FilePath &qmldirFile)
|
||||||
|
{
|
||||||
|
auto qmldirFileStr = qmldirFile.toFSPathString();
|
||||||
|
|
||||||
|
// check qmldirFile
|
||||||
|
if (!qmldirFile.exists()) {
|
||||||
|
qCWarning(log) << "File not found:" << qmldirFileStr;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (qmldirFile.fileName() != Constants::QmlDir::QMLDIR) {
|
||||||
|
qCWarning(log) << "It's not qmldir file:" << qmldirFileStr;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto qmldirContents = qmldirFile.fileContents();
|
||||||
|
if (!qmldirContents) {
|
||||||
|
qCWarning(log) << "Unable to read the file:" << qmldirFileStr
|
||||||
|
<< ", error:" << qmldirContents.error();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// find module name
|
||||||
|
QByteArray fileContents = qmldirContents.value();
|
||||||
|
QTextStream ts(fileContents);
|
||||||
|
QString moduleName;
|
||||||
|
|
||||||
|
while (!ts.atEnd()) {
|
||||||
|
QString line = ts.readLine().trimmed();
|
||||||
|
if (line.startsWith(Constants::QmlDir::MODULE, Qt::CaseInsensitive)) {
|
||||||
|
auto list = line.split(' ');
|
||||||
|
if (list.size() != 2) {
|
||||||
|
qCWarning(log) << "Invalid module identifier:" << line;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
moduleName = list.last();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleName.isEmpty()) {
|
||||||
|
qCWarning(log) << "Module name not found in the qmldir";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// list qml files
|
||||||
|
const auto qmldirParent = qmldirFile.parentDir();
|
||||||
|
auto qmlDirEntries = qmldirParent.dirEntries(Utils::FileFilter{{Constants::QmlDir::QML_FILE_FILTER},
|
||||||
|
QDir::NoFilter,
|
||||||
|
QDirIterator::Subdirectories});
|
||||||
|
if (qmlDirEntries.empty()) {
|
||||||
|
qCWarning(log) << "No qml files found in:" << qmldirParent;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto qmlFiles = Utils::transform<QStringList>(qmlDirEntries, [qmldirParent](const Utils::FilePath &path) {
|
||||||
|
return path.relativePathFrom(qmldirParent).toFSPathString();
|
||||||
|
});
|
||||||
|
|
||||||
|
// build mcu module project
|
||||||
|
QJsonObject result;
|
||||||
|
result.insert(Constants::Json::MODULE_URI, moduleName);
|
||||||
|
result.insert(Constants::Json::QML_FILES, QJsonArray::fromStringList(qmlFiles));
|
||||||
|
|
||||||
|
auto filename = moduleName.replace('.', '_');
|
||||||
|
auto qmlprojectPath = qmldirParent.resolvePath(
|
||||||
|
Utils::FilePath::fromString(filename + Constants::QmlProject::QMLPROJECT_EXTENSION));
|
||||||
|
result.insert(Constants::Json::QMLPROJECT_PATH, qmlprojectPath.toFSPathString());
|
||||||
|
|
||||||
|
return McuModuleProjectItem(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool McuModuleProjectItem::isValid() const noexcept
|
||||||
|
{
|
||||||
|
return !uri().isEmpty() && !qmlFiles().isEmpty() && isValidQmlProjectPath(qmlProjectPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString McuModuleProjectItem::uri() const noexcept
|
||||||
|
{
|
||||||
|
return m_project[Constants::Json::MODULE_URI].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void McuModuleProjectItem::setUri(const QString &moduleUri)
|
||||||
|
{
|
||||||
|
m_project[Constants::Json::MODULE_URI] = moduleUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList McuModuleProjectItem::qmlFiles() const noexcept
|
||||||
|
{
|
||||||
|
return m_project[Constants::Json::QML_FILES].toVariant().toStringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void McuModuleProjectItem::setQmlFiles(const QStringList &files)
|
||||||
|
{
|
||||||
|
m_project[Constants::Json::QML_FILES] = QJsonArray::fromStringList(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::FilePath McuModuleProjectItem::qmlProjectPath() const noexcept
|
||||||
|
{
|
||||||
|
return Utils::FilePath::fromString(m_project[Constants::Json::QMLPROJECT_PATH].toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void McuModuleProjectItem::setQmlProjectPath(const Utils::FilePath &path)
|
||||||
|
{
|
||||||
|
m_project[Constants::Json::QMLPROJECT_PATH] = path.toFSPathString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject McuModuleProjectItem::project() const noexcept
|
||||||
|
{
|
||||||
|
return m_project;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool McuModuleProjectItem::saveQmlProjectFile() const
|
||||||
|
{
|
||||||
|
if (!isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto path = qmlProjectPath();
|
||||||
|
if (path.exists()) {
|
||||||
|
if (McuModuleProjectItem old(path); old == *this) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QTC_ASSERT_EXPECTED(path.writeFileContents(jsonToQmlproject()), return false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool McuModuleProjectItem::operator==(const McuModuleProjectItem &other) const noexcept
|
||||||
|
{
|
||||||
|
return this->project() == other.project();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray McuModuleProjectItem::jsonToQmlproject() const
|
||||||
|
{
|
||||||
|
auto quoted = [](const QString &s) { return QString("\"%1\"").arg(s); };
|
||||||
|
auto indent = [](int tabs = 1) { return QString(" ").repeated(tabs * 4); };
|
||||||
|
auto quotedQmlFiles = Utils::transform<QStringList>(qmlFiles(), [quoted](const QString &file) {
|
||||||
|
return quoted(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
QString qmlFilesSeparator;
|
||||||
|
QTextStream ts(&qmlFilesSeparator);
|
||||||
|
ts << "," << Qt::endl << indent(3);
|
||||||
|
|
||||||
|
return Constants::QmlProject::QMLPROJECT_TEMPLATE
|
||||||
|
.arg(quoted(uri()), quotedQmlFiles.join(qmlFilesSeparator))
|
||||||
|
.toUtf8();
|
||||||
|
}
|
||||||
|
} // namespace QmlProjectManager
|
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../qmlprojectmanager_global.h"
|
||||||
|
|
||||||
|
#include <utils/filepath.h>
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
#ifndef UNIT_TESTS
|
||||||
|
# define MCUMODULEPROJEC_EXPORT QMLPROJECTMANAGER_EXPORT
|
||||||
|
#else
|
||||||
|
# define MCUMODULEPROJEC_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace QmlProjectManager {
|
||||||
|
class MCUMODULEPROJEC_EXPORT McuModuleProjectItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit McuModuleProjectItem(const QJsonObject &project);
|
||||||
|
explicit McuModuleProjectItem(const Utils::FilePath &qmlprojectFile);
|
||||||
|
|
||||||
|
static std::optional<McuModuleProjectItem> fromQmldirModule(const Utils::FilePath &qmldirFile);
|
||||||
|
|
||||||
|
bool isValid() const noexcept;
|
||||||
|
|
||||||
|
QString uri() const noexcept;
|
||||||
|
void setUri(const QString &moduleUri);
|
||||||
|
|
||||||
|
QStringList qmlFiles() const noexcept;
|
||||||
|
void setQmlFiles(const QStringList &files);
|
||||||
|
|
||||||
|
Utils::FilePath qmlProjectPath() const noexcept;
|
||||||
|
void setQmlProjectPath(const Utils::FilePath &path);
|
||||||
|
|
||||||
|
QJsonObject project() const noexcept;
|
||||||
|
|
||||||
|
bool saveQmlProjectFile() const;
|
||||||
|
|
||||||
|
bool operator==(const McuModuleProjectItem &other) const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArray jsonToQmlproject() const;
|
||||||
|
|
||||||
|
Utils::FilePath m_qmlProjectFile;
|
||||||
|
QJsonObject m_project;
|
||||||
|
};
|
||||||
|
} // namespace QmlProjectManager
|
@@ -6,6 +6,7 @@ extend_qtc_test(unittest
|
|||||||
SOURCES
|
SOURCES
|
||||||
converters-test.cpp
|
converters-test.cpp
|
||||||
projectitem-test.cpp
|
projectitem-test.cpp
|
||||||
|
mcumoduleprojectitem-test.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
unittest_copy_data_folder()
|
unittest_copy_data_folder()
|
||||||
|
@@ -70,3 +70,13 @@ Some main points for qmlproject files for MCU projects:
|
|||||||
Test data contains an example project folders that file filters will be initialized and tested.
|
Test data contains an example project folders that file filters will be initialized and tested.
|
||||||
|
|
||||||
* **filelist.txt**: List of the files need to be found by the file filters.
|
* **filelist.txt**: List of the files need to be found by the file filters.
|
||||||
|
|
||||||
|
## Qml to qmlproject test data
|
||||||
|
Input data for the McuModuleProjectItem tests. McuModuleProjectItem represents the MCU module and can be generated from a regular QML module (based on qmldir).
|
||||||
|
|
||||||
|
* **existing_qmlproject**: read and process valid .qmlproject module
|
||||||
|
* **incorrect_module_name_qmldir**: generate .qmlproject based on qmldir (failure - module name is wrong)
|
||||||
|
* **invalid_qmlproject**: read and process invalid .qmlproject module
|
||||||
|
* **missing_module_name_qmldir**: generate .qmlproject based on qmldir (failure - missing module name)
|
||||||
|
* **missing_qml_files_qmldir**: generate .qmlproject based on qmldir (failure - missing qml files)
|
||||||
|
* **missing_qmlproject**: generate .qmlproject based on qmldir (success)
|
||||||
|
@@ -0,0 +1,5 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,6 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
# test comment
|
||||||
|
module test.module
|
||||||
|
singleton TestSingleton 1.0 TestSingleton.qml
|
@@ -0,0 +1,16 @@
|
|||||||
|
import QmlProject 1.3
|
||||||
|
|
||||||
|
Project {
|
||||||
|
MCU.Module {
|
||||||
|
uri: "test.module"
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlFiles {
|
||||||
|
files: [
|
||||||
|
"TestSingleton.qml",
|
||||||
|
"File1.qml",
|
||||||
|
"File2.qml",
|
||||||
|
"Internal/File3.qml"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,6 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
# test comment
|
||||||
|
module test module
|
||||||
|
singleton TestSingleton 1.0 TestSingleton.qml
|
@@ -0,0 +1,5 @@
|
|||||||
|
import QmlProject 1.3
|
||||||
|
|
||||||
|
Project {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,6 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,2 @@
|
|||||||
|
# test comment
|
||||||
|
singleton TestSingleton 1.0 TestSingleton.qml
|
@@ -0,0 +1,2 @@
|
|||||||
|
# test comment
|
||||||
|
module test.module
|
@@ -0,0 +1,5 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,6 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
# test comment
|
||||||
|
module test.module
|
||||||
|
singleton TestSingleton 1.0 TestSingleton.qml
|
@@ -0,0 +1,368 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "../utils/googletest.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
#include <qmlprojectmanager/qmldirtoqmlproject/mcumoduleprojectitem.h>
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr QLatin1String localTestDataDir{UNITTEST_DIR "/qmlprojectmanager/data"};
|
||||||
|
|
||||||
|
constexpr QLatin1String jsonProject{R"(
|
||||||
|
{
|
||||||
|
"moduleUri": "test.module",
|
||||||
|
"qmlFiles": [
|
||||||
|
"TestSingleton.qml",
|
||||||
|
"File1.qml",
|
||||||
|
"File2.qml",
|
||||||
|
"Internal/File3.qml"
|
||||||
|
],
|
||||||
|
"qmlProjectPath": "%1"
|
||||||
|
}
|
||||||
|
)"};
|
||||||
|
|
||||||
|
class McuModuleProjectItem : public testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
static void SetUpTestSuite()
|
||||||
|
{
|
||||||
|
existingQmlProject = std::make_unique<const QmlProjectManager::McuModuleProjectItem>(
|
||||||
|
Utils::FilePath::fromString(
|
||||||
|
localTestDataDir + "/qmldirtoqmlproject/existing_qmlproject/test_module.qmlproject"));
|
||||||
|
|
||||||
|
auto fromQmldir = QmlProjectManager::McuModuleProjectItem::fromQmldirModule(
|
||||||
|
Utils::FilePath::fromString(localTestDataDir
|
||||||
|
+ "/qmldirtoqmlproject/missing_qmlproject/qmldir"));
|
||||||
|
missingQmlProject = std::make_unique<const QmlProjectManager::McuModuleProjectItem>(
|
||||||
|
fromQmldir ? *fromQmldir : QmlProjectManager::McuModuleProjectItem{QJsonObject{}});
|
||||||
|
|
||||||
|
invalidQmlProject = std::make_unique<const QmlProjectManager::McuModuleProjectItem>(
|
||||||
|
Utils::FilePath::fromString(
|
||||||
|
localTestDataDir + "/qmldirtoqmlproject/invalid_qmlproject/test_module.qmlproject"));
|
||||||
|
|
||||||
|
fromJsonObject = std::make_unique<const QmlProjectManager::McuModuleProjectItem>(
|
||||||
|
QJsonDocument::fromJson(
|
||||||
|
jsonProject.arg(localTestDataDir + "/qmldirtoqmlproject/test_module.qmlproject").toUtf8())
|
||||||
|
.object());
|
||||||
|
|
||||||
|
fromIncompleteJsonObject = std::make_unique<const QmlProjectManager::McuModuleProjectItem>(
|
||||||
|
QJsonDocument::fromJson(jsonProject.toString().toUtf8()).object());
|
||||||
|
|
||||||
|
createFromEmpty = std::make_unique<QmlProjectManager::McuModuleProjectItem>(QJsonObject{});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TearDownTestSuite()
|
||||||
|
{
|
||||||
|
existingQmlProject.reset();
|
||||||
|
missingQmlProject->qmlProjectPath().removeFile();
|
||||||
|
missingQmlProject.reset();
|
||||||
|
invalidQmlProject.reset();
|
||||||
|
fromJsonObject.reset();
|
||||||
|
fromIncompleteJsonObject.reset();
|
||||||
|
createFromEmpty->qmlProjectPath().removeFile();
|
||||||
|
createFromEmpty.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
inline static std::unique_ptr<const QmlProjectManager::McuModuleProjectItem> existingQmlProject;
|
||||||
|
inline static std::unique_ptr<const QmlProjectManager::McuModuleProjectItem> missingQmlProject;
|
||||||
|
inline static std::unique_ptr<const QmlProjectManager::McuModuleProjectItem> invalidQmlProject;
|
||||||
|
inline static std::unique_ptr<const QmlProjectManager::McuModuleProjectItem> fromJsonObject;
|
||||||
|
inline static std::unique_ptr<const QmlProjectManager::McuModuleProjectItem> fromIncompleteJsonObject;
|
||||||
|
inline static std::unique_ptr<QmlProjectManager::McuModuleProjectItem> createFromEmpty;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, is_valid_existing_qmlproject)
|
||||||
|
{
|
||||||
|
auto isValid = existingQmlProject->isValid();
|
||||||
|
|
||||||
|
ASSERT_TRUE(isValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_uri_existing_qmlproject)
|
||||||
|
{
|
||||||
|
auto uri = existingQmlProject->uri();
|
||||||
|
|
||||||
|
ASSERT_THAT(uri, Eq("test.module"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_qml_files_existing_qmlproject)
|
||||||
|
{
|
||||||
|
auto files = existingQmlProject->qmlFiles();
|
||||||
|
|
||||||
|
ASSERT_THAT(files,
|
||||||
|
UnorderedElementsAre("Internal/File3.qml", "File2.qml", "File1.qml", "TestSingleton.qml"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_qmlproject_path_existing_qmlproject)
|
||||||
|
{
|
||||||
|
auto path = existingQmlProject->qmlProjectPath();
|
||||||
|
auto expectedPath = Utils::FilePath::fromString(
|
||||||
|
localTestDataDir + "/qmldirtoqmlproject/existing_qmlproject/test_module.qmlproject");
|
||||||
|
|
||||||
|
ASSERT_THAT(path, Eq(expectedPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_project_existing_qmlproject)
|
||||||
|
{
|
||||||
|
auto project = existingQmlProject->project();
|
||||||
|
auto expectedJsonProject = QJsonDocument::fromJson(
|
||||||
|
jsonProject
|
||||||
|
.arg(localTestDataDir + "/qmldirtoqmlproject/existing_qmlproject/test_module.qmlproject")
|
||||||
|
.toUtf8())
|
||||||
|
.object();
|
||||||
|
|
||||||
|
ASSERT_THAT(project, Eq(expectedJsonProject));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, save_qmlproject_file_existing_qmlproject)
|
||||||
|
{
|
||||||
|
bool saved = existingQmlProject->saveQmlProjectFile();
|
||||||
|
|
||||||
|
ASSERT_FALSE(saved);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, is_valid_missing_qmlproject)
|
||||||
|
{
|
||||||
|
auto isValid = missingQmlProject->isValid();
|
||||||
|
|
||||||
|
ASSERT_TRUE(isValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_uri_missing_qmlproject)
|
||||||
|
{
|
||||||
|
auto uri = missingQmlProject->uri();
|
||||||
|
|
||||||
|
ASSERT_THAT(uri, Eq("test.module"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_qml_files_missing_qmlproject)
|
||||||
|
{
|
||||||
|
auto files = missingQmlProject->qmlFiles();
|
||||||
|
|
||||||
|
ASSERT_THAT(files,
|
||||||
|
UnorderedElementsAre("Internal/File3.qml", "File2.qml", "File1.qml", "TestSingleton.qml"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_qmlproject_path_missing_qmlproject)
|
||||||
|
{
|
||||||
|
auto path = missingQmlProject->qmlProjectPath();
|
||||||
|
auto expectedPath = Utils::FilePath::fromString(
|
||||||
|
localTestDataDir + "/qmldirtoqmlproject/missing_qmlproject/test_module.qmlproject");
|
||||||
|
|
||||||
|
ASSERT_THAT(path, Eq(expectedPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, check_saved_qmlproject_file_missing_qmlproject)
|
||||||
|
{
|
||||||
|
auto projectPath = Utils::FilePath::fromString(
|
||||||
|
localTestDataDir + "/qmldirtoqmlproject/missing_qmlproject/test_module.qmlproject");
|
||||||
|
missingQmlProject->saveQmlProjectFile();
|
||||||
|
|
||||||
|
QmlProjectManager::McuModuleProjectItem savedQmlProject(projectPath);
|
||||||
|
|
||||||
|
ASSERT_THAT(*missingQmlProject, Eq(savedQmlProject));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, is_valid_invalid_qmlproject)
|
||||||
|
{
|
||||||
|
auto isValid = invalidQmlProject->isValid();
|
||||||
|
|
||||||
|
ASSERT_FALSE(isValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_uri_invalid_qmlproject)
|
||||||
|
{
|
||||||
|
auto uri = invalidQmlProject->uri();
|
||||||
|
|
||||||
|
ASSERT_THAT(uri, IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_qml_files_invalid_qmlproject)
|
||||||
|
{
|
||||||
|
auto files = invalidQmlProject->qmlFiles();
|
||||||
|
|
||||||
|
ASSERT_THAT(files, IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_qmlproject_path_invalid_qmlproject)
|
||||||
|
{
|
||||||
|
auto path = invalidQmlProject->qmlProjectPath();
|
||||||
|
auto expectedPath = Utils::FilePath::fromString(
|
||||||
|
localTestDataDir + "/qmldirtoqmlproject/invalid_qmlproject/test_module.qmlproject");
|
||||||
|
|
||||||
|
ASSERT_THAT(path, Eq(expectedPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, save_qmlproject_file_invalid_qmlproject)
|
||||||
|
{
|
||||||
|
bool saved = invalidQmlProject->saveQmlProjectFile();
|
||||||
|
|
||||||
|
ASSERT_FALSE(saved);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, is_valid_from_json_object)
|
||||||
|
{
|
||||||
|
auto isValid = fromJsonObject->isValid();
|
||||||
|
|
||||||
|
ASSERT_TRUE(isValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_uri_from_json_object)
|
||||||
|
{
|
||||||
|
auto uri = fromJsonObject->uri();
|
||||||
|
|
||||||
|
ASSERT_THAT(uri, Eq("test.module"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_qml_files_from_json_object)
|
||||||
|
{
|
||||||
|
auto files = fromJsonObject->qmlFiles();
|
||||||
|
|
||||||
|
ASSERT_THAT(files,
|
||||||
|
UnorderedElementsAre("Internal/File3.qml", "File2.qml", "File1.qml", "TestSingleton.qml"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_qmlproject_path_from_json_object)
|
||||||
|
{
|
||||||
|
auto path = fromJsonObject->qmlProjectPath();
|
||||||
|
auto expectedPath = Utils::FilePath::fromString(localTestDataDir
|
||||||
|
+ "/qmldirtoqmlproject/test_module.qmlproject");
|
||||||
|
|
||||||
|
ASSERT_THAT(path, Eq(expectedPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_project_from_json_object)
|
||||||
|
{
|
||||||
|
auto project = fromJsonObject->project();
|
||||||
|
auto expectedJsonProject = QJsonDocument::fromJson(
|
||||||
|
jsonProject
|
||||||
|
.arg(localTestDataDir
|
||||||
|
+ "/qmldirtoqmlproject/test_module.qmlproject")
|
||||||
|
.toUtf8())
|
||||||
|
.object();
|
||||||
|
|
||||||
|
ASSERT_THAT(project, Eq(expectedJsonProject));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, is_valid_from_incomplete_json_object)
|
||||||
|
{
|
||||||
|
auto isValid = fromIncompleteJsonObject->isValid();
|
||||||
|
|
||||||
|
ASSERT_FALSE(isValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_uri_from_incomplete_json_object)
|
||||||
|
{
|
||||||
|
auto uri = fromIncompleteJsonObject->uri();
|
||||||
|
|
||||||
|
ASSERT_THAT(uri, Eq("test.module"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_qml_files_from_incomplete_json_object)
|
||||||
|
{
|
||||||
|
auto files = fromIncompleteJsonObject->qmlFiles();
|
||||||
|
|
||||||
|
ASSERT_THAT(files,
|
||||||
|
UnorderedElementsAre("Internal/File3.qml", "File2.qml", "File1.qml", "TestSingleton.qml"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, get_qmlproject_path_from_incomplete_json_object)
|
||||||
|
{
|
||||||
|
auto path = fromIncompleteJsonObject->qmlProjectPath();
|
||||||
|
|
||||||
|
ASSERT_FALSE(path.endsWith(".qmlproject"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, save_qmlproject_from_incomplete_json_object)
|
||||||
|
{
|
||||||
|
bool saved = fromIncompleteJsonObject->saveQmlProjectFile();
|
||||||
|
|
||||||
|
ASSERT_FALSE(saved);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, set_uri_create_from_empty)
|
||||||
|
{
|
||||||
|
createFromEmpty->setUri("test.module");
|
||||||
|
|
||||||
|
ASSERT_THAT(createFromEmpty->uri(), Eq("test.module"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, set_qml_files_create_from_empty)
|
||||||
|
{
|
||||||
|
createFromEmpty->setQmlFiles({"File1.qml", "File2.qml"});
|
||||||
|
|
||||||
|
ASSERT_THAT(createFromEmpty->qmlFiles(), UnorderedElementsAre("File1.qml", "File2.qml"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, set_qmlproject_path_create_from_empty)
|
||||||
|
{
|
||||||
|
auto projectPath = Utils::FilePath::fromString(localTestDataDir
|
||||||
|
+ "/qmldirtoqmlproject/test_module.qmlproject");
|
||||||
|
|
||||||
|
createFromEmpty->setQmlProjectPath(projectPath);
|
||||||
|
|
||||||
|
ASSERT_THAT(createFromEmpty->qmlProjectPath(), Eq(projectPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, is_valid_create_from_empty)
|
||||||
|
{
|
||||||
|
bool isValid = createFromEmpty->isValid();
|
||||||
|
|
||||||
|
ASSERT_TRUE(isValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, check_saved_qmlproject_create_from_empty)
|
||||||
|
{
|
||||||
|
auto projectPath = Utils::FilePath::fromString(localTestDataDir
|
||||||
|
+ "/qmldirtoqmlproject/test_module.qmlproject");
|
||||||
|
createFromEmpty->saveQmlProjectFile();
|
||||||
|
|
||||||
|
QmlProjectManager::McuModuleProjectItem savedQmlProject(projectPath);
|
||||||
|
|
||||||
|
ASSERT_THAT(*createFromEmpty, Eq(savedQmlProject));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, create_from_nonexisting_file)
|
||||||
|
{
|
||||||
|
auto projectPath = Utils::FilePath::fromString(localTestDataDir
|
||||||
|
+ "/qmldirtoqmlproject/nonexisting");
|
||||||
|
|
||||||
|
auto projectItem = QmlProjectManager::McuModuleProjectItem::fromQmldirModule(projectPath);
|
||||||
|
|
||||||
|
ASSERT_FALSE(projectItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, create_from_missing_module_name_qmldir)
|
||||||
|
{
|
||||||
|
auto projectPath = Utils::FilePath::fromString(
|
||||||
|
localTestDataDir + "/qmldirtoqmlproject/missing_module_name_qmldir/qmldir");
|
||||||
|
|
||||||
|
auto projectItem = QmlProjectManager::McuModuleProjectItem::fromQmldirModule(projectPath);
|
||||||
|
|
||||||
|
ASSERT_FALSE(projectItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, create_from_incorrect_module_name_qmldir)
|
||||||
|
{
|
||||||
|
auto projectPath = Utils::FilePath::fromString(
|
||||||
|
localTestDataDir + "/qmldirtoqmlproject/incorrect_module_name_qmldir/qmldir");
|
||||||
|
|
||||||
|
auto projectItem = QmlProjectManager::McuModuleProjectItem::fromQmldirModule(projectPath);
|
||||||
|
|
||||||
|
ASSERT_FALSE(projectItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(McuModuleProjectItem, create_from_missing_qml_files_qmldir)
|
||||||
|
{
|
||||||
|
auto projectPath = Utils::FilePath::fromString(
|
||||||
|
localTestDataDir + "/qmldirtoqmlproject/missing_qml_files_qmldir/qmldir");
|
||||||
|
|
||||||
|
auto projectItem = QmlProjectManager::McuModuleProjectItem::fromQmldirModule(projectPath);
|
||||||
|
|
||||||
|
ASSERT_FALSE(projectItem);
|
||||||
|
}
|
Reference in New Issue
Block a user