Some test madness

This commit is contained in:
Petr Mrázek 2013-12-17 02:09:58 +01:00
parent 20e86801b3
commit d6c71488b3
22 changed files with 457 additions and 201 deletions

View File

@ -43,11 +43,18 @@ ENDIF()
######## 3rd Party Libs ######## ######## 3rd Party Libs ########
# Find the required Qt parts # Find the required Qt parts
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED) find_package(Qt5Widgets REQUIRED)
find_package(Qt5Network REQUIRED) find_package(Qt5Network REQUIRED)
find_package(Qt5Test REQUIRED)
find_package(Qt5LinguistTools 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. # The Qt5 cmake files don't provide its install paths, so ask qmake.
get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION) get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION)

View File

@ -286,7 +286,7 @@ void MultiMC::initLogger()
QsLogging::Logger &logger = QsLogging::Logger::instance(); QsLogging::Logger &logger = QsLogging::Logger::instance();
logger.setLoggingLevel(QsLogging::TraceLevel); logger.setLoggingLevel(QsLogging::TraceLevel);
m_fileDestination = QsLogging::DestinationFactory::MakeFileDestination("MultiMC.log"); 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_fileDestination.get());
logger.addDestination(m_debugDestination.get()); logger.addDestination(m_debugDestination.get());
// log all the things // log all the things

View File

@ -23,10 +23,7 @@
QString PathCombine(QString path1, QString path2) QString PathCombine(QString path1, QString path2)
{ {
if (!path1.endsWith('/')) return QDir::cleanPath(path1 + QDir::separator() + path2);
return path1.append('/').append(path2);
else
return path1.append(path2);
} }
QString PathCombine(QString path1, QString path2, QString path3) QString PathCombine(QString path1, QString path2, QString path3)

View File

@ -77,6 +77,15 @@ void DebugOutputDestination::write(const QString &message)
QsDebugOutput::output(message); QsDebugOutput::output(message);
} }
class QDebugDestination : public Destination
{
public:
virtual void write(const QString &message)
{
qDebug() << message;
};
};
DestinationPtr DestinationFactory::MakeFileDestination(const QString &filePath) DestinationPtr DestinationFactory::MakeFileDestination(const QString &filePath)
{ {
return DestinationPtr(new FileDestination(filePath)); return DestinationPtr(new FileDestination(filePath));
@ -87,4 +96,9 @@ DestinationPtr DestinationFactory::MakeDebugOutputDestination()
return DestinationPtr(new DebugOutputDestination); return DestinationPtr(new DebugOutputDestination);
} }
DestinationPtr DestinationFactory::MakeQDebugDestination()
{
return DestinationPtr(new QDebugDestination);
}
} // end namespace } // end namespace

View File

@ -47,6 +47,7 @@ class DestinationFactory
public: public:
static DestinationPtr MakeFileDestination(const QString &filePath); static DestinationPtr MakeFileDestination(const QString &filePath);
static DestinationPtr MakeDebugOutputDestination(); static DestinationPtr MakeDebugOutputDestination();
static DestinationPtr MakeQDebugDestination();
}; };
} // end namespace } // end namespace

View File

