From 3e8bcc1cf6f3400fff9aa361ddc109bafe16d646 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 15 Dec 2013 12:18:42 +0100 Subject: Unit tests for the DownloadUpdateTask class --- tests/tst_DownloadUpdateTask.cpp | 136 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 tests/tst_DownloadUpdateTask.cpp (limited to 'tests/tst_DownloadUpdateTask.cpp') diff --git a/tests/tst_DownloadUpdateTask.cpp b/tests/tst_DownloadUpdateTask.cpp new file mode 100644 index 00000000..69391466 --- /dev/null +++ b/tests/tst_DownloadUpdateTask.cpp @@ -0,0 +1,136 @@ +#include +#include + +#include "TestUtil.h" + +#include "logic/updater/DownloadUpdateTask.h" +#include "logic/updater/UpdateChecker.h" + +Q_DECLARE_METATYPE(DownloadUpdateTask::VersionFileList) + +bool operator==(const DownloadUpdateTask::FileSource &f1, const DownloadUpdateTask::FileSource &f2) +{ + return f1.type == f2.type && + f1.url == f2.url && + f1.compressionType == f2.compressionType; +} +bool operator==(const DownloadUpdateTask::VersionFileEntry &v1, const DownloadUpdateTask::VersionFileEntry &v2) +{ + return v1.path == v2.path && + v1.mode == v2.mode && + v1.sources == v2.sources && + v1.md5 == v2.md5; +} + +QDebug operator<<(QDebug dbg, const DownloadUpdateTask::FileSource &f) +{ + dbg.nospace() << "FileSource(type=" << f.type << " url=" << f.url << " comp=" << f.compressionType << ")"; + return dbg.maybeSpace(); +} +QDebug operator<<(QDebug dbg, const DownloadUpdateTask::VersionFileEntry &v) +{ + dbg.nospace() << "VersionFileEntry(path=" << v.path << " mode=" << v.mode << " md5=" << v.md5 << " sources=" << v.sources << ")"; + return dbg.maybeSpace(); +} + +class DownloadUpdateTaskTest : public QObject +{ + Q_OBJECT +private +slots: + void initTestCase() + { + + } + void cleanupTestCase() + { + + } + + void test_writeInstallScript() + { + DownloadUpdateTask task(QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/")).toString(), 0); + + DownloadUpdateTask::UpdateOperationList ops; + + ops << DownloadUpdateTask::UpdateOperation::CopyOp("sourceOne", "destOne", 0777) + << DownloadUpdateTask::UpdateOperation::CopyOp("MultiMC.exe", "M/u/l/t/i/M/C/e/x/e") + << DownloadUpdateTask::UpdateOperation::DeleteOp("toDelete.abc"); + + const QString script = QDir::temp().absoluteFilePath("MultiMCUpdateScript.xml"); + QVERIFY(task.writeInstallScript(ops, script)); + QCOMPARE(TestsInternal::readFileUtf8(script), MULTIMC_GET_TEST_FILE_UTF8("tests/data/tst_DownloadUpdateTask-test_writeInstallScript.xml")); + } + + void test_parseVersionInfo_data() + { + QTest::addColumn("data"); + QTest::addColumn("list"); + QTest::addColumn("error"); + QTest::addColumn("ret"); + + QTest::newRow("one") << MULTIMC_GET_TEST_FILE("tests/data/1.json") + << (DownloadUpdateTask::VersionFileList() + << DownloadUpdateTask::VersionFileEntry{"fileOne", 493, + (DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileOneA")), + "9eb84090956c484e32cb6c08455a667b"} + << DownloadUpdateTask::VersionFileEntry{"fileTwo", 644, + (DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileTwo")), + "38f94f54fa3eb72b0ea836538c10b043"} + << DownloadUpdateTask::VersionFileEntry{"fileThree", 750, + (DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileThree")), + "f12df554b21e320be6471d7154130e70"}) + << QString() + << true; + QTest::newRow("two") << MULTIMC_GET_TEST_FILE("tests/data/2.json") + << (DownloadUpdateTask::VersionFileList() + << DownloadUpdateTask::VersionFileEntry{"fileOne", 493, + (DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileOneB")), + "42915a71277c9016668cce7b82c6b577"} + << DownloadUpdateTask::VersionFileEntry{"fileTwo", 644, + (DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileTwo")), + "38f94f54fa3eb72b0ea836538c10b043"}) + << QString() + << true; + } + void test_parseVersionInfo() + { + QFETCH(QByteArray, data); + QFETCH(DownloadUpdateTask::VersionFileList, list); + QFETCH(QString, error); + QFETCH(bool, ret); + + DownloadUpdateTask::VersionFileList outList; + QString outError; + bool outRet = DownloadUpdateTask("", 0).parseVersionInfo(data, &outList, &outError); + QCOMPARE(outRet, ret); + QCOMPARE(outList, list); + QCOMPARE(outError, error); + } + + void test_processFileLists() + { + // TODO create unit test for this + } + + void test_masterTest() + { + QLOG_INFO() << "#####################"; + MMC->m_version.build = 1; + MMC->m_version.channel = "develop"; + MMC->updateChecker()->setChannelListUrl(QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/channels.json")).toString()); + MMC->updateChecker()->setCurrentChannel("develop"); + + DownloadUpdateTask task(QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/")).toString(), 2); + + QSignalSpy succeededSpy(&task, SIGNAL(succeeded())); + + task.start(); + + QVERIFY(succeededSpy.wait()); + } +}; + +QTEST_GUILESS_MAIN_MULTIMC(DownloadUpdateTaskTest) + +#include "tst_DownloadUpdateTask.moc" -- cgit From 7f884a18a85eca8c1a395ab0e9d421f17a98f142 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 15 Dec 2013 18:50:56 +0100 Subject: Finish unit tests for the DownloadUpdateTask class --- logic/updater/DownloadUpdateTask.cpp | 60 ++++++++++++++++++-------------- logic/updater/DownloadUpdateTask.h | 18 +++++----- tests/tst_DownloadUpdateTask.cpp | 66 +++++++++++++++++++++++++++++++++++- 3 files changed, 109 insertions(+), 35 deletions(-) (limited to 'tests/tst_DownloadUpdateTask.cpp') diff --git a/logic/updater/DownloadUpdateTask.cpp b/logic/updater/DownloadUpdateTask.cpp index ed5bfd02..d72cfcf6 100644 --- a/logic/updater/DownloadUpdateTask.cpp +++ b/logic/updater/DownloadUpdateTask.cpp @@ -234,15 +234,36 @@ bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileLis } void DownloadUpdateTask::processFileLists() +{ + // Create a network job for downloading files. + NetJob* netJob = new NetJob("Update Files"); + + processFileLists(netJob, m_cVersionFileList, m_nVersionFileList, m_operationList); + + // Add listeners to wait for the downloads to finish. + QObject::connect(netJob, &NetJob::succeeded, this, &DownloadUpdateTask::fileDownloadFinished); + QObject::connect(netJob, &NetJob::progress, this, &DownloadUpdateTask::fileDownloadProgressChanged); + QObject::connect(netJob, &NetJob::failed, this, &DownloadUpdateTask::fileDownloadFailed); + + // Now start the download. + setStatus(tr("Downloading %1 update files.").arg(QString::number(netJob->size()))); + QLOG_DEBUG() << "Begin downloading update files to" << m_updateFilesDir.path(); + m_filesNetJob.reset(netJob); + netJob->start(); + + writeInstallScript(m_operationList, PathCombine(m_updateFilesDir.path(), "file_list.xml")); +} + +void DownloadUpdateTask::processFileLists(NetJob *job, const VersionFileList ¤tVersion, const VersionFileList &newVersion, DownloadUpdateTask::UpdateOperationList &ops) { setStatus(tr("Processing file lists. Figuring out how to install the update.")); // First, if we've loaded the current version's file list, we need to iterate through it and // delete anything in the current one version's list that isn't in the new version's list. - for (VersionFileEntry entry : m_cVersionFileList) + for (VersionFileEntry entry : currentVersion) { bool keep = false; - for (VersionFileEntry newEntry : m_nVersionFileList) + for (VersionFileEntry newEntry : newVersion) { if (newEntry.path == entry.path) { @@ -253,14 +274,11 @@ void DownloadUpdateTask::processFileLists() } // If the loop reaches the end and we didn't find a match, delete the file. if(!keep) - m_operationList.append(UpdateOperation::DeleteOp(entry.path)); + ops.append(UpdateOperation::DeleteOp(entry.path)); } - // Create a network job for downloading files. - NetJob* netJob = new NetJob("Update Files"); - // Next, check each file in MultiMC's folder and see if we need to update them. - for (VersionFileEntry entry : m_nVersionFileList) + for (VersionFileEntry entry : newVersion) { // TODO: Let's not MD5sum a ton of files on the GUI thread. We should probably find a way to do this in the background. QString fileMD5; @@ -287,31 +305,21 @@ void DownloadUpdateTask::processFileLists() // Download it to updatedir/- where filepath is the file's path with slashes replaced by underscores. QString dlPath = PathCombine(m_updateFilesDir.path(), QString(entry.path).replace("/", "_")); - // We need to download the file to the updatefiles folder and add a task to copy it to its install path. - auto download = MD5EtagDownload::make(source.url, dlPath); - download->m_check_md5 = true; - download->m_expected_md5 = entry.md5; - netJob->addNetAction(download); + if (job) + { + // We need to download the file to the updatefiles folder and add a task to copy it to its install path. + auto download = MD5EtagDownload::make(source.url, dlPath); + download->m_check_md5 = true; + download->m_expected_md5 = entry.md5; + job->addNetAction(download); + } // Now add a copy operation to our operations list to install the file. - m_operationList.append(UpdateOperation::CopyOp(dlPath, entry.path, entry.mode)); + ops.append(UpdateOperation::CopyOp(dlPath, entry.path, entry.mode)); } } } } - - // Add listeners to wait for the downloads to finish. - QObject::connect(netJob, &NetJob::succeeded, this, &DownloadUpdateTask::fileDownloadFinished); - QObject::connect(netJob, &NetJob::progress, this, &DownloadUpdateTask::fileDownloadProgressChanged); - QObject::connect(netJob, &NetJob::failed, this, &DownloadUpdateTask::fileDownloadFailed); - - // Now start the download. - setStatus(tr("Downloading %1 update files.").arg(QString::number(netJob->size()))); - QLOG_DEBUG() << "Begin downloading update files to" << m_updateFilesDir.path(); - m_filesNetJob.reset(netJob); - netJob->start(); - - writeInstallScript(m_operationList, PathCombine(m_updateFilesDir.path(), "file_list.xml")); } bool DownloadUpdateTask::writeInstallScript(UpdateOperationList& opsList, QString scriptFile) diff --git a/logic/updater/DownloadUpdateTask.h b/logic/updater/DownloadUpdateTask.h index 1d1fc7bf..8530be77 100644 --- a/logic/updater/DownloadUpdateTask.h +++ b/logic/updater/DownloadUpdateTask.h @@ -54,13 +54,11 @@ public: QString url; QString compressionType; }; - typedef QList FileSourceList; /*! * Structure that describes an entry in a GoUpdate version's `Files` list. */ - struct VersionFileEntry { QString path; @@ -68,12 +66,8 @@ public: FileSourceList sources; QString md5; }; - typedef QList VersionFileList; -protected: - friend class DownloadUpdateTaskTest; - /*! * Structure that describes an operation to perform when installing updates. */ @@ -104,9 +98,12 @@ protected: // Yeah yeah, polymorphism blah blah inheritance, blah blah object oriented. I'm lazy, OK? }; - typedef QList UpdateOperationList; +protected: + friend class DownloadUpdateTaskTest; + + /*! * Used for arguments to parseVersionInfo and friends to specify which version info file to parse. */ @@ -159,6 +156,12 @@ protected: * Takes a list of file entries for the current version's files and the new version's files * and populates the downloadList and operationList with information about how to download and install the update. */ + virtual void processFileLists(NetJob *job, const VersionFileList ¤tVersion, const VersionFileList &newVersion, UpdateOperationList &ops); + + /*! + * Calls \see processFileLists to populate the \see m_operationList and a NetJob, and then executes + * the NetJob to fetch all needed files + */ virtual void processFileLists(); /*! @@ -166,7 +169,6 @@ protected: */ virtual bool writeInstallScript(UpdateOperationList& opsList, QString scriptFile); - VersionFileList m_downloadList; UpdateOperationList m_operationList; VersionFileList m_nVersionFileList; diff --git a/tests/tst_DownloadUpdateTask.cpp b/tests/tst_DownloadUpdateTask.cpp index 69391466..d96e4cf1 100644 --- a/tests/tst_DownloadUpdateTask.cpp +++ b/tests/tst_DownloadUpdateTask.cpp @@ -5,8 +5,10 @@ #include "logic/updater/DownloadUpdateTask.h" #include "logic/updater/UpdateChecker.h" +#include "depends/util/include/pathutils.h" Q_DECLARE_METATYPE(DownloadUpdateTask::VersionFileList) +Q_DECLARE_METATYPE(DownloadUpdateTask::UpdateOperation) bool operator==(const DownloadUpdateTask::FileSource &f1, const DownloadUpdateTask::FileSource &f2) { @@ -21,6 +23,13 @@ bool operator==(const DownloadUpdateTask::VersionFileEntry &v1, const DownloadUp v1.sources == v2.sources && v1.md5 == v2.md5; } +bool operator==(const DownloadUpdateTask::UpdateOperation &u1, const DownloadUpdateTask::UpdateOperation &u2) +{ + return u1.type == u2.type && + u1.file == u2.file && + u1.dest == u2.dest && + u1.mode == u2.mode; +} QDebug operator<<(QDebug dbg, const DownloadUpdateTask::FileSource &f) { @@ -32,6 +41,22 @@ QDebug operator<<(QDebug dbg, const DownloadUpdateTask::VersionFileEntry &v) dbg.nospace() << "VersionFileEntry(path=" << v.path << " mode=" << v.mode << " md5=" << v.md5 << " sources=" << v.sources << ")"; return dbg.maybeSpace(); } +QDebug operator<<(QDebug dbg, const DownloadUpdateTask::UpdateOperation::Type &t) +{ + switch (t) + { + case DownloadUpdateTask::UpdateOperation::OP_COPY: dbg << "OP_COPY"; break; + case DownloadUpdateTask::UpdateOperation::OP_DELETE: dbg << "OP_DELETE"; break; + case DownloadUpdateTask::UpdateOperation::OP_MOVE: dbg << "OP_MOVE"; break; + case DownloadUpdateTask::UpdateOperation::OP_CHMOD: dbg << "OP_CHMOD"; break; + } + return dbg.maybeSpace(); +} +QDebug operator<<(QDebug dbg, const DownloadUpdateTask::UpdateOperation &u) +{ + dbg.nospace() << "UpdateOperation(type=" << u.type << " file=" << u.file << " dest=" << u.dest << " mode=" << u.mode << ")"; + return dbg.maybeSpace(); +} class DownloadUpdateTaskTest : public QObject { @@ -108,9 +133,48 @@ slots: QCOMPARE(outError, error); } + void test_processFileLists_data() + { + QTest::addColumn("downloader"); + QTest::addColumn("currentVersion"); + QTest::addColumn("newVersion"); + QTest::addColumn("expectedOperations"); + + DownloadUpdateTask *downloader = new DownloadUpdateTask(QString(), -1); + + // update fileOne, keep fileTwo, remove fileThree + QTest::newRow("test 1") << downloader + << (DownloadUpdateTask::VersionFileList() + << DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileOne"), 493, DownloadUpdateTask::FileSourceList() + << DownloadUpdateTask::FileSource("http", "http://host/path/fileOne-1"), "9eb84090956c484e32cb6c08455a667b"} + << DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileTwo"), 644, DownloadUpdateTask::FileSourceList() + << DownloadUpdateTask::FileSource("http", "http://host/path/fileTwo-1"), "38f94f54fa3eb72b0ea836538c10b043"} + << DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileThree"), 420, DownloadUpdateTask::FileSourceList() + << DownloadUpdateTask::FileSource("http", "http://host/path/fileThree-1"), "f12df554b21e320be6471d7154130e70"}) + << (DownloadUpdateTask::VersionFileList() + << DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileOne"), 493, DownloadUpdateTask::FileSourceList() + << DownloadUpdateTask::FileSource("http", "http://host/path/fileOne-2"), "42915a71277c9016668cce7b82c6b577"} + << DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileTwo"), 644, DownloadUpdateTask::FileSourceList() + << DownloadUpdateTask::FileSource("http", "http://host/path/fileTwo-2"), "38f94f54fa3eb72b0ea836538c10b043"}) + << (DownloadUpdateTask::UpdateOperationList() + << DownloadUpdateTask::UpdateOperation::DeleteOp(QFINDTESTDATA("tests/data/fileThree")) + << DownloadUpdateTask::UpdateOperation::CopyOp(PathCombine(downloader->updateFilesDir(), QFINDTESTDATA("tests/data/fileOne").replace("/", "_")), + QFINDTESTDATA("tests/data/fileOne"), 493)); + } void test_processFileLists() { - // TODO create unit test for this + QFETCH(DownloadUpdateTask *, downloader); + QFETCH(DownloadUpdateTask::VersionFileList, currentVersion); + QFETCH(DownloadUpdateTask::VersionFileList, newVersion); + QFETCH(DownloadUpdateTask::UpdateOperationList, expectedOperations); + + DownloadUpdateTask::UpdateOperationList operations; + + downloader->processFileLists(new NetJob("Dummy"), currentVersion, newVersion, operations); + qDebug() << (operations == expectedOperations); + qDebug() << operations; + qDebug() << expectedOperations; + QCOMPARE(operations, expectedOperations); } void test_masterTest() -- cgit From d6c71488b34a2854461feee3296c11568542ecbe Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Tue, 17 Dec 2013 02:09:58 +0100 Subject: Some test madness --- CMakeLists.txt | 9 +- MultiMC.cpp | 2 +- depends/util/src/pathutils.cpp | 5 +- logger/QsLogDest.cpp | 14 ++ logger/QsLogDest.h | 1 + logic/net/ForgeXzDownload.cpp | 5 +- logic/updater/DownloadUpdateTask.cpp | 279 ++++++++++++++------- logic/updater/DownloadUpdateTask.h | 5 +- tests/CMakeLists.txt | 10 +- tests/TestUtil.h | 3 + tests/data/.gitattributes | 2 + tests/data/1.json | 6 +- tests/data/2.json | 4 +- tests/data/CMakeLists.txt | 4 - tests/data/channels.json | 2 +- ...oadUpdateTask-test_writeInstallScript_win32.xml | 17 ++ tests/test.manifest | 27 ++ tests/test.rc | 28 +++ tests/tst_DownloadUpdateTask.cpp | 194 +++++++++----- tests/tst_UpdateChecker.cpp | 2 +- tests/tst_pathutils.cpp | 32 ++- tests/tst_userutils.cpp | 7 +- 22 files changed, 457 insertions(+), 201 deletions(-) create mode 100644 tests/data/.gitattributes delete mode 100644 tests/data/CMakeLists.txt create mode 100644 tests/data/tst_DownloadUpdateTask-test_writeInstallScript_win32.xml create mode 100644 tests/test.manifest create mode 100644 tests/test.rc (limited to 'tests/tst_DownloadUpdateTask.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 33f74a8a..17674513 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,11 +43,18 @@ ENDIF() ######## 3rd Party Libs ######## # Find the required Qt parts +find_package(Qt5Core REQUIRED) find_package(Qt5Widgets REQUIRED) find_package(Qt5Network REQUIRED) +find_package(Qt5Test REQUIRED) find_package(Qt5LinguistTools REQUIRED) -include_directories(${Qt5Widgets_INCLUDE_DIRS}) +include_directories( + ${Qt5Core_INCLUDE_DIRS} + ${Qt5Widgets_INCLUDE_DIRS} + ${Qt5Network_INCLUDE_DIRS} + ${Qt5Test_INCLUDE_DIRS} + ) # The Qt5 cmake files don't provide its install paths, so ask qmake. get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION) diff --git a/MultiMC.cpp b/MultiMC.cpp index 65c24087..71a8fe59 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -286,7 +286,7 @@ void MultiMC::initLogger() QsLogging::Logger &logger = QsLogging::Logger::instance(); logger.setLoggingLevel(QsLogging::TraceLevel); m_fileDestination = QsLogging::DestinationFactory::MakeFileDestination("MultiMC.log"); - m_debugDestination = QsLogging::DestinationFactory::MakeDebugOutputDestination(); + m_debugDestination = QsLogging::DestinationFactory::MakeQDebugDestination(); logger.addDestination(m_fileDestination.get()); logger.addDestination(m_debugDestination.get()); // log all the things diff --git a/depends/util/src/pathutils.cpp b/depends/util/src/pathutils.cpp index 485d03e8..20888754 100644 --- a/depends/util/src/pathutils.cpp +++ b/depends/util/src/pathutils.cpp @@ -23,10 +23,7 @@ QString PathCombine(QString path1, QString path2) { - if (!path1.endsWith('/')) - return path1.append('/').append(path2); - else - return path1.append(path2); + return QDir::cleanPath(path1 + QDir::separator() + path2); } QString PathCombine(QString path1, QString path2, QString path3) diff --git a/logger/QsLogDest.cpp b/logger/QsLogDest.cpp index 2fd29b23..4a47060e 100644 --- a/logger/QsLogDest.cpp +++ b/logger/QsLogDest.cpp @@ -77,6 +77,15 @@ void DebugOutputDestination::write(const QString &message) QsDebugOutput::output(message); } +class QDebugDestination : public Destination +{ +public: + virtual void write(const QString &message) + { + qDebug() << message; + }; +}; + DestinationPtr DestinationFactory::MakeFileDestination(const QString &filePath) { return DestinationPtr(new FileDestination(filePath)); @@ -87,4 +96,9 @@ DestinationPtr DestinationFactory::MakeDebugOutputDestination() return DestinationPtr(new DebugOutputDestination); } +DestinationPtr DestinationFactory::MakeQDebugDestination() +{ + return DestinationPtr(new QDebugDestination); +} + } // end namespace diff --git a/logger/QsLogDest.h b/logger/QsLogDest.h index e7fcc045..a8000022 100644 --- a/logger/QsLogDest.h +++ b/logger/QsLogDest.h @@ -47,6 +47,7 @@ class DestinationFactory public: static DestinationPtr MakeFileDestination(const QString &filePath); static DestinationPtr MakeDebugOutputDestination(); + static DestinationPtr MakeQDebugDestination(); }; } // end namespace diff --git a/logic/net/ForgeXzDownload.cpp b/logic/net/ForgeXzDownload.cpp index 1771d304..83cbabd0 100644 --- a/logic/net/ForgeXzDownload.cpp +++ b/logic/net/ForgeXzDownload.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "logger/QsLog.h" ForgeXzDownload::ForgeXzDownload(QString relative_path, MetaEntryPtr entry) : NetAction() @@ -312,9 +313,11 @@ void ForgeXzDownload::decompressAndInstall() // revert pack200 pack200_file.close(); QString pack_name = pack200_file.fileName(); + QString source_native = QDir::toNativeSeparators(pack_name); + QString target_native = QDir::toNativeSeparators(m_target_path); try { - unpack_200(pack_name.toStdString(), m_target_path.toStdString()); + unpack_200(source_native.toStdString(), target_native.toStdString()); } catch (std::runtime_error &err) { diff --git a/logic/updater/DownloadUpdateTask.cpp b/logic/updater/DownloadUpdateTask.cpp index d72cfcf6..cc06104a 100644 --- a/logic/updater/DownloadUpdateTask.cpp +++ b/logic/updater/DownloadUpdateTask.cpp @@ -26,9 +26,8 @@ #include - -DownloadUpdateTask::DownloadUpdateTask(QString repoUrl, int versionId, QObject* parent) : - Task(parent) +DownloadUpdateTask::DownloadUpdateTask(QString repoUrl, int versionId, QObject *parent) + : Task(parent) { m_cVersionId = MMC->version().build; @@ -87,7 +86,8 @@ void DownloadUpdateTask::findCurrentVersionInfo() // Load the channel list and wait for it to finish loading. QLOG_INFO() << "No channel list entries found. Will try reloading it."; - QObject::connect(checker.get(), &UpdateChecker::channelListLoaded, this, &DownloadUpdateTask::processChannels); + QObject::connect(checker.get(), &UpdateChecker::channelListLoaded, this, + &DownloadUpdateTask::processChannels); checker->updateChanList(); } else @@ -101,11 +101,12 @@ void DownloadUpdateTask::loadVersionInfo() setStatus(tr("Loading version information.")); // Create the net job for loading version info. - NetJob* netJob = new NetJob("Version Info"); - + NetJob *netJob = new NetJob("Version Info"); + // Find the index URL. QUrl newIndexUrl = QUrl(m_nRepoUrl).resolved(QString::number(m_nVersionId) + ".json"); - + QLOG_DEBUG() << m_nRepoUrl << " turns into " << newIndexUrl; + // Add a net action to download the version info for the version we're updating to. netJob->addNetAction(ByteArrayDownload::make(newIndexUrl)); @@ -114,10 +115,12 @@ void DownloadUpdateTask::loadVersionInfo() { QUrl cIndexUrl = QUrl(m_cRepoUrl).resolved(QString::number(m_cVersionId) + ".json"); netJob->addNetAction(ByteArrayDownload::make(cIndexUrl)); + QLOG_DEBUG() << m_cRepoUrl << " turns into " << cIndexUrl; } // Connect slots so we know when it's done. - QObject::connect(netJob, &NetJob::succeeded, this, &DownloadUpdateTask::vinfoDownloadFinished); + QObject::connect(netJob, &NetJob::succeeded, this, + &DownloadUpdateTask::vinfoDownloadFinished); QObject::connect(netJob, &NetJob::failed, this, &DownloadUpdateTask::vinfoDownloadFailed); // Store the NetJob in a class member. We don't want to lose it! @@ -135,7 +138,8 @@ void DownloadUpdateTask::vinfoDownloadFinished() void DownloadUpdateTask::vinfoDownloadFailed() { - // Something failed. We really need the second download (current version info), so parse downloads anyways as long as the first one succeeded. + // Something failed. We really need the second download (current version info), so parse + // downloads anyways as long as the first one succeeded. if (m_vinfoNetJob->first()->m_status != Job_Failed) { parseDownloadedVersionInfo(); @@ -154,43 +158,51 @@ void DownloadUpdateTask::parseDownloadedVersionInfo() setStatus(tr("Reading file list for new version.")); QLOG_DEBUG() << "Reading file list for new version."; QString error; - if (!parseVersionInfo(std::dynamic_pointer_cast( - m_vinfoNetJob->first())->m_data, &m_nVersionFileList, &error)) + if (!parseVersionInfo( + std::dynamic_pointer_cast(m_vinfoNetJob->first())->m_data, + &m_nVersionFileList, &error)) { emitFailed(error); return; } - // If there is a second entry in the network job's list, load it as the current version's info. + // If there is a second entry in the network job's list, load it as the current version's + // info. if (m_vinfoNetJob->size() >= 2 && m_vinfoNetJob->operator[](1)->m_status != Job_Failed) { setStatus(tr("Reading file list for current version.")); QLOG_DEBUG() << "Reading file list for current version."; QString error; - parseVersionInfo(std::dynamic_pointer_cast( - m_vinfoNetJob->operator[](1))->m_data, &m_cVersionFileList, &error); + parseVersionInfo( + std::dynamic_pointer_cast(m_vinfoNetJob->operator[](1))->m_data, + &m_cVersionFileList, &error); } // We don't need this any more. m_vinfoNetJob.reset(); - // Now that we're done loading version info, we can move on to the next step. Process file lists and download files. + // Now that we're done loading version info, we can move on to the next step. Process file + // lists and download files. processFileLists(); } -bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileList* list, QString *error) +bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileList *list, + QString *error) { QJsonParseError jsonError; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); if (jsonError.error != QJsonParseError::NoError) { - *error = QString("Failed to parse version info JSON: %1 at %2").arg(jsonError.errorString()).arg(jsonError.offset); + *error = QString("Failed to parse version info JSON: %1 at %2") + .arg(jsonError.errorString()) + .arg(jsonError.offset); QLOG_ERROR() << error; return false; } QJsonObject json = jsonDoc.object(); + QLOG_DEBUG() << data; QLOG_DEBUG() << "Loading version info from JSON."; QJsonArray filesArray = json.value("Files").toArray(); for (QJsonValue fileValue : filesArray) @@ -198,13 +210,10 @@ bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileLis QJsonObject fileObj = fileValue.toObject(); VersionFileEntry file{ - fileObj.value("Path").toString(), - fileObj.value("Perms").toVariant().toInt(), - FileSourceList(), - fileObj.value("MD5").toString(), - }; + fileObj.value("Path").toString(), fileObj.value("Perms").toVariant().toInt(), + FileSourceList(), fileObj.value("MD5").toString(), }; QLOG_DEBUG() << "File" << file.path << "with perms" << file.mode; - + QJsonArray sourceArray = fileObj.value("Sources").toArray(); for (QJsonValue val : sourceArray) { @@ -213,11 +222,14 @@ bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileLis QString type = sourceObj.value("SourceType").toString(); if (type == "http") { - file.sources.append(FileSource("http", preparePath(sourceObj.value("Url").toString()))); + file.sources.append( + FileSource("http", preparePath(sourceObj.value("Url").toString()))); } else if (type == "httpc") { - file.sources.append(FileSource("httpc", preparePath(sourceObj.value("Url").toString()), sourceObj.value("CompressionType").toString())); + file.sources.append(FileSource("httpc", + preparePath(sourceObj.value("Url").toString()), + sourceObj.value("CompressionType").toString())); } else { @@ -236,13 +248,19 @@ bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileLis void DownloadUpdateTask::processFileLists() { // Create a network job for downloading files. - NetJob* netJob = new NetJob("Update Files"); + NetJob *netJob = new NetJob("Update Files"); - processFileLists(netJob, m_cVersionFileList, m_nVersionFileList, m_operationList); + if (!processFileLists(netJob, m_cVersionFileList, m_nVersionFileList, m_operationList)) + { + emitFailed(tr("Failed to process update lists...")); + return; + } // Add listeners to wait for the downloads to finish. - QObject::connect(netJob, &NetJob::succeeded, this, &DownloadUpdateTask::fileDownloadFinished); - QObject::connect(netJob, &NetJob::progress, this, &DownloadUpdateTask::fileDownloadProgressChanged); + QObject::connect(netJob, &NetJob::succeeded, this, + &DownloadUpdateTask::fileDownloadFinished); + QObject::connect(netJob, &NetJob::progress, this, + &DownloadUpdateTask::fileDownloadProgressChanged); QObject::connect(netJob, &NetJob::failed, this, &DownloadUpdateTask::fileDownloadFailed); // Now start the download. @@ -254,75 +272,144 @@ void DownloadUpdateTask::processFileLists() writeInstallScript(m_operationList, PathCombine(m_updateFilesDir.path(), "file_list.xml")); } -void DownloadUpdateTask::processFileLists(NetJob *job, const VersionFileList ¤tVersion, const VersionFileList &newVersion, DownloadUpdateTask::UpdateOperationList &ops) +bool +DownloadUpdateTask::processFileLists(NetJob *job, + const DownloadUpdateTask::VersionFileList ¤tVersion, + const DownloadUpdateTask::VersionFileList &newVersion, + DownloadUpdateTask::UpdateOperationList &ops) { setStatus(tr("Processing file lists. Figuring out how to install the update.")); - // First, if we've loaded the current version's file list, we need to iterate through it and + // First, if we've loaded the current version's file list, we need to iterate through it and // delete anything in the current one version's list that isn't in the new version's list. for (VersionFileEntry entry : currentVersion) { + QFileInfo toDelete(entry.path); + if (!toDelete.exists()) + { + QLOG_ERROR() << "Expected file " << toDelete.absoluteFilePath() + << " doesn't exist!"; + QLOG_ERROR() << "CWD: " << QDir::currentPath(); + } bool keep = false; + + // for (VersionFileEntry newEntry : newVersion) { if (newEntry.path == entry.path) { - QLOG_DEBUG() << "Not deleting" << entry.path << "because it is still present in the new version."; + QLOG_DEBUG() << "Not deleting" << entry.path + << "because it is still present in the new version."; keep = true; break; } } + // If the loop reaches the end and we didn't find a match, delete the file. - if(!keep) - ops.append(UpdateOperation::DeleteOp(entry.path)); + if (!keep) + { + QFileInfo toDelete(entry.path); + if (toDelete.exists()) + ops.append(UpdateOperation::DeleteOp(entry.path)); + } } // Next, check each file in MultiMC's folder and see if we need to update them. for (VersionFileEntry entry : newVersion) { - // TODO: Let's not MD5sum a ton of files on the GUI thread. We should probably find a way to do this in the background. + // TODO: Let's not MD5sum a ton of files on the GUI thread. We should probably find a + // way to do this in the background. QString fileMD5; QFile entryFile(entry.path); - if (entryFile.open(QFile::ReadOnly)) + QFileInfo entryInfo(entry.path); + + bool needs_upgrade = false; + if (!entryFile.exists()) + { + needs_upgrade = true; + } + else { - QCryptographicHash hash(QCryptographicHash::Md5); - hash.addData(entryFile.readAll()); - fileMD5 = hash.result().toHex(); + bool pass = true; + if (!entryInfo.isReadable()) + { + QLOG_ERROR() << "File " << entry.path << " is not readable."; + pass = false; + } + if (!entryInfo.isWritable()) + { + QLOG_ERROR() << "File " << entry.path << " is not writable."; + pass = false; + } + if (!entryFile.open(QFile::ReadOnly)) + { + QLOG_ERROR() << "File " << entry.path << " cannot be opened for reading."; + pass = false; + } + if (!pass) + { + QLOG_ERROR() << "CWD: " << QDir::currentPath(); + ops.clear(); + return false; + } } - if (!entryFile.exists() || fileMD5.isEmpty() || fileMD5 != entry.md5) + QCryptographicHash hash(QCryptographicHash::Md5); + auto foo = entryFile.readAll(); + + hash.addData(foo); + fileMD5 = hash.result().toHex(); + if ((fileMD5 != entry.md5)) + { + QLOG_DEBUG() << "MD5Sum does not match!"; + QLOG_DEBUG() << "Expected:'" << entry.md5 << "'"; + QLOG_DEBUG() << "Got: '" << fileMD5 << "'"; + needs_upgrade = true; + } + + // skip file. it doesn't need an upgrade. + if (!needs_upgrade) { - QLOG_DEBUG() << "Found file" << entry.path << "that needs updating."; + QLOG_DEBUG() << "File" << entry.path << " does not need updating."; + continue; + } + + // yep. this file actually needs an upgrade. PROCEED. + QLOG_DEBUG() << "Found file" << entry.path << " that needs updating."; - // Go through the sources list and find one to use. - // TODO: Make a NetAction that takes a source list and tries each of them until one works. For now, we'll just use the first http one. - for (FileSource source : entry.sources) + // Go through the sources list and find one to use. + // TODO: Make a NetAction that takes a source list and tries each of them until one + // works. For now, we'll just use the first http one. + for (FileSource source : entry.sources) + { + if (source.type == "http") { - if (source.type == "http") + QLOG_DEBUG() << "Will download" << entry.path << "from" << source.url; + + // Download it to updatedir/- where filepath is the file's + // path with slashes replaced by underscores. + QString dlPath = + PathCombine(m_updateFilesDir.path(), QString(entry.path).replace("/", "_")); + + if (job) { - QLOG_DEBUG() << "Will download" << entry.path << "from" << source.url; - - // Download it to updatedir/- where filepath is the file's path with slashes replaced by underscores. - QString dlPath = PathCombine(m_updateFilesDir.path(), QString(entry.path).replace("/", "_")); - - if (job) - { - // We need to download the file to the updatefiles folder and add a task to copy it to its install path. - auto download = MD5EtagDownload::make(source.url, dlPath); - download->m_check_md5 = true; - download->m_expected_md5 = entry.md5; - job->addNetAction(download); - } - - // Now add a copy operation to our operations list to install the file. - ops.append(UpdateOperation::CopyOp(dlPath, entry.path, entry.mode)); + // We need to download the file to the updatefiles folder and add a task + // to copy it to its install path. + auto download = MD5EtagDownload::make(source.url, dlPath); + download->m_check_md5 = true; + download->m_expected_md5 = entry.md5; + job->addNetAction(download); } + + // Now add a copy operation to our operations list to install the file. + ops.append(UpdateOperation::CopyOp(dlPath, entry.path, entry.mode)); } } } + return true; } -bool DownloadUpdateTask::writeInstallScript(UpdateOperationList& opsList, QString scriptFile) +bool DownloadUpdateTask::writeInstallScript(UpdateOperationList &opsList, QString scriptFile) { // Build the base structure of the XML document. QDomDocument doc; @@ -342,38 +429,43 @@ bool DownloadUpdateTask::writeInstallScript(UpdateOperationList& opsList, QStrin { QDomElement file = doc.createElement("file"); + QString native_file = QDir::toNativeSeparators(op.file); + QString native_dest = QDir::toNativeSeparators(op.dest); + switch (op.type) { - case UpdateOperation::OP_COPY: - { - // Install the file. - QDomElement name = doc.createElement("source"); - QDomElement path = doc.createElement("dest"); - QDomElement mode = doc.createElement("mode"); - name.appendChild(doc.createTextNode(op.file)); - path.appendChild(doc.createTextNode(op.dest)); - // We need to add a 0 at the beginning here, because Qt doesn't convert to octal correctly. - mode.appendChild(doc.createTextNode("0" + QString::number(op.mode, 8))); - file.appendChild(name); - file.appendChild(path); - file.appendChild(mode); - installFiles.appendChild(file); - QLOG_DEBUG() << "Will install file" << op.file; - } - break; + case UpdateOperation::OP_COPY: + { + // Install the file. + QDomElement name = doc.createElement("source"); + QDomElement path = doc.createElement("dest"); + QDomElement mode = doc.createElement("mode"); + name.appendChild(doc.createTextNode(native_file)); + path.appendChild(doc.createTextNode(native_dest)); + // We need to add a 0 at the beginning here, because Qt doesn't convert to octal + // correctly. + mode.appendChild(doc.createTextNode("0" + QString::number(op.mode, 8))); + file.appendChild(name); + file.appendChild(path); + file.appendChild(mode); + installFiles.appendChild(file); + QLOG_DEBUG() << "Will install file" << native_file; + } + break; - case UpdateOperation::OP_DELETE: - { - // Delete the file. - file.appendChild(doc.createTextNode(op.file)); - removeFiles.appendChild(file); - QLOG_DEBUG() << "Will remove file" << op.file; - } - break; + case UpdateOperation::OP_DELETE: + { + // Delete the file. + file.appendChild(doc.createTextNode(native_file)); + removeFiles.appendChild(file); + QLOG_DEBUG() << "Will remove file" << native_file; + } + break; - default: - QLOG_WARN() << "Can't write update operation of type" << op.type << "to file. Not implemented."; - continue; + default: + QLOG_WARN() << "Can't write update operation of type" << op.type + << "to file. Not implemented."; + continue; } } @@ -395,7 +487,9 @@ bool DownloadUpdateTask::writeInstallScript(UpdateOperationList& opsList, QStrin QString DownloadUpdateTask::preparePath(const QString &path) { - return QString(path).replace("$PWD", qApp->applicationDirPath()); + QString foo = path; + foo.replace("$PWD", qApp->applicationDirPath()); + return QUrl::fromLocalFile(foo).toString(QUrl::FullyEncoded); } void DownloadUpdateTask::fileDownloadFinished() @@ -412,11 +506,10 @@ void DownloadUpdateTask::fileDownloadFailed() void DownloadUpdateTask::fileDownloadProgressChanged(qint64 current, qint64 total) { - setProgress((int)(((float)current / (float)total)*100)); + setProgress((int)(((float)current / (float)total) * 100)); } QString DownloadUpdateTask::updateFilesDir() { return m_updateFilesDir.path(); } - diff --git a/logic/updater/DownloadUpdateTask.h b/logic/updater/DownloadUpdateTask.h index 8530be77..1fc14049 100644 --- a/logic/updater/DownloadUpdateTask.h +++ b/logic/updater/DownloadUpdateTask.h @@ -156,7 +156,7 @@ protected: * Takes a list of file entries for the current version's files and the new version's files * and populates the downloadList and operationList with information about how to download and install the update. */ - virtual void processFileLists(NetJob *job, const VersionFileList ¤tVersion, const VersionFileList &newVersion, UpdateOperationList &ops); + virtual bool processFileLists(NetJob *job, const VersionFileList ¤tVersion, const VersionFileList &newVersion, UpdateOperationList &ops); /*! * Calls \see processFileLists to populate the \see m_operationList and a NetJob, and then executes @@ -195,7 +195,8 @@ protected: QTemporaryDir m_updateFilesDir; /*! - * Substitutes $PWD for the application directory + * Filters paths + * Path of the format $PWD/path, it is converted to a file:///$PWD/ URL */ static QString preparePath(const QString &path); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 14670fbd..2d851404 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,6 +8,9 @@ macro(add_unit_test name) unset(srcs) foreach(arg ${testname} ${ARGN}) list(APPEND srcs ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) + if (WIN32) + list(APPEND srcs ${CMAKE_CURRENT_SOURCE_DIR}/test.rc) + endif() endforeach() add_executable(tst_${name} ${srcs}) qt5_use_modules(tst_${name} Test Core Network Widgets) @@ -81,4 +84,9 @@ if(MultiMC_CODE_COVERAGE) add_custom_target(MultiMC_RUN_TESTS DEPENDS MultiMC_GENERATE_COVERAGE_HTML) endif(MultiMC_CODE_COVERAGE) -add_subdirectory(data) + +add_custom_target(MultiMC_Test_Data + ALL + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/data + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/data ${CMAKE_CURRENT_BINARY_DIR}/data +) diff --git a/tests/TestUtil.h b/tests/TestUtil.h index 5de8c4f2..fd25d24f 100644 --- a/tests/TestUtil.h +++ b/tests/TestUtil.h @@ -31,6 +31,9 @@ struct TestsInternal # define _MMC_EXTRA_ARGV # define _MMC_EXTRA_ARGC 0 #endif + + + #define QTEST_GUILESS_MAIN_MULTIMC(TestObject) \ int main(int argc, char *argv[]) \ { \ diff --git a/tests/data/.gitattributes b/tests/data/.gitattributes new file mode 100644 index 00000000..9ac803f0 --- /dev/null +++ b/tests/data/.gitattributes @@ -0,0 +1,2 @@ +* -text -diff + diff --git a/tests/data/1.json b/tests/data/1.json index d5261d2c..f9f99b22 100644 --- a/tests/data/1.json +++ b/tests/data/1.json @@ -8,7 +8,7 @@ "Sources": [ { "SourceType": "http", - "Url": "file://$PWD/tests/data/fileOneA" + "Url": "$PWD/tests/data/fileOneA" } ], "Executable": true, @@ -20,7 +20,7 @@ "Sources": [ { "SourceType": "http", - "Url": "file://$PWD/tests/data/fileTwo" + "Url": "$PWD/tests/data/fileTwo" } ], "Executable": false, @@ -32,7 +32,7 @@ "Sources": [ { "SourceType": "http", - "Url": "file://$PWD/tests/data/fileThree" + "Url": "$PWD/tests/data/fileThree" } ], "Executable": false, diff --git a/tests/data/2.json b/tests/data/2.json index a96aff79..bb59b9b6 100644 --- a/tests/data/2.json +++ b/tests/data/2.json @@ -8,7 +8,7 @@ "Sources": [ { "SourceType": "http", - "Url": "file://$PWD/tests/data/fileOneB" + "Url": "$PWD/tests/data/fileOneB" } ], "Executable": true, @@ -20,7 +20,7 @@ "Sources": [ { "SourceType": "http", - "Url": "file://$PWD/tests/data/fileTwo" + "Url": "$PWD/tests/data/fileTwo" } ], "Executable": false, diff --git a/tests/data/CMakeLists.txt b/tests/data/CMakeLists.txt deleted file mode 100644 index eee5a596..00000000 --- a/tests/data/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_custom_target(MultiMC_Test_Data - ALL - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/tests/data/channels.json b/tests/data/channels.json index e4f04bff..6bf65a82 100644 --- a/tests/data/channels.json +++ b/tests/data/channels.json @@ -5,7 +5,7 @@ "id": "develop", "name": "Develop", "description": "The channel called \"develop\"", - "url": "file://$PWD/tests/data/" + "url": "$PWD/tests/data/" }, { "id": "stable", diff --git a/tests/data/tst_DownloadUpdateTask-test_writeInstallScript_win32.xml b/tests/data/tst_DownloadUpdateTask-test_writeInstallScript_win32.xml new file mode 100644 index 00000000..c79ef984 --- /dev/null +++ b/tests/data/tst_DownloadUpdateTask-test_writeInstallScript_win32.xml @@ -0,0 +1,17 @@ + + + + sourceOne + destOne + 0777 + + + MultiMC.exe + M\u\l\t\i\M\C\e\x\e + 0644 + + + + toDelete.abc + + diff --git a/tests/test.manifest b/tests/test.manifest new file mode 100644 index 00000000..8b4dbb98 --- /dev/null +++ b/tests/test.manifest @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + Custom Minecraft launcher for managing multiple installs. + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test.rc b/tests/test.rc new file mode 100644 index 00000000..a288dba6 --- /dev/null +++ b/tests/test.rc @@ -0,0 +1,28 @@ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +1 RT_MANIFEST "test.manifest" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION 1,0,0,0 +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "MultiMC Contributors" + VALUE "FileDescription", "Testcase" + VALUE "FileVersion", "1.0.0.0" + VALUE "ProductName", "MultiMC Testcase" + VALUE "ProductVersion", "5" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0000, 0x04b0 // Unicode + END +END diff --git a/tests/tst_DownloadUpdateTask.cpp b/tests/tst_DownloadUpdateTask.cpp index d96e4cf1..764af935 100644 --- a/tests/tst_DownloadUpdateTask.cpp +++ b/tests/tst_DownloadUpdateTask.cpp @@ -7,54 +7,73 @@ #include "logic/updater/UpdateChecker.h" #include "depends/util/include/pathutils.h" +DownloadUpdateTask::FileSourceList encodeBaseFile(const char *suffix) +{ + auto base = qApp->applicationDirPath(); + QUrl localFile = QUrl::fromLocalFile(base + suffix); + QString localUrlString = localFile.toString(QUrl::FullyEncoded); + auto item = DownloadUpdateTask::FileSource("http", localUrlString); + return DownloadUpdateTask::FileSourceList({item}); +} + Q_DECLARE_METATYPE(DownloadUpdateTask::VersionFileList) Q_DECLARE_METATYPE(DownloadUpdateTask::UpdateOperation) -bool operator==(const DownloadUpdateTask::FileSource &f1, const DownloadUpdateTask::FileSource &f2) +bool operator==(const DownloadUpdateTask::FileSource &f1, + const DownloadUpdateTask::FileSource &f2) { - return f1.type == f2.type && - f1.url == f2.url && - f1.compressionType == f2.compressionType; + return f1.type == f2.type && f1.url == f2.url && f1.compressionType == f2.compressionType; } -bool operator==(const DownloadUpdateTask::VersionFileEntry &v1, const DownloadUpdateTask::VersionFileEntry &v2) +bool operator==(const DownloadUpdateTask::VersionFileEntry &v1, + const DownloadUpdateTask::VersionFileEntry &v2) { - return v1.path == v2.path && - v1.mode == v2.mode && - v1.sources == v2.sources && - v1.md5 == v2.md5; + return v1.path == v2.path && v1.mode == v2.mode && v1.sources == v2.sources && + v1.md5 == v2.md5; } -bool operator==(const DownloadUpdateTask::UpdateOperation &u1, const DownloadUpdateTask::UpdateOperation &u2) +bool operator==(const DownloadUpdateTask::UpdateOperation &u1, + const DownloadUpdateTask::UpdateOperation &u2) { - return u1.type == u2.type && - u1.file == u2.file && - u1.dest == u2.dest && - u1.mode == u2.mode; + return u1.type == u2.type && u1.file == u2.file && u1.dest == u2.dest && u1.mode == u2.mode; } QDebug operator<<(QDebug dbg, const DownloadUpdateTask::FileSource &f) { - dbg.nospace() << "FileSource(type=" << f.type << " url=" << f.url << " comp=" << f.compressionType << ")"; + dbg.nospace() << "FileSource(type=" << f.type << " url=" << f.url + << " comp=" << f.compressionType << ")"; return dbg.maybeSpace(); } + QDebug operator<<(QDebug dbg, const DownloadUpdateTask::VersionFileEntry &v) { - dbg.nospace() << "VersionFileEntry(path=" << v.path << " mode=" << v.mode << " md5=" << v.md5 << " sources=" << v.sources << ")"; + dbg.nospace() << "VersionFileEntry(path=" << v.path << " mode=" << v.mode + << " md5=" << v.md5 << " sources=" << v.sources << ")"; return dbg.maybeSpace(); } + QDebug operator<<(QDebug dbg, const DownloadUpdateTask::UpdateOperation::Type &t) { switch (t) { - case DownloadUpdateTask::UpdateOperation::OP_COPY: dbg << "OP_COPY"; break; - case DownloadUpdateTask::UpdateOperation::OP_DELETE: dbg << "OP_DELETE"; break; - case DownloadUpdateTask::UpdateOperation::OP_MOVE: dbg << "OP_MOVE"; break; - case DownloadUpdateTask::UpdateOperation::OP_CHMOD: dbg << "OP_CHMOD"; break; + case DownloadUpdateTask::UpdateOperation::OP_COPY: + dbg << "OP_COPY"; + break; + case DownloadUpdateTask::UpdateOperation::OP_DELETE: + dbg << "OP_DELETE"; + break; + case DownloadUpdateTask::UpdateOperation::OP_MOVE: + dbg << "OP_MOVE"; + break; + case DownloadUpdateTask::UpdateOperation::OP_CHMOD: + dbg << "OP_CHMOD"; + break; } return dbg.maybeSpace(); } + QDebug operator<<(QDebug dbg, const DownloadUpdateTask::UpdateOperation &u) { - dbg.nospace() << "UpdateOperation(type=" << u.type << " file=" << u.file << " dest=" << u.dest << " mode=" << u.mode << ")"; + dbg.nospace() << "UpdateOperation(type=" << u.type << " file=" << u.file + << " dest=" << u.dest << " mode=" << u.mode << ")"; return dbg.maybeSpace(); } @@ -65,26 +84,30 @@ private slots: void initTestCase() { - } void cleanupTestCase() { - } void test_writeInstallScript() { - DownloadUpdateTask task(QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/")).toString(), 0); + DownloadUpdateTask task( + QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/")).toString(), 0); DownloadUpdateTask::UpdateOperationList ops; ops << DownloadUpdateTask::UpdateOperation::CopyOp("sourceOne", "destOne", 0777) << DownloadUpdateTask::UpdateOperation::CopyOp("MultiMC.exe", "M/u/l/t/i/M/C/e/x/e") << DownloadUpdateTask::UpdateOperation::DeleteOp("toDelete.abc"); - +#if defined(Q_OS_WIN) + auto testFile = "tests/data/tst_DownloadUpdateTask-test_writeInstallScript_win32.xml"; +#else + auto testFile = "tests/data/tst_DownloadUpdateTask-test_writeInstallScript.xml"; +#endif const QString script = QDir::temp().absoluteFilePath("MultiMCUpdateScript.xml"); QVERIFY(task.writeInstallScript(ops, script)); - QCOMPARE(TestsInternal::readFileUtf8(script), MULTIMC_GET_TEST_FILE_UTF8("tests/data/tst_DownloadUpdateTask-test_writeInstallScript.xml")); + QCOMPARE(TestsInternal::readFileUtf8(script).replace(QRegExp("[\r\n]+"), "\n"), + MULTIMC_GET_TEST_FILE_UTF8(testFile).replace(QRegExp("[\r\n]+"), "\n")); } void test_parseVersionInfo_data() @@ -94,29 +117,34 @@ slots: QTest::addColumn("error"); QTest::addColumn("ret"); - QTest::newRow("one") << MULTIMC_GET_TEST_FILE("tests/data/1.json") - << (DownloadUpdateTask::VersionFileList() - << DownloadUpdateTask::VersionFileEntry{"fileOne", 493, - (DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileOneA")), - "9eb84090956c484e32cb6c08455a667b"} - << DownloadUpdateTask::VersionFileEntry{"fileTwo", 644, - (DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileTwo")), - "38f94f54fa3eb72b0ea836538c10b043"} - << DownloadUpdateTask::VersionFileEntry{"fileThree", 750, - (DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileThree")), - "f12df554b21e320be6471d7154130e70"}) - << QString() - << true; - QTest::newRow("two") << MULTIMC_GET_TEST_FILE("tests/data/2.json") - << (DownloadUpdateTask::VersionFileList() - << DownloadUpdateTask::VersionFileEntry{"fileOne", 493, - (DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileOneB")), - "42915a71277c9016668cce7b82c6b577"} - << DownloadUpdateTask::VersionFileEntry{"fileTwo", 644, - (DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileTwo")), - "38f94f54fa3eb72b0ea836538c10b043"}) - << QString() - << true; + QTest::newRow("one") + << MULTIMC_GET_TEST_FILE("tests/data/1.json") + << (DownloadUpdateTask::VersionFileList() + << DownloadUpdateTask::VersionFileEntry{"fileOne", + 493, + encodeBaseFile("/tests/data/fileOneA"), + "9eb84090956c484e32cb6c08455a667b"} + << DownloadUpdateTask::VersionFileEntry{"fileTwo", + 644, + encodeBaseFile("/tests/data/fileTwo"), + "38f94f54fa3eb72b0ea836538c10b043"} + << DownloadUpdateTask::VersionFileEntry{"fileThree", + 750, + encodeBaseFile("/tests/data/fileThree"), + "f12df554b21e320be6471d7154130e70"}) + << QString() << true; + QTest::newRow("two") + << MULTIMC_GET_TEST_FILE("tests/data/2.json") + << (DownloadUpdateTask::VersionFileList() + << DownloadUpdateTask::VersionFileEntry{"fileOne", + 493, + encodeBaseFile("/tests/data/fileOneB"), + "42915a71277c9016668cce7b82c6b577"} + << DownloadUpdateTask::VersionFileEntry{"fileTwo", + 644, + encodeBaseFile("/tests/data/fileTwo"), + "38f94f54fa3eb72b0ea836538c10b043"}) + << QString() << true; } void test_parseVersionInfo() { @@ -143,23 +171,45 @@ slots: DownloadUpdateTask *downloader = new DownloadUpdateTask(QString(), -1); // update fileOne, keep fileTwo, remove fileThree - QTest::newRow("test 1") << downloader - << (DownloadUpdateTask::VersionFileList() - << DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileOne"), 493, DownloadUpdateTask::FileSourceList() - << DownloadUpdateTask::FileSource("http", "http://host/path/fileOne-1"), "9eb84090956c484e32cb6c08455a667b"} - << DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileTwo"), 644, DownloadUpdateTask::FileSourceList() - << DownloadUpdateTask::FileSource("http", "http://host/path/fileTwo-1"), "38f94f54fa3eb72b0ea836538c10b043"} - << DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileThree"), 420, DownloadUpdateTask::FileSourceList() - << DownloadUpdateTask::FileSource("http", "http://host/path/fileThree-1"), "f12df554b21e320be6471d7154130e70"}) - << (DownloadUpdateTask::VersionFileList() - << DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileOne"), 493, DownloadUpdateTask::FileSourceList() - << DownloadUpdateTask::FileSource("http", "http://host/path/fileOne-2"), "42915a71277c9016668cce7b82c6b577"} - << DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileTwo"), 644, DownloadUpdateTask::FileSourceList() - << DownloadUpdateTask::FileSource("http", "http://host/path/fileTwo-2"), "38f94f54fa3eb72b0ea836538c10b043"}) - << (DownloadUpdateTask::UpdateOperationList() - << DownloadUpdateTask::UpdateOperation::DeleteOp(QFINDTESTDATA("tests/data/fileThree")) - << DownloadUpdateTask::UpdateOperation::CopyOp(PathCombine(downloader->updateFilesDir(), QFINDTESTDATA("tests/data/fileOne").replace("/", "_")), - QFINDTESTDATA("tests/data/fileOne"), 493)); + QTest::newRow("test 1") + << downloader << (DownloadUpdateTask::VersionFileList() + << DownloadUpdateTask::VersionFileEntry{ + "tests/data/fileOne", 493, + DownloadUpdateTask::FileSourceList() + << DownloadUpdateTask::FileSource( + "http", "http://host/path/fileOne-1"), + "9eb84090956c484e32cb6c08455a667b"} + << DownloadUpdateTask::VersionFileEntry{ + "tests/data/fileTwo", 644, + DownloadUpdateTask::FileSourceList() + << DownloadUpdateTask::FileSource( + "http", "http://host/path/fileTwo-1"), + "38f94f54fa3eb72b0ea836538c10b043"} + << DownloadUpdateTask::VersionFileEntry{ + "tests/data/fileThree", 420, + DownloadUpdateTask::FileSourceList() + << DownloadUpdateTask::FileSource( + "http", "http://host/path/fileThree-1"), + "f12df554b21e320be6471d7154130e70"}) + << (DownloadUpdateTask::VersionFileList() + << DownloadUpdateTask::VersionFileEntry{ + "tests/data/fileOne", 493, + DownloadUpdateTask::FileSourceList() + << DownloadUpdateTask::FileSource("http", + "http://host/path/fileOne-2"), + "42915a71277c9016668cce7b82c6b577"} + << DownloadUpdateTask::VersionFileEntry{ + "tests/data/fileTwo", 644, + DownloadUpdateTask::FileSourceList() + << DownloadUpdateTask::FileSource("http", + "http://host/path/fileTwo-2"), + "38f94f54fa3eb72b0ea836538c10b043"}) + << (DownloadUpdateTask::UpdateOperationList() + << DownloadUpdateTask::UpdateOperation::DeleteOp("tests/data/fileThree") + << DownloadUpdateTask::UpdateOperation::CopyOp( + PathCombine(downloader->updateFilesDir(), + QString("tests/data/fileOne").replace("/", "_")), + "tests/data/fileOne", 493)); } void test_processFileLists() { @@ -170,7 +220,8 @@ slots: DownloadUpdateTask::UpdateOperationList operations; - downloader->processFileLists(new NetJob("Dummy"), currentVersion, newVersion, operations); + downloader->processFileLists(new NetJob("Dummy"), currentVersion, newVersion, + operations); qDebug() << (operations == expectedOperations); qDebug() << operations; qDebug() << expectedOperations; @@ -182,10 +233,15 @@ slots: QLOG_INFO() << "#####################"; MMC->m_version.build = 1; MMC->m_version.channel = "develop"; - MMC->updateChecker()->setChannelListUrl(QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/channels.json")).toString()); + auto channels = + QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/channels.json")); + auto root = QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/")); + QLOG_DEBUG() << "channels: " << channels; + QLOG_DEBUG() << "root: " << root; + MMC->updateChecker()->setChannelListUrl(channels.toString()); MMC->updateChecker()->setCurrentChannel("develop"); - DownloadUpdateTask task(QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/")).toString(), 2); + DownloadUpdateTask task(root.toString(), 2); QSignalSpy succeededSpy(&task, SIGNAL(succeeded())); diff --git a/tests/tst_UpdateChecker.cpp b/tests/tst_UpdateChecker.cpp index 0f023f0e..af3ae802 100644 --- a/tests/tst_UpdateChecker.cpp +++ b/tests/tst_UpdateChecker.cpp @@ -76,7 +76,7 @@ slots: << true << true << (QList() - << UpdateChecker::ChannelListEntry{"develop", "Develop", "The channel called \"develop\"", "file://$PWD/tests/data/"} + << UpdateChecker::ChannelListEntry{"develop", "Develop", "The channel called \"develop\"", "$PWD/tests/data/"} << UpdateChecker::ChannelListEntry{"stable", "Stable", "It's stable at least", "ftp://username@host/path/to/stuff"} << UpdateChecker::ChannelListEntry{"42", "The Channel", "This is the channel that is going to answer all of your questions", "https://dent.me/tea"}); } diff --git a/tests/tst_pathutils.cpp b/tests/tst_pathutils.cpp index 1e4a83bf..a1310d00 100644 --- a/tests/tst_pathutils.cpp +++ b/tests/tst_pathutils.cpp @@ -23,13 +23,12 @@ slots: QTest::addColumn("path1"); QTest::addColumn("path2"); -#if defined(Q_OS_UNIX) - QTest::newRow("unix 1") << "/abc/def/ghi/jkl" << "/abc/def" << "ghi/jkl"; - QTest::newRow("unix 2") << "/abc/def/ghi/jkl" << "/abc/def/" << "ghi/jkl"; -#elif defined(Q_OS_WIN) - QTest::newRow("win, from C:") << "C:\\abc" << "C:" << "abc\\def"; - QTest::newRow("win 1") << "C:\\abc\\def\\ghi\\jkl" << "C:\\abc\\def" << "ghi\\jkl"; - QTest::newRow("win 2") << "C:\\abc\\def\\ghi\\jkl" << "C:\\abc\\def\\" << "ghi\\jkl"; + QTest::newRow("qt 1") << "/abc/def/ghi/jkl" << "/abc/def" << "ghi/jkl"; + QTest::newRow("qt 2") << "/abc/def/ghi/jkl" << "/abc/def/" << "ghi/jkl"; +#if defined(Q_OS_WIN) + QTest::newRow("win native, from C:") << "C:/abc" << "C:" << "abc"; + QTest::newRow("win native 1") << "C:/abc/def/ghi/jkl" << "C:\\abc\\def" << "ghi\\jkl"; + QTest::newRow("win native 2") << "C:/abc/def/ghi/jkl" << "C:\\abc\\def\\" << "ghi\\jkl"; #endif } void test_PathCombine1() @@ -48,16 +47,15 @@ slots: QTest::addColumn("path2"); QTest::addColumn("path3"); -#if defined(Q_OS_UNIX) - QTest::newRow("unix 1") << "/abc/def/ghi/jkl" << "/abc" << "def" << "ghi/jkl"; - QTest::newRow("unix 2") << "/abc/def/ghi/jkl" << "/abc/" << "def" << "ghi/jkl"; - QTest::newRow("unix 3") << "/abc/def/ghi/jkl" << "/abc" << "def/" << "ghi/jkl"; - QTest::newRow("unix 4") << "/abc/def/ghi/jkl" << "/abc/" << "def/" << "ghi/jkl"; -#elif defined(Q_OS_WIN) - QTest::newRow("win 1") << "C:\\abc\\def\\ghi\\jkl" << "C:\\abc" << "def" << "ghi\\jkl"; - QTest::newRow("win 2") << "C:\\abc\\def\\ghi\\jkl" << "C:\\abc\\" << "def" << "ghi\\jkl"; - QTest::newRow("win 3") << "C:\\abc\\def\\ghi\\jkl" << "C:\\abc" << "def\\" << "ghi\\jkl"; - QTest::newRow("win 4") << "C:\\abc\\def\\ghi\\jkl" << "C:\\abc\\" << "def" << "ghi\\jkl"; + QTest::newRow("qt 1") << "/abc/def/ghi/jkl" << "/abc" << "def" << "ghi/jkl"; + QTest::newRow("qt 2") << "/abc/def/ghi/jkl" << "/abc/" << "def" << "ghi/jkl"; + QTest::newRow("qt 3") << "/abc/def/ghi/jkl" << "/abc" << "def/" << "ghi/jkl"; + QTest::newRow("qt 4") << "/abc/def/ghi/jkl" << "/abc/" << "def/" << "ghi/jkl"; +#if defined(Q_OS_WIN) + QTest::newRow("win 1") << "C:/abc/def/ghi/jkl" << "C:\\abc" << "def" << "ghi\\jkl"; + QTest::newRow("win 2") << "C:/abc/def/ghi/jkl" << "C:\\abc\\" << "def" << "ghi\\jkl"; + QTest::newRow("win 3") << "C:/abc/def/ghi/jkl" << "C:\\abc" << "def\\" << "ghi\\jkl"; + QTest::newRow("win 4") << "C:/abc/def/ghi/jkl" << "C:\\abc\\" << "def" << "ghi\\jkl"; #endif } void test_PathCombine2() diff --git a/tests/tst_userutils.cpp b/tests/tst_userutils.cpp index 62bee985..3bc980c0 100644 --- a/tests/tst_userutils.cpp +++ b/tests/tst_userutils.cpp @@ -23,6 +23,9 @@ slots: QCOMPARE(Util::getDesktopDir(), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); } +// this is only valid on linux +// FIXME: implement on windows, OSX, then test. +#if defined(Q_OS_LINUX) void test_createShortcut_data() { QTest::addColumn("location"); @@ -40,7 +43,7 @@ slots: #if defined(Q_OS_LINUX) << MULTIMC_GET_TEST_FILE("data/tst_userutils-test_createShortcut-unix") #elif defined(Q_OS_WIN) - << QString() + << QByteArray() #endif ; } @@ -59,8 +62,10 @@ slots: //QDir().remove(location); } +#endif }; + QTEST_GUILESS_MAIN_MULTIMC(UserUtilsTest) #include "tst_userutils.moc" -- cgit From 0d7b411729b89c5cebc8baaf48bec46fb182536b Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Wed, 25 Dec 2013 03:25:21 +0100 Subject: No more windows paths in tests. --- ...DownloadUpdateTask-test_writeInstallScript_win32.xml | 17 ----------------- tests/tst_DownloadUpdateTask.cpp | 4 ---- 2 files changed, 21 deletions(-) delete mode 100644 tests/data/tst_DownloadUpdateTask-test_writeInstallScript_win32.xml (limited to 'tests/tst_DownloadUpdateTask.cpp') diff --git a/tests/data/tst_DownloadUpdateTask-test_writeInstallScript_win32.xml b/tests/data/tst_DownloadUpdateTask-test_writeInstallScript_win32.xml deleted file mode 100644 index c79ef984..00000000 --- a/tests/data/tst_DownloadUpdateTask-test_writeInstallScript_win32.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - sourceOne - destOne - 0777 - - - MultiMC.exe - M\u\l\t\i\M\C\e\x\e - 0644 - - - - toDelete.abc - - diff --git a/tests/tst_DownloadUpdateTask.cpp b/tests/tst_DownloadUpdateTask.cpp index 764af935..f47552fe 100644 --- a/tests/tst_DownloadUpdateTask.cpp +++ b/tests/tst_DownloadUpdateTask.cpp @@ -99,11 +99,7 @@ slots: ops << DownloadUpdateTask::UpdateOperation::CopyOp("sourceOne", "destOne", 0777) << DownloadUpdateTask::UpdateOperation::CopyOp("MultiMC.exe", "M/u/l/t/i/M/C/e/x/e") << DownloadUpdateTask::UpdateOperation::DeleteOp("toDelete.abc"); -#if defined(Q_OS_WIN) - auto testFile = "tests/data/tst_DownloadUpdateTask-test_writeInstallScript_win32.xml"; -#else auto testFile = "tests/data/tst_DownloadUpdateTask-test_writeInstallScript.xml"; -#endif const QString script = QDir::temp().absoluteFilePath("MultiMCUpdateScript.xml"); QVERIFY(task.writeInstallScript(ops, script)); QCOMPARE(TestsInternal::readFileUtf8(script).replace(QRegExp("[\r\n]+"), "\n"), -- cgit From 7652b3d64a63c587f520633364412345083210d4 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Sat, 28 Dec 2013 02:03:53 +0100 Subject: Various updater fixes Updater tests for path utils The updater now doesn't use splitpath on Windows (fixes problems with Windows XP) Fix up paths for the OSX updater - should now install the updates into the right place Fix translations install path - translation isntall and deploy should be fixed --- CMakeLists.txt | 6 ++++- logic/updater/DownloadUpdateTask.cpp | 36 +++++++++++++++++++++---- logic/updater/DownloadUpdateTask.h | 16 ++++++++++- mmc_updater/src/FileUtils.cpp | 44 ++----------------------------- mmc_updater/src/tests/CMakeLists.txt | 19 ++++++++----- mmc_updater/src/tests/TestFileUtils.cpp | 33 +++++++++++++++++++++-- mmc_updater/src/tests/TestParseScript.cpp | 2 +- mmc_updater/src/tests/test.manifest | 27 +++++++++++++++++++ mmc_updater/src/tests/test.rc | 28 ++++++++++++++++++++ tests/tst_DownloadUpdateTask.cpp | 19 +++++++++++++ 10 files changed, 171 insertions(+), 59 deletions(-) create mode 100644 mmc_updater/src/tests/test.manifest create mode 100644 mmc_updater/src/tests/test.rc (limited to 'tests/tst_DownloadUpdateTask.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b371aa9..7c8087cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -662,8 +662,12 @@ ELSE() ENDIF() add_custom_target (translations DEPENDS ${QM_FILES}) +IF(APPLE AND UNIX) ## OSX + install(FILES ${QM_FILES} DESTINATION MultiMC.app/Contents/MacOS/translations) +ELSE() + install(FILES ${QM_FILES} DESTINATION translations) +ENDIF() -install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/translations) # Tests add_subdirectory(tests) diff --git a/logic/updater/DownloadUpdateTask.cpp b/logic/updater/DownloadUpdateTask.cpp index 057ca436..0b09ad2a 100644 --- a/logic/updater/DownloadUpdateTask.cpp +++ b/logic/updater/DownloadUpdateTask.cpp @@ -66,7 +66,7 @@ void DownloadUpdateTask::processChannels() if (channel.id == channelId) { QLOG_INFO() << "Found matching channel."; - m_cRepoUrl = preparePath(channel.url); + m_cRepoUrl = fixPathForTests(channel.url); break; } } @@ -207,8 +207,17 @@ bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileLis { QJsonObject fileObj = fileValue.toObject(); + QString file_path = fileObj.value("Path").toString(); +#ifdef Q_OS_MAC + // On OSX, the paths for the updater need to be fixed. + // basically, anything that isn't in the .app folder is ignored. + // everything else is changed so the code that processes the files actually finds + // them and puts the replacements in the right spots. + if(!fixPathForOSX(file_path)) + continue; +#endif VersionFileEntry file{ - fileObj.value("Path").toString(), fileObj.value("Perms").toVariant().toInt(), + file_path , fileObj.value("Perms").toVariant().toInt(), FileSourceList(), fileObj.value("MD5").toString(), }; QLOG_DEBUG() << "File" << file.path << "with perms" << file.mode; @@ -221,12 +230,12 @@ bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileLis if (type == "http") { file.sources.append( - FileSource("http", preparePath(sourceObj.value("Url").toString()))); + FileSource("http", fixPathForTests(sourceObj.value("Url").toString()))); } else if (type == "httpc") { file.sources.append(FileSource("httpc", - preparePath(sourceObj.value("Url").toString()), + fixPathForTests(sourceObj.value("Url").toString()), sourceObj.value("CompressionType").toString())); } else @@ -491,7 +500,7 @@ bool DownloadUpdateTask::writeInstallScript(UpdateOperationList &opsList, QStrin return true; } -QString DownloadUpdateTask::preparePath(const QString &path) +QString DownloadUpdateTask::fixPathForTests(const QString &path) { if(path.startsWith("$PWD")) { @@ -502,6 +511,23 @@ QString DownloadUpdateTask::preparePath(const QString &path) return path; } +bool DownloadUpdateTask::fixPathForOSX(QString &path) +{ + if(path.startsWith("MultiMC.app/")) + { + // remove the prefix and add a new, more appropriate one. + path.remove(0,12); + path = QString("../../") + path; + return true; + } + else + { + QLOG_ERROR() << "Update path not within .app: " << path; + return false; + } +} + + void DownloadUpdateTask::fileDownloadFinished() { emitSucceeded(); diff --git a/logic/updater/DownloadUpdateTask.h b/logic/updater/DownloadUpdateTask.h index 79d73af3..d82b044f 100644 --- a/logic/updater/DownloadUpdateTask.h +++ b/logic/updater/DownloadUpdateTask.h @@ -198,7 +198,21 @@ protected: * Filters paths * Path of the format $PWD/path, it is converted to a file:///$PWD/ URL */ - static QString preparePath(const QString &path); + static QString fixPathForTests(const QString &path); + + /*! + * Filters paths + * This fixes destination paths for OSX. + * The updater runs in MultiMC.app/Contents/MacOs by default + * The destination paths are such as this: MultiMC.app/blah/blah + * + * Therefore we chop off the 'MultiMC.app' prefix and prepend ../.. + * + * Returns false if the path couldn't be fixed (is invalid) + * + * Has no effect on systems that aren't OSX + */ + static bool fixPathForOSX(QString &path); protected slots: void vinfoDownloadFinished(); diff --git a/mmc_updater/src/FileUtils.cpp b/mmc_updater/src/FileUtils.cpp index 10435e49..712c0c5d 100644 --- a/mmc_updater/src/FileUtils.cpp +++ b/mmc_updater/src/FileUtils.cpp @@ -10,6 +10,8 @@ #include #include #include +// this actually works with mingw32, which we use. +#include #ifdef PLATFORM_UNIX #include @@ -19,7 +21,6 @@ #include #include #include -#include #endif FileUtils::IOException::IOException(const std::string& error) @@ -249,59 +250,18 @@ void FileUtils::removeFile(const char* src) throw (IOException) std::string FileUtils::fileName(const char* path) { -#ifdef PLATFORM_UNIX char* pathCopy = strdup(path); std::string basename = ::basename(pathCopy); free(pathCopy); return basename; -#else - char baseName[MAX_PATH]; - char extension[MAX_PATH]; - _splitpath_s(path, - 0, /* drive */ - 0, /* drive length */ - 0, /* dir */ - 0, /* dir length */ - baseName, - MAX_PATH, /* baseName length */ - extension, - MAX_PATH /* extension length */ - ); - return std::string(baseName) + std::string(extension); -#endif } std::string FileUtils::dirname(const char* path) { -#ifdef PLATFORM_UNIX char* pathCopy = strdup(path); std::string dirname = ::dirname(pathCopy); free(pathCopy); return dirname; -#else - char drive[3]; - char dir[MAX_PATH]; - - _splitpath_s(path, - drive, /* drive */ - 3, /* drive length */ - dir, - MAX_PATH, /* dir length */ - 0, /* filename */ - 0, /* filename length */ - 0, /* extension */ - 0 /* extension length */ - ); - - std::string result; - if (drive[0]) - { - result += std::string(drive); - } - result += dir; - - return result; -#endif } void FileUtils::touch(const char* path) throw (IOException) diff --git a/mmc_updater/src/tests/CMakeLists.txt b/mmc_updater/src/tests/CMakeLists.txt index 1d62214e..79402245 100644 --- a/mmc_updater/src/tests/CMakeLists.txt +++ b/mmc_updater/src/tests/CMakeLists.txt @@ -29,13 +29,18 @@ endforeach() # Add unit test binaries macro(ADD_UPDATER_TEST CLASS) - set(TEST_TARGET updater_${CLASS}) - add_executable(${TEST_TARGET} ${CLASS}.cpp) - target_link_libraries(${TEST_TARGET} updatershared) - add_test(NAME ${TEST_TARGET} COMMAND ${TEST_TARGET}) - if (APPLE) - set_target_properties(${TEST_TARGET} PROPERTIES LINK_FLAGS "-framework Security -framework Cocoa") - endif() + set(TEST_TARGET updater_${CLASS}) + unset(srcs) + list(APPEND srcs ${CLASS}.cpp) + if (WIN32) + list(APPEND srcs ${CMAKE_CURRENT_SOURCE_DIR}/test.rc) + endif() + add_executable(${TEST_TARGET} ${srcs}) + target_link_libraries(${TEST_TARGET} updatershared) + add_test(NAME ${TEST_TARGET} COMMAND ${TEST_TARGET}) + if (APPLE) + set_target_properties(${TEST_TARGET} PROPERTIES LINK_FLAGS "-framework Security -framework Cocoa") + endif() endmacro() add_updater_test(TestParseScript) diff --git a/mmc_updater/src/tests/TestFileUtils.cpp b/mmc_updater/src/tests/TestFileUtils.cpp index 709acc5c..f8535a28 100644 --- a/mmc_updater/src/tests/TestFileUtils.cpp +++ b/mmc_updater/src/tests/TestFileUtils.cpp @@ -5,10 +5,39 @@ void TestFileUtils::testDirName() { + std::string dirName; + std::string fileName; + #ifdef PLATFORM_WINDOWS - std::string dirName = FileUtils::dirname("E:/Some Dir/App.exe"); - TEST_COMPARE(dirName,"E:/Some Dir/"); + // absolute paths + dirName = FileUtils::dirname("E:/Some Dir/App.exe"); + TEST_COMPARE(dirName,"E:/Some Dir"); + fileName = FileUtils::fileName("E:/Some Dir/App.exe"); + TEST_COMPARE(fileName,"App.exe"); + + dirName = FileUtils::dirname("C:/Users/kitteh/AppData/Local/Temp/MultiMC5-yidaaa/MultiMC.exe"); + TEST_COMPARE(dirName,"C:/Users/kitteh/AppData/Local/Temp/MultiMC5-yidaaa"); + fileName = FileUtils::fileName("C:/Users/kitteh/AppData/Local/Temp/MultiMC5-yidaaa/MultiMC.exe"); + TEST_COMPARE(fileName,"MultiMC.exe"); + +#else + // absolute paths + dirName = FileUtils::dirname("/home/tester/foo bar/baz"); + TEST_COMPARE(dirName,"/home/tester/foo bar"); + fileName = FileUtils::fileName("/home/tester/foo bar/baz"); + TEST_COMPARE(fileName,"baz"); #endif + // current directory + dirName = FileUtils::dirname("App.exe"); + TEST_COMPARE(dirName,"."); + fileName = FileUtils::fileName("App.exe"); + TEST_COMPARE(fileName,"App.exe"); + + // relative paths + dirName = FileUtils::dirname("Foo/App.exe"); + TEST_COMPARE(dirName,"Foo"); + fileName = FileUtils::fileName("Foo/App.exe"); + TEST_COMPARE(fileName,"App.exe"); } void TestFileUtils::testIsRelative() diff --git a/mmc_updater/src/tests/TestParseScript.cpp b/mmc_updater/src/tests/TestParseScript.cpp index f4453957..e8087b33 100644 --- a/mmc_updater/src/tests/TestParseScript.cpp +++ b/mmc_updater/src/tests/TestParseScript.cpp @@ -10,7 +10,7 @@ void TestParseScript::testParse() { UpdateScript script; - script.parse("file_list.xml"); + script.parse("mmc_updater/src/tests/file_list.xml"); TEST_COMPARE(script.isValid(),true); } diff --git a/mmc_updater/src/tests/test.manifest b/mmc_updater/src/tests/test.manifest new file mode 100644 index 00000000..8b4dbb98 --- /dev/null +++ b/mmc_updater/src/tests/test.manifest @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + Custom Minecraft launcher for managing multiple installs. + + + + + + + + + + + \ No newline at end of file diff --git a/mmc_updater/src/tests/test.rc b/mmc_updater/src/tests/test.rc new file mode 100644 index 00000000..a288dba6 --- /dev/null +++ b/mmc_updater/src/tests/test.rc @@ -0,0 +1,28 @@ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +1 RT_MANIFEST "test.manifest" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION 1,0,0,0 +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "MultiMC Contributors" + VALUE "FileDescription", "Testcase" + VALUE "FileVersion", "1.0.0.0" + VALUE "ProductName", "MultiMC Testcase" + VALUE "ProductVersion", "5" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0000, 0x04b0 // Unicode + END +END diff --git a/tests/tst_DownloadUpdateTask.cpp b/tests/tst_DownloadUpdateTask.cpp index f47552fe..3b2c6793 100644 --- a/tests/tst_DownloadUpdateTask.cpp +++ b/tests/tst_DownloadUpdateTask.cpp @@ -245,6 +245,25 @@ slots: QVERIFY(succeededSpy.wait()); } + + void test_OSXPathFixup() + { + QString path, pathOrig; + bool result; + // Proper OSX path + pathOrig = path = "MultiMC.app/Foo/Bar/Baz"; + qDebug() << "Proper OSX path: " << path; + result = DownloadUpdateTask::fixPathForOSX(path); + QCOMPARE(path, QString("../../Foo/Bar/Baz")); + QCOMPARE(result, true); + + // Bad OSX path + pathOrig = path = "translations/klingon.lol"; + qDebug() << "Bad OSX path: " << path; + result = DownloadUpdateTask::fixPathForOSX(path); + QCOMPARE(path, pathOrig); + QCOMPARE(result, false); + } }; QTEST_GUILESS_MAIN_MULTIMC(DownloadUpdateTaskTest) -- cgit