@ -20,6 +20,7 @@
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QFileInfo> #include <QFileInfo>
#include <QDateTime> #include <QDateTime>
#include <QDir>
#include "logger/QsLog.h" #include "logger/QsLog.h"
ForgeXzDownload::ForgeXzDownload(QString relative_path, MetaEntryPtr entry) : NetAction() ForgeXzDownload::ForgeXzDownload(QString relative_path, MetaEntryPtr entry) : NetAction()
@ -312,9 +313,11 @@ void ForgeXzDownload::decompressAndInstall()
// revert pack200 // revert pack200
pack200_file.close(); pack200_file.close();
QString pack_name = pack200_file.fileName(); QString pack_name = pack200_file.fileName();
QString source_native = QDir::toNativeSeparators(pack_name);
QString target_native = QDir::toNativeSeparators(m_target_path);
try try
{ {
unpack_200(pack_name.toStdString(), m_target_path.toStdString()); unpack_200(source_native.toStdString(), target_native.toStdString());
} }
catch (std::runtime_error &err) catch (std::runtime_error &err)
{ {

View File

@ -26,9 +26,8 @@
#include <QDomDocument> #include <QDomDocument>
DownloadUpdateTask::DownloadUpdateTask(QString repoUrl, int versionId, QObject *parent)
DownloadUpdateTask::DownloadUpdateTask(QString repoUrl, int versionId, QObject* parent) : : Task(parent)
Task(parent)
{ {
m_cVersionId = MMC->version().build; m_cVersionId = MMC->version().build;
@ -87,7 +86,8 @@ void DownloadUpdateTask::findCurrentVersionInfo()
// Load the channel list and wait for it to finish loading. // Load the channel list and wait for it to finish loading.
QLOG_INFO() << "No channel list entries found. Will try reloading it."; 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(); checker->updateChanList();
} }
else else
@ -101,10 +101,11 @@ void DownloadUpdateTask::loadVersionInfo()
setStatus(tr("Loading version information.")); setStatus(tr("Loading version information."));
// Create the net job for loading version info. // Create the net job for loading version info.
NetJob* netJob = new NetJob("Version Info"); NetJob *netJob = new NetJob("Version Info");
// Find the index URL. // Find the index URL.
QUrl newIndexUrl = QUrl(m_nRepoUrl).resolved(QString::number(m_nVersionId) + ".json"); 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. // Add a net action to download the version info for the version we're updating to.
netJob->addNetAction(ByteArrayDownload::make(newIndexUrl)); netJob->addNetAction(ByteArrayDownload::make(newIndexUrl));
@ -114,10 +115,12 @@ void DownloadUpdateTask::loadVersionInfo()
{ {
QUrl cIndexUrl = QUrl(m_cRepoUrl).resolved(QString::number(m_cVersionId) + ".json"); QUrl cIndexUrl = QUrl(m_cRepoUrl).resolved(QString::number(m_cVersionId) + ".json");
netJob->addNetAction(ByteArrayDownload::make(cIndexUrl)); netJob->addNetAction(ByteArrayDownload::make(cIndexUrl));
QLOG_DEBUG() << m_cRepoUrl << " turns into " << cIndexUrl;
} }
// Connect slots so we know when it's done. // 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); QObject::connect(netJob, &NetJob::failed, this, &DownloadUpdateTask::vinfoDownloadFailed);
// Store the NetJob in a class member. We don't want to lose it! // Store the NetJob in a class member. We don't want to lose it!
@ -135,7 +138,8 @@ void DownloadUpdateTask::vinfoDownloadFinished()
void DownloadUpdateTask::vinfoDownloadFailed() 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) if (m_vinfoNetJob->first()->m_status != Job_Failed)
{ {
parseDownloadedVersionInfo(); parseDownloadedVersionInfo();
@ -154,43 +158,51 @@ void DownloadUpdateTask::parseDownloadedVersionInfo()
setStatus(tr("Reading file list for new version.")); setStatus(tr("Reading file list for new version."));
QLOG_DEBUG() << "Reading file list for new version."; QLOG_DEBUG() << "Reading file list for new version.";
QString error; QString error;
if (!parseVersionInfo(std::dynamic_pointer_cast<ByteArrayDownload>( if (!parseVersionInfo(
m_vinfoNetJob->first())->m_data, &m_nVersionFileList, &error)) std::dynamic_pointer_cast<ByteArrayDownload>(m_vinfoNetJob->first())->m_data,
&m_nVersionFileList, &error))
{ {
emitFailed(error); emitFailed(error);
return; 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) if (m_vinfoNetJob->size() >= 2 && m_vinfoNetJob->operator[](1)->m_status != Job_Failed)
{ {
setStatus(tr("Reading file list for current version.")); setStatus(tr("Reading file list for current version."));
QLOG_DEBUG() << "Reading file list for current version."; QLOG_DEBUG() << "Reading file list for current version.";
QString error; QString error;
parseVersionInfo(std::dynamic_pointer_cast<ByteArrayDownload>( parseVersionInfo(
m_vinfoNetJob->operator[](1))->m_data, &m_cVersionFileList, &error); std::dynamic_pointer_cast<ByteArrayDownload>(m_vinfoNetJob->operator[](1))->m_data,
&m_cVersionFileList, &error);
} }
// We don't need this any more. // We don't need this any more.
m_vinfoNetJob.reset(); 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(); processFileLists();
} }
bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileList* list, QString *error) bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileList *list,
QString *error)
{ {
QJsonParseError jsonError; QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
if (jsonError.error != QJsonParseError::NoError) 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; QLOG_ERROR() << error;
return false; return false;
} }
QJsonObject json = jsonDoc.object(); QJsonObject json = jsonDoc.object();
QLOG_DEBUG() << data;
QLOG_DEBUG() << "Loading version info from JSON."; QLOG_DEBUG() << "Loading version info from JSON.";
QJsonArray filesArray = json.value("Files").toArray(); QJsonArray filesArray = json.value("Files").toArray();
for (QJsonValue fileValue : filesArray) for (QJsonValue fileValue : filesArray)
@ -198,11 +210,8 @@ bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileLis
QJsonObject fileObj = fileValue.toObject(); QJsonObject fileObj = fileValue.toObject();
VersionFileEntry file{ VersionFileEntry file{
fileObj.value("Path").toString(), fileObj.value("Path").toString(), fileObj.value("Perms").toVariant().toInt(),
fileObj.value("Perms").toVariant().toInt(), FileSourceList(), fileObj.value("MD5").toString(), };
FileSourceList(),
fileObj.value("MD5").toString(),
};
QLOG_DEBUG() << "File" << file.path << "with perms" << file.mode; QLOG_DEBUG() << "File" << file.path << "with perms" << file.mode;
QJsonArray sourceArray = fileObj.value("Sources").toArray(); QJsonArray sourceArray = fileObj.value("Sources").toArray();
@ -213,11 +222,14 @@ bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileLis
QString type = sourceObj.value("SourceType").toString(); QString type = sourceObj.value("SourceType").toString();
if (type == "http") 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") 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 else
{ {
@ -236,13 +248,19 @@ bool DownloadUpdateTask::parseVersionInfo(const QByteArray &data, VersionFileLis
void DownloadUpdateTask::processFileLists() void DownloadUpdateTask::processFileLists()
{ {
// Create a network job for downloading files. // 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. // Add listeners to wait for the downloads to finish.
QObject::connect(netJob, &NetJob::succeeded, this, &DownloadUpdateTask::fileDownloadFinished); QObject::connect(netJob, &NetJob::succeeded, this,
QObject::connect(netJob, &NetJob::progress, this, &DownloadUpdateTask::fileDownloadProgressChanged); &DownloadUpdateTask::fileDownloadFinished);
QObject::connect(netJob, &NetJob::progress, this,
&DownloadUpdateTask::fileDownloadProgressChanged);
QObject::connect(netJob, &NetJob::failed, this, &DownloadUpdateTask::fileDownloadFailed); QObject::connect(netJob, &NetJob::failed, this, &DownloadUpdateTask::fileDownloadFailed);
// Now start the download. // Now start the download.
@ -254,7 +272,11 @@ void DownloadUpdateTask::processFileLists()
writeInstallScript(m_operationList, PathCombine(m_updateFilesDir.path(), "file_list.xml")); writeInstallScript(m_operationList, PathCombine(m_updateFilesDir.path(), "file_list.xml"));
} }
void DownloadUpdateTask::processFileLists(NetJob *job, const VersionFileList &currentVersion, const VersionFileList &newVersion, DownloadUpdateTask::UpdateOperationList &ops) bool
DownloadUpdateTask::processFileLists(NetJob *job,
const DownloadUpdateTask::VersionFileList &currentVersion,
const DownloadUpdateTask::VersionFileList &newVersion,
DownloadUpdateTask::UpdateOperationList &ops)
{ {
setStatus(tr("Processing file lists. Figuring out how to install the update.")); setStatus(tr("Processing file lists. Figuring out how to install the update."));
@ -262,52 +284,117 @@ void DownloadUpdateTask::processFileLists(NetJob *job, const VersionFileList &cu
// delete anything in the current one version's list that isn't in the new version's list. // delete anything in the current one version's list that isn't in the new version's list.
for (VersionFileEntry entry : currentVersion) 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; bool keep = false;
//
for (VersionFileEntry newEntry : newVersion) for (VersionFileEntry newEntry : newVersion)
{ {
if (newEntry.path == entry.path) 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; keep = true;
break; break;
} }
} }
// If the loop reaches the end and we didn't find a match, delete the file. // If the loop reaches the end and we didn't find a match, delete the file.
if(!keep) if (!keep)
{
QFileInfo toDelete(entry.path);
if (toDelete.exists())
ops.append(UpdateOperation::DeleteOp(entry.path)); ops.append(UpdateOperation::DeleteOp(entry.path));
} }
}
// Next, check each file in MultiMC's folder and see if we need to update them. // Next, check each file in MultiMC's folder and see if we need to update them.
for (VersionFileEntry entry : newVersion) 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; QString fileMD5;
QFile entryFile(entry.path); QFile entryFile(entry.path);
if (entryFile.open(QFile::ReadOnly)) QFileInfo entryInfo(entry.path);
bool needs_upgrade = false;
if (!entryFile.exists())
{ {
QCryptographicHash hash(QCryptographicHash::Md5); needs_upgrade = true;
hash.addData(entryFile.readAll()); }
fileMD5 = hash.result().toHex(); else
{
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() << "Found file" << entry.path << "that needs updating."; 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() << "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. // 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. // 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) for (FileSource source : entry.sources)
{ {
if (source.type == "http") if (source.type == "http")
{ {
QLOG_DEBUG() << "Will download" << entry.path << "from" << source.url; QLOG_DEBUG() << "Will download" << entry.path << "from" << source.url;
// Download it to updatedir/<filepath>-<md5> where filepath is the file's path with slashes replaced by underscores. // Download it to updatedir/<filepath>-<md5> where filepath is the file's
QString dlPath = PathCombine(m_updateFilesDir.path(), QString(entry.path).replace("/", "_")); // path with slashes replaced by underscores.
QString dlPath =
PathCombine(m_updateFilesDir.path(), QString(entry.path).replace("/", "_"));
if (job) if (job)
{ {
// We need to download the file to the updatefiles folder and add a task to copy it to its install path. // 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); auto download = MD5EtagDownload::make(source.url, dlPath);
download->m_check_md5 = true; download->m_check_md5 = true;
download->m_expected_md5 = entry.md5; download->m_expected_md5 = entry.md5;
@ -319,10 +406,10 @@ void DownloadUpdateTask::processFileLists(NetJob *job, const VersionFileList &cu
} }
} }
} }
} return true;
} }
bool DownloadUpdateTask::writeInstallScript(UpdateOperationList& opsList, QString scriptFile) bool DownloadUpdateTask::writeInstallScript(UpdateOperationList &opsList, QString scriptFile)
{ {
// Build the base structure of the XML document. // Build the base structure of the XML document.
QDomDocument doc; QDomDocument doc;
@ -342,6 +429,9 @@ bool DownloadUpdateTask::writeInstallScript(UpdateOperationList& opsList, QStrin
{ {
QDomElement file = doc.createElement("file"); QDomElement file = doc.createElement("file");
QString native_file = QDir::toNativeSeparators(op.file);
QString native_dest = QDir::toNativeSeparators(op.dest);
switch (op.type) switch (op.type)
{ {
case UpdateOperation::OP_COPY: case UpdateOperation::OP_COPY:
@ -350,29 +440,31 @@ bool DownloadUpdateTask::writeInstallScript(UpdateOperationList& opsList, QStrin
QDomElement name = doc.createElement("source"); QDomElement name = doc.createElement("source");
QDomElement path = doc.createElement("dest"); QDomElement path = doc.createElement("dest");
QDomElement mode = doc.createElement("mode"); QDomElement mode = doc.createElement("mode");
name.appendChild(doc.createTextNode(op.file)); name.appendChild(doc.createTextNode(native_file));
path.appendChild(doc.createTextNode(op.dest)); path.appendChild(doc.createTextNode(native_dest));
// We need to add a 0 at the beginning here, because Qt doesn't convert to octal correctly. // 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))); mode.appendChild(doc.createTextNode("0" + QString::number(op.mode, 8)));
file.appendChild(name); file.appendChild(name);
file.appendChild(path); file.appendChild(path);
file.appendChild(mode); file.appendChild(mode);
installFiles.appendChild(file); installFiles.appendChild(file);
QLOG_DEBUG() << "Will install file" << op.file; QLOG_DEBUG() << "Will install file" << native_file;
} }
break; break;
case UpdateOperation::OP_DELETE: case UpdateOperation::OP_DELETE:
{ {
// Delete the file. // Delete the file.
file.appendChild(doc.createTextNode(op.file)); file.appendChild(doc.createTextNode(native_file));
removeFiles.appendChild(file); removeFiles.appendChild(file);
QLOG_DEBUG() << "Will remove file" << op.file; QLOG_DEBUG() << "Will remove file" << native_file;
} }
break; break;
default: default:
QLOG_WARN() << "Can't write update operation of type" << op.type << "to file. Not implemented."; QLOG_WARN() << "Can't write update operation of type" << op.type
<< "to file. Not implemented.";
continue; continue;
} }
} }
@ -395,7 +487,9 @@ bool DownloadUpdateTask::writeInstallScript(UpdateOperationList& opsList, QStrin
QString DownloadUpdateTask::preparePath(const QString &path) 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() void DownloadUpdateTask::fileDownloadFinished()
@ -412,11 +506,10 @@ void DownloadUpdateTask::fileDownloadFailed()
void DownloadUpdateTask::fileDownloadProgressChanged(qint64 current, qint64 total) void DownloadUpdateTask::fileDownloadProgressChanged(qint64 current, qint64 total)
{ {
setProgress((int)(((float)current / (float)total)*100)); setProgress((int)(((float)current / (float)total) * 100));
} }
QString DownloadUpdateTask::updateFilesDir() QString DownloadUpdateTask::updateFilesDir()
{ {
return m_updateFilesDir.path(); return m_updateFilesDir.path();
} }

View File

@ -156,7 +156,7 @@ protected:
* Takes a list of file entries for the current version's files and the new version's files * 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. * and populates the downloadList and operationList with information about how to download and install the update.
*/ */
virtual void processFileLists(NetJob *job, const VersionFileList &currentVersion, const VersionFileList &newVersion, UpdateOperationList &ops); virtual bool processFileLists(NetJob *job, const VersionFileList &currentVersion, const VersionFileList &newVersion, UpdateOperationList &ops);
/*! /*!
* Calls \see processFileLists to populate the \see m_operationList and a NetJob, and then executes * Calls \see processFileLists to populate the \see m_operationList and a NetJob, and then executes
@ -195,7 +195,8 @@ protected:
QTemporaryDir m_updateFilesDir; 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); static QString preparePath(const QString &path);

View File

@ -8,6 +8,9 @@ macro(add_unit_test name)
unset(srcs) unset(srcs)
foreach(arg ${testname} ${ARGN}) foreach(arg ${testname} ${ARGN})
list(APPEND srcs ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) list(APPEND srcs ${CMAKE_CURRENT_SOURCE_DIR}/${arg})
if (WIN32)
list(APPEND srcs ${CMAKE_CURRENT_SOURCE_DIR}/test.rc)
endif()
endforeach() endforeach()
add_executable(tst_${name} ${srcs}) add_executable(tst_${name} ${srcs})
qt5_use_modules(tst_${name} Test Core Network Widgets) 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) add_custom_target(MultiMC_RUN_TESTS DEPENDS MultiMC_GENERATE_COVERAGE_HTML)
endif(MultiMC_CODE_COVERAGE) 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
)

View File

@ -31,6 +31,9 @@ struct TestsInternal
# define _MMC_EXTRA_ARGV # define _MMC_EXTRA_ARGV
# define _MMC_EXTRA_ARGC 0 # define _MMC_EXTRA_ARGC 0
#endif #endif
#define QTEST_GUILESS_MAIN_MULTIMC(TestObject) \ #define QTEST_GUILESS_MAIN_MULTIMC(TestObject) \
int main(int argc, char *argv[]) \ int main(int argc, char *argv[]) \
{ \ { \

2
tests/data/.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
* -text -diff

View File

@ -8,7 +8,7 @@
"Sources": [ "Sources": [
{ {
"SourceType": "http", "SourceType": "http",
"Url": "file://$PWD/tests/data/fileOneA" "Url": "$PWD/tests/data/fileOneA"
} }
], ],
"Executable": true, "Executable": true,
@ -20,7 +20,7 @@
"Sources": [ "Sources": [
{ {
"SourceType": "http", "SourceType": "http",
"Url": "file://$PWD/tests/data/fileTwo" "Url": "$PWD/tests/data/fileTwo"
} }
], ],
"Executable": false, "Executable": false,
@ -32,7 +32,7 @@
"Sources": [ "Sources": [
{ {
"SourceType": "http", "SourceType": "http",
"Url": "file://$PWD/tests/data/fileThree" "Url": "$PWD/tests/data/fileThree"
} }
], ],
"Executable": false, "Executable": false,

View File

@ -8,7 +8,7 @@
"Sources": [ "Sources": [
{ {
"SourceType": "http", "SourceType": "http",
"Url": "file://$PWD/tests/data/fileOneB" "Url": "$PWD/tests/data/fileOneB"
} }
], ],
"Executable": true, "Executable": true,
@ -20,7 +20,7 @@
"Sources": [ "Sources": [
{ {
"SourceType": "http", "SourceType": "http",
"Url": "file://$PWD/tests/data/fileTwo" "Url": "$PWD/tests/data/fileTwo"
} }
], ],
"Executable": false, "Executable": false,

View File

@ -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}
)

View File

@ -5,7 +5,7 @@
"id": "develop", "id": "develop",
"name": "Develop", "name": "Develop",
"description": "The channel called \"develop\"", "description": "The channel called \"develop\"",
"url": "file://$PWD/tests/data/" "url": "$PWD/tests/data/"
}, },
{ {
"id": "stable", "id": "stable",

View File

@ -0,0 +1,17 @@
<update version="3">
<install>
<file>
<source>sourceOne</source>
<dest>destOne</dest>
<mode>0777</mode>
</file>
<file>
<source>MultiMC.exe</source>
<dest>M\u\l\t\i\M\C\e\x\e</dest>
<mode>0644</mode>
</file>
</install>
<uninstall>
<file>toDelete.abc</file>
</uninstall>
</update>

27
tests/test.manifest Normal file
View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity name="MultiMC.Test.0" type="win32" version="5.0.0.0" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
<description>Custom Minecraft launcher for managing multiple installs.</description>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--The ID below indicates app support for Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!--The ID below indicates app support for Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!--The ID below indicates app support for Windows Developer Preview / Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application>
</compatibility>
</assembly>

28
tests/test.rc Normal file
View File

@ -0,0 +1,28 @@
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
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

View File

@ -7,54 +7,73 @@
#include "logic/updater/UpdateChecker.h" #include "logic/updater/UpdateChecker.h"
#include "depends/util/include/pathutils.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::VersionFileList)
Q_DECLARE_METATYPE(DownloadUpdateTask::UpdateOperation) 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 && return f1.type == f2.type && f1.url == f2.url && f1.compressionType == f2.compressionType;
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 && return v1.path == v2.path && v1.mode == v2.mode && v1.sources == v2.sources &&
v1.mode == v2.mode &&
v1.sources == v2.sources &&
v1.md5 == v2.md5; 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 && return u1.type == u2.type && u1.file == u2.file && u1.dest == u2.dest && u1.mode == u2.mode;
u1.file == u2.file &&
u1.dest == u2.dest &&
u1.mode == u2.mode;
} }
QDebug operator<<(QDebug dbg, const DownloadUpdateTask::FileSource &f) 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(); return dbg.maybeSpace();
} }
QDebug operator<<(QDebug dbg, const DownloadUpdateTask::VersionFileEntry &v) 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(); return dbg.maybeSpace();
} }
QDebug operator<<(QDebug dbg, const DownloadUpdateTask::UpdateOperation::Type &t) QDebug operator<<(QDebug dbg, const DownloadUpdateTask::UpdateOperation::Type &t)
{ {
switch (t) switch (t)
{ {
case DownloadUpdateTask::UpdateOperation::OP_COPY: dbg << "OP_COPY"; break; case DownloadUpdateTask::UpdateOperation::OP_COPY:
case DownloadUpdateTask::UpdateOperation::OP_DELETE: dbg << "OP_DELETE"; break; dbg << "OP_COPY";
case DownloadUpdateTask::UpdateOperation::OP_MOVE: dbg << "OP_MOVE"; break; break;
case DownloadUpdateTask::UpdateOperation::OP_CHMOD: dbg << "OP_CHMOD"; 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(); return dbg.maybeSpace();
} }
QDebug operator<<(QDebug dbg, const DownloadUpdateTask::UpdateOperation &u) 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(); return dbg.maybeSpace();
} }
@ -65,26 +84,30 @@ private
slots: slots:
void initTestCase() void initTestCase()
{ {
} }
void cleanupTestCase() void cleanupTestCase()
{ {
} }
void test_writeInstallScript() 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; DownloadUpdateTask::UpdateOperationList ops;
ops << DownloadUpdateTask::UpdateOperation::CopyOp("sourceOne", "destOne", 0777) ops << DownloadUpdateTask::UpdateOperation::CopyOp("sourceOne", "destOne", 0777)
<< DownloadUpdateTask::UpdateOperation::CopyOp("MultiMC.exe", "M/u/l/t/i/M/C/e/x/e") << DownloadUpdateTask::UpdateOperation::CopyOp("MultiMC.exe", "M/u/l/t/i/M/C/e/x/e")
<< DownloadUpdateTask::UpdateOperation::DeleteOp("toDelete.abc"); << 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"); const QString script = QDir::temp().absoluteFilePath("MultiMCUpdateScript.xml");
QVERIFY(task.writeInstallScript(ops, script)); 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() void test_parseVersionInfo_data()
@ -94,29 +117,34 @@ slots:
QTest::addColumn<QString>("error"); QTest::addColumn<QString>("error");
QTest::addColumn<bool>("ret"); QTest::addColumn<bool>("ret");
QTest::newRow("one") << MULTIMC_GET_TEST_FILE("tests/data/1.json") QTest::newRow("one")
<< MULTIMC_GET_TEST_FILE("tests/data/1.json")
<< (DownloadUpdateTask::VersionFileList() << (DownloadUpdateTask::VersionFileList()
<< DownloadUpdateTask::VersionFileEntry{"fileOne", 493, << DownloadUpdateTask::VersionFileEntry{"fileOne",
(DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileOneA")), 493,
encodeBaseFile("/tests/data/fileOneA"),
"9eb84090956c484e32cb6c08455a667b"} "9eb84090956c484e32cb6c08455a667b"}
<< DownloadUpdateTask::VersionFileEntry{"fileTwo", 644, << DownloadUpdateTask::VersionFileEntry{"fileTwo",
(DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileTwo")), 644,
encodeBaseFile("/tests/data/fileTwo"),
"38f94f54fa3eb72b0ea836538c10b043"} "38f94f54fa3eb72b0ea836538c10b043"}
<< DownloadUpdateTask::VersionFileEntry{"fileThree", 750, << DownloadUpdateTask::VersionFileEntry{"fileThree",
(DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileThree")), 750,
encodeBaseFile("/tests/data/fileThree"),
"f12df554b21e320be6471d7154130e70"}) "f12df554b21e320be6471d7154130e70"})
<< QString() << QString() << true;
<< true; QTest::newRow("two")
QTest::newRow("two") << MULTIMC_GET_TEST_FILE("tests/data/2.json") << MULTIMC_GET_TEST_FILE("tests/data/2.json")
<< (DownloadUpdateTask::VersionFileList() << (DownloadUpdateTask::VersionFileList()
<< DownloadUpdateTask::VersionFileEntry{"fileOne", 493, << DownloadUpdateTask::VersionFileEntry{"fileOne",
(DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileOneB")), 493,
encodeBaseFile("/tests/data/fileOneB"),
"42915a71277c9016668cce7b82c6b577"} "42915a71277c9016668cce7b82c6b577"}
<< DownloadUpdateTask::VersionFileEntry{"fileTwo", 644, << DownloadUpdateTask::VersionFileEntry{"fileTwo",
(DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http", "file://" + qApp->applicationDirPath() + "/tests/data/fileTwo")), 644,
encodeBaseFile("/tests/data/fileTwo"),
"38f94f54fa3eb72b0ea836538c10b043"}) "38f94f54fa3eb72b0ea836538c10b043"})
<< QString() << QString() << true;
<< true;
} }
void test_parseVersionInfo() void test_parseVersionInfo()
{ {
@ -143,23 +171,45 @@ slots:
DownloadUpdateTask *downloader = new DownloadUpdateTask(QString(), -1); DownloadUpdateTask *downloader = new DownloadUpdateTask(QString(), -1);
// update fileOne, keep fileTwo, remove fileThree // update fileOne, keep fileTwo, remove fileThree
QTest::newRow("test 1") << downloader 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::VersionFileList()
<< DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileOne"), 493, DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::VersionFileEntry{
<< DownloadUpdateTask::FileSource("http", "http://host/path/fileOne-1"), "9eb84090956c484e32cb6c08455a667b"} "tests/data/fileOne", 493,
<< DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileTwo"), 644, DownloadUpdateTask::FileSourceList() DownloadUpdateTask::FileSourceList()
<< DownloadUpdateTask::FileSource("http", "http://host/path/fileTwo-1"), "38f94f54fa3eb72b0ea836538c10b043"} << DownloadUpdateTask::FileSource("http",
<< DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileThree"), 420, DownloadUpdateTask::FileSourceList() "http://host/path/fileOne-2"),
<< DownloadUpdateTask::FileSource("http", "http://host/path/fileThree-1"), "f12df554b21e320be6471d7154130e70"}) "42915a71277c9016668cce7b82c6b577"}
<< (DownloadUpdateTask::VersionFileList() << DownloadUpdateTask::VersionFileEntry{
<< DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileOne"), 493, DownloadUpdateTask::FileSourceList() "tests/data/fileTwo", 644,
<< DownloadUpdateTask::FileSource("http", "http://host/path/fileOne-2"), "42915a71277c9016668cce7b82c6b577"} DownloadUpdateTask::FileSourceList()
<< DownloadUpdateTask::VersionFileEntry{QFINDTESTDATA("tests/data/fileTwo"), 644, DownloadUpdateTask::FileSourceList() << DownloadUpdateTask::FileSource("http",
<< DownloadUpdateTask::FileSource("http", "http://host/path/fileTwo-2"), "38f94f54fa3eb72b0ea836538c10b043"}) "http://host/path/fileTwo-2"),
"38f94f54fa3eb72b0ea836538c10b043"})
<< (DownloadUpdateTask::UpdateOperationList() << (DownloadUpdateTask::UpdateOperationList()
<< DownloadUpdateTask::UpdateOperation::DeleteOp(QFINDTESTDATA("tests/data/fileThree")) << DownloadUpdateTask::UpdateOperation::DeleteOp("tests/data/fileThree")
<< DownloadUpdateTask::UpdateOperation::CopyOp(PathCombine(downloader->updateFilesDir(), QFINDTESTDATA("tests/data/fileOne").replace("/", "_")), << DownloadUpdateTask::UpdateOperation::CopyOp(
QFINDTESTDATA("tests/data/fileOne"), 493)); PathCombine(downloader->updateFilesDir(),
QString("tests/data/fileOne").replace("/", "_")),
"tests/data/fileOne", 493));
} }
void test_processFileLists() void test_processFileLists()
{ {
@ -170,7 +220,8 @@ slots:
DownloadUpdateTask::UpdateOperationList operations; DownloadUpdateTask::UpdateOperationList operations;
downloader->processFileLists(new NetJob("Dummy"), currentVersion, newVersion, operations); downloader->processFileLists(new NetJob("Dummy"), currentVersion, newVersion,
operations);
qDebug() << (operations == expectedOperations); qDebug() << (operations == expectedOperations);
qDebug() << operations; qDebug() << operations;
qDebug() << expectedOperations; qDebug() << expectedOperations;
@ -182,10 +233,15 @@ slots:
QLOG_INFO() << "#####################"; QLOG_INFO() << "#####################";
MMC->m_version.build = 1; MMC->m_version.build = 1;
MMC->m_version.channel = "develop"; 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"); 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())); QSignalSpy succeededSpy(&task, SIGNAL(succeeded()));

View File

@ -76,7 +76,7 @@ slots:
<< true << true
<< true << true
<< (QList<UpdateChecker::ChannelListEntry>() << (QList<UpdateChecker::ChannelListEntry>()
<< 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{"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"}); << UpdateChecker::ChannelListEntry{"42", "The Channel", "This is the channel that is going to answer all of your questions", "https://dent.me/tea"});
} }

View File

@ -23,13 +23,12 @@ slots:
QTest::addColumn<QString>("path1"); QTest::addColumn<QString>("path1");
QTest::addColumn<QString>("path2"); QTest::addColumn<QString>("path2");
#if defined(Q_OS_UNIX) QTest::newRow("qt 1") << "/abc/def/ghi/jkl" << "/abc/def" << "ghi/jkl";
QTest::newRow("unix 1") << "/abc/def/ghi/jkl" << "/abc/def" << "ghi/jkl"; QTest::newRow("qt 2") << "/abc/def/ghi/jkl" << "/abc/def/" << "ghi/jkl";
QTest::newRow("unix 2") << "/abc/def/ghi/jkl" << "/abc/def/" << "ghi/jkl"; #if defined(Q_OS_WIN)
#elif defined(Q_OS_WIN) QTest::newRow("win native, from C:") << "C:/abc" << "C:" << "abc";
QTest::newRow("win, from C:") << "C:\\abc" << "C:" << "abc\\def"; QTest::newRow("win native 1") << "C:/abc/def/ghi/jkl" << "C:\\abc\\def" << "ghi\\jkl";
QTest::newRow("win 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";
QTest::newRow("win 2") << "C:\\abc\\def\\ghi\\jkl" << "C:\\abc\\def\\" << "ghi\\jkl";
#endif #endif
} }
void test_PathCombine1() void test_PathCombine1()
@ -48,16 +47,15 @@ slots:
QTest::addColumn<QString>("path2"); QTest::addColumn<QString>("path2");
QTest::addColumn<QString>("path3"); QTest::addColumn<QString>("path3");
#if defined(Q_OS_UNIX) QTest::newRow("qt 1") << "/abc/def/ghi/jkl" << "/abc" << "def" << "ghi/jkl";
QTest::newRow("unix 1") << "/abc/def/ghi/jkl" << "/abc" << "def" << "ghi/jkl"; QTest::newRow("qt 2") << "/abc/def/ghi/jkl" << "/abc/" << "def" << "ghi/jkl";
QTest::newRow("unix 2") << "/abc/def/ghi/jkl" << "/abc/" << "def" << "ghi/jkl"; QTest::newRow("qt 3") << "/abc/def/ghi/jkl" << "/abc" << "def/" << "ghi/jkl";
QTest::newRow("unix 3") << "/abc/def/ghi/jkl" << "/abc" << "def/" << "ghi/jkl"; QTest::newRow("qt 4") << "/abc/def/ghi/jkl" << "/abc/" << "def/" << "ghi/jkl";
QTest::newRow("unix 4") << "/abc/def/ghi/jkl" << "/abc/" << "def/" << "ghi/jkl"; #if defined(Q_OS_WIN)
#elif defined(Q_OS_WIN) QTest::newRow("win 1") << "C:/abc/def/ghi/jkl" << "C:\\abc" << "def" << "ghi\\jkl";
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 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 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("win 4") << "C:\\abc\\def\\ghi\\jkl" << "C:\\abc\\" << "def" << "ghi\\jkl";
#endif #endif
} }
void test_PathCombine2() void test_PathCombine2()

View File

@ -23,6 +23,9 @@ slots:
QCOMPARE(Util::getDesktopDir(), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); 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() void test_createShortcut_data()
{ {
QTest::addColumn<QString>("location"); QTest::addColumn<QString>("location");
@ -40,7 +43,7 @@ slots:
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
<< MULTIMC_GET_TEST_FILE("data/tst_userutils-test_createShortcut-unix") << MULTIMC_GET_TEST_FILE("data/tst_userutils-test_createShortcut-unix")
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
<< QString() << QByteArray()
#endif #endif
; ;
} }
@ -59,8 +62,10 @@ slots:
//QDir().remove(location); //QDir().remove(location);
} }
#endif
}; };
QTEST_GUILESS_MAIN_MULTIMC(UserUtilsTest) QTEST_GUILESS_MAIN_MULTIMC(UserUtilsTest)
#include "tst_userutils.moc" #include "tst_userutils.moc"