Sync from quickmods

This commit is contained in:
Petr Mrázek 2014-09-06 18:16:56 +02:00
parent 36efcf8d3c
commit 20cb97a35a
57 changed files with 569 additions and 326 deletions

View File

@ -251,12 +251,12 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override) : QApplication(argc
std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory()));
for (auto profiler : m_profilers.values())
{
profiler->registerSettings(m_settings.get());
profiler->registerSettings(m_settings);
}
m_tools.insert("mcedit", std::shared_ptr<BaseDetachedToolFactory>(new MCEditFactory()));
for (auto tool : m_tools.values())
{
tool->registerSettings(m_settings.get());
tool->registerSettings(m_settings);
}
// launch instance, if that's what should be done

View File

@ -1,6 +1,8 @@
#pragma once
#include <QString>
#include <QList>
#include "libutil_config.h"
class QUrl;
@ -10,10 +12,12 @@ namespace Util
struct Version
{
Version(const QString &str);
Version() {}
bool operator<(const Version &other) const;
bool operator<=(const Version &other) const;
bool operator>(const Version &other) const;
bool operator>=(const Version &other) const;
bool operator==(const Version &other) const;
bool operator!=(const Version &other) const;
@ -24,9 +28,34 @@ struct Version
private:
QString m_string;
struct Section
{
explicit Section(const QString &str, const int num) : numValid(true), number(num), string(str) {}
explicit Section(const QString &str) : numValid(false), string(str) {}
explicit Section() {}
bool numValid;
int number;
QString string;
inline bool operator!=(const Section &other) const
{
return (numValid && other.numValid) ? (number != other.number) : (string != other.string);
}
inline bool operator<(const Section &other) const
{
return (numValid && other.numValid) ? (number < other.number) : (string < other.string);
}
inline bool operator>(const Section &other) const
{
return (numValid && other.numValid) ? (number > other.number) : (string > other.string);
}
};
QList<Section> m_sections;
void parse();
};
LIBUTIL_EXPORT QUrl expandQMURL(const QString &in);
LIBUTIL_EXPORT bool versionIsInInterval(const QString &version, const QString &interval);
LIBUTIL_EXPORT bool versionIsInInterval(const Version &version, const QString &interval);
}

View File

@ -7,42 +7,20 @@
Util::Version::Version(const QString &str) : m_string(str)
{
parse();
}
bool Util::Version::operator<(const Version &other) const
{
QStringList parts1 = m_string.split('.');
QStringList parts2 = other.m_string.split('.');
while (!parts1.isEmpty() && !parts2.isEmpty())
const int size = qMax(m_sections.size(), other.m_sections.size());
for (int i = 0; i < size; ++i)
{
QString part1 = parts1.isEmpty() ? "0" : parts1.takeFirst();
QString part2 = parts2.isEmpty() ? "0" : parts2.takeFirst();
bool ok1 = false;
bool ok2 = false;
int int1 = part1.toInt(&ok1);
int int2 = part2.toInt(&ok2);
if (ok1 && ok2)
const Section sec1 = (i >= m_sections.size()) ? Section("0", 0) : m_sections.at(i);
const Section sec2 =
(i >= other.m_sections.size()) ? Section("0", 0) : other.m_sections.at(i);
if (sec1 != sec2)
{
if (int1 == int2)
{
continue;
}
else
{
return int1 < int2;
}
}
else
{
if (part1 == part2)
{
continue;
}
else
{
return part1 < part2;
}
return sec1 < sec2;
}
}
@ -54,77 +32,35 @@ bool Util::Version::operator<=(const Util::Version &other) const
}
bool Util::Version::operator>(const Version &other) const
{
QStringList parts1 = m_string.split('.');
QStringList parts2 = other.m_string.split('.');
while (!parts1.isEmpty() && !parts2.isEmpty())
const int size = qMax(m_sections.size(), other.m_sections.size());
for (int i = 0; i < size; ++i)
{
QString part1 = parts1.isEmpty() ? "0" : parts1.takeFirst();
QString part2 = parts2.isEmpty() ? "0" : parts2.takeFirst();
bool ok1 = false;
bool ok2 = false;
int int1 = part1.toInt(&ok1);
int int2 = part2.toInt(&ok2);
if (ok1 && ok2)
const Section sec1 = (i >= m_sections.size()) ? Section("0", 0) : m_sections.at(i);
const Section sec2 =
(i >= other.m_sections.size()) ? Section("0", 0) : other.m_sections.at(i);
if (sec1 != sec2)
{
if (int1 == int2)
{
continue;
}
else
{
return int1 > int2;
}
}
else
{
if (part1 == part2)
{
continue;
}
else
{
return part1 > part2;
}
return sec1 > sec2;
}
}
return false;
}
bool Util::Version::operator>=(const Version &other) const
{
return *this > other || *this == other;
}
bool Util::Version::operator==(const Version &other) const
{
QStringList parts1 = m_string.split('.');
QStringList parts2 = other.m_string.split('.');
while (!parts1.isEmpty() && !parts2.isEmpty())
const int size = qMax(m_sections.size(), other.m_sections.size());
for (int i = 0; i < size; ++i)
{
QString part1 = parts1.isEmpty() ? "0" : parts1.takeFirst();
QString part2 = parts2.isEmpty() ? "0" : parts2.takeFirst();
bool ok1 = false;
bool ok2 = false;
int int1 = part1.toInt(&ok1);
int int2 = part2.toInt(&ok2);
if (ok1 && ok2)
const Section sec1 = (i >= m_sections.size()) ? Section("0", 0) : m_sections.at(i);
const Section sec2 =
(i >= other.m_sections.size()) ? Section("0", 0) : other.m_sections.at(i);
if (sec1 != sec2)
{
if (int1 == int2)
{
continue;
}
else
{
return false;
}
}
else
{
if (part1 == part2)
{
continue;
}
else
{
return false;
}
return false;
}
}
@ -135,45 +71,41 @@ bool Util::Version::operator!=(const Version &other) const
return !operator==(other);
}
QUrl Util::expandQMURL(const QString &in)
void Util::Version::parse()
{
QUrl inUrl(in);
if (inUrl.scheme() == "github")
m_sections.clear();
QStringList parts = m_string.split('.');
for (const auto part : parts)
{
// needed because QUrl makes the host all lower cases
const QString repo = in.mid(in.indexOf(inUrl.host(), 0, Qt::CaseInsensitive), inUrl.host().size());
QUrl out;
out.setScheme("https");
out.setHost("raw.github.com");
out.setPath(QString("/%1/%2/%3%4")
.arg(inUrl.userInfo(), repo,
inUrl.fragment().isEmpty() ? "master" : inUrl.fragment(), inUrl.path()));
return out;
}
else if (inUrl.scheme() == "mcf")
{
QUrl out;
out.setScheme("http");
out.setHost("www.minecraftforum.net");
out.setPath(QString("/topic/%1-").arg(inUrl.path()));
return out;
}
else
{
return in;
bool ok = false;
int num = part.toInt(&ok);
if (ok)
{
m_sections.append(Section(part, num));
}
else
{
m_sections.append(Section(part));
}
}
}
bool Util::versionIsInInterval(const QString &version, const QString &interval)
{
if (interval.isEmpty() || version == interval)
return versionIsInInterval(Util::Version(version), interval);
}
bool Util::versionIsInInterval(const Version &version, const QString &interval)
{
if (interval.isEmpty() || version.toString() == interval)
{
return true;
}
// Interval notation is used
QRegularExpression exp(
"(?<start>[\\[\\]\\(\\)])(?<bottom>.*?)(,(?<top>.*?))?(?<end>[\\[\\]\\(\\)])");
"(?<start>[\\[\\]\\(\\)])(?<bottom>.*?)(,(?<top>.*?))?(?<end>[\\[\\]\\(\\)]),?");
QRegularExpressionMatch match = exp.match(interval);
if (match.hasMatch())
{
@ -185,11 +117,12 @@ bool Util::versionIsInInterval(const QString &version, const QString &interval)
// check if in range (bottom)
if (!bottom.isEmpty())
{
if ((start == '[') && !(version >= bottom))
const auto bottomVersion = Util::Version(bottom);
if ((start == '[') && !(version >= bottomVersion))
{
return false;
}
else if ((start == '(') && !(version > bottom))
else if ((start == '(') && !(version > bottomVersion))
{
return false;
}
@ -198,11 +131,12 @@ bool Util::versionIsInInterval(const QString &version, const QString &interval)
// check if in range (top)
if (!top.isEmpty())
{
if ((end == ']') && !(version <= top))
const auto topVersion = Util::Version(top);
if ((end == ']') && !(version <= topVersion))
{
return false;
}
else if ((end == ')') && !(version < top))
else if ((end == ')') && !(version < topVersion))
{
return false;
}

View File

@ -65,9 +65,9 @@
#include "gui/pages/global/MultiMCPage.h"
#include "gui/pages/global/ExternalToolsPage.h"
#include "gui/pages/global/AccountListPage.h"
#include "pages/global/ProxyPage.h"
#include "pages/global/JavaPage.h"
#include "pages/global/MinecraftPage.h"
#include "gui/pages/global/ProxyPage.h"
#include "gui/pages/global/JavaPage.h"
#include "gui/pages/global/MinecraftPage.h"
#include "gui/ConsoleWindow.h"
#include "pagedialog/PageDialog.h"
@ -91,6 +91,7 @@
#include "logic/net/NetJob.h"
#include "logic/BaseInstance.h"
#include "logic/OneSixInstance.h"
#include "logic/InstanceFactory.h"
#include "logic/MinecraftProcess.h"
#include "logic/OneSixUpdate.h"

View File

@ -387,7 +387,7 @@
</action>
<action name="actionEditInstance">
<property name="text">
<string>Edit Mods</string>
<string>Edit Instance</string>
</property>
<property name="iconText">
<string>Edit Instance</string>

View File

@ -4,7 +4,7 @@
bool lastfirst(QModelIndexList &list, int &first, int &last)
{
if (!list.size())
if (list.isEmpty())
return false;
first = last = list[0].row();
for (auto item : list)
@ -37,4 +37,4 @@ void showWebsiteForMod(QWidget *parentDlg, Mod &m)
QObject::tr("The mod author didn't provide a website link for this mod."),
QMessageBox::Warning);
}
}
}

View File

@ -38,15 +38,6 @@ NewInstanceDialog::NewInstanceDialog(QWidget *parent)
ui->setupUi(this);
resize(minimumSizeHint());
layout()->setSizeConstraint(QLayout::SetFixedSize);
/*
if (!MinecraftVersionList::getMainList().isLoaded())
{
TaskDialog *taskDlg = new TaskDialog(this);
Task *loadTask = MinecraftVersionList::getMainList().getLoadTask();
loadTask->setParent(taskDlg);
taskDlg->exec(loadTask);
}
*/
setSelectedVersion(MMC->minecraftlist()->getLatestStable(), true);
InstIconKey = "infinity";
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));

View File

@ -16,6 +16,7 @@
#pragma once
#include <QDialog>
#include "logic/BaseVersion.h"
namespace Ui

View File

@ -113,16 +113,10 @@ void drawProgressOverlay(QPainter *painter, const QStyleOptionViewItemV4 &option
void drawBadges(QPainter *painter, const QStyleOptionViewItemV4 &option, BaseInstance *instance)
{
QList<QString> pixmaps;
for (auto flag : instance->flags())
const BaseInstance::InstanceFlags flags = instance->flags();
if (flags & BaseInstance::VersionBrokenFlag)
{
switch (flag)
{
case BaseInstance::VersionBrokenFlag:
pixmaps.append("broken");
break;
default:
break;
}
pixmaps.append("broken");
}
// begin easter eggs
@ -160,7 +154,7 @@ void drawBadges(QPainter *painter, const QStyleOptionViewItemV4 &option, BaseIns
{
return;
}
const QPixmap pixmap = ListViewDelegate::requestPixmap(it.next()).scaled(
const QPixmap pixmap = ListViewDelegate::requestBadgePixmap(it.next()).scaled(
itemSide, itemSide, Qt::KeepAspectRatio, Qt::FastTransformation);
painter->drawPixmap(option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide,
y * itemSide + qMax(y - 1, 0) * spacing, itemSide, itemSide,
@ -354,7 +348,7 @@ QSize ListViewDelegate::sizeHint(const QStyleOptionViewItem &option,
return sz;
}
QPixmap ListViewDelegate::requestPixmap(const QString &key)
QPixmap ListViewDelegate::requestBadgePixmap(const QString &key)
{
if (!m_pixmapCache.contains(key))
{

View File

@ -23,7 +23,7 @@ class ListViewDelegate : public QStyledItemDelegate
public:
explicit ListViewDelegate(QObject *parent = 0);
static QPixmap requestPixmap(const QString &key);
static QPixmap requestBadgePixmap(const QString &key);
protected:
void paint(QPainter *painter, const QStyleOptionViewItem &option,

View File

@ -29,6 +29,7 @@
#include <cmdutils.h>
#include "logic/minecraft/MinecraftVersionList.h"
#include "logic/icons/IconList.h"
#include "logic/InstanceList.h"
BaseInstance::BaseInstance(BaseInstancePrivate *d_in, const QString &rootDir,
SettingsObject *settings_obj, QObject *parent)
@ -143,10 +144,12 @@ QString BaseInstance::minecraftRoot() const
InstanceList *BaseInstance::instList() const
{
if (parent()->inherits("InstanceList"))
return (InstanceList *)parent();
else
return NULL;
return qobject_cast<InstanceList *>(parent());
}
InstancePtr BaseInstance::getSharedPtr()
{
return instList()->getInstanceById(id());
}
std::shared_ptr<BaseVersionList> BaseInstance::versionList() const
@ -160,13 +163,12 @@ SettingsObject &BaseInstance::settings() const
return *d->m_settings;
}
QSet<BaseInstance::InstanceFlag> BaseInstance::flags() const
BaseInstance::InstanceFlags BaseInstance::flags() const
{
I_D(const BaseInstance);
return QSet<InstanceFlag>(d->m_flags);
return d->m_flags;
}
void BaseInstance::setFlags(const QSet<InstanceFlag> &flags)
void BaseInstance::setFlags(const InstanceFlags &flags)
{
I_D(BaseInstance);
if (flags != d->m_flags)
@ -176,10 +178,24 @@ void BaseInstance::setFlags(const QSet<InstanceFlag> &flags)
emit propertiesChanged(this);
}
}
void BaseInstance::setFlag(const BaseInstance::InstanceFlag flag)
{
I_D(BaseInstance);
d->m_flags |= flag;
emit flagsChanged();
emit propertiesChanged(this);
}
void BaseInstance::unsetFlag(const BaseInstance::InstanceFlag flag)
{
I_D(BaseInstance);
d->m_flags &= ~flag;
emit flagsChanged();
emit propertiesChanged(this);
}
bool BaseInstance::canLaunch() const
{
return !flags().contains(VersionBrokenFlag);
return !(flags() & VersionBrokenFlag);
}
bool BaseInstance::reload()

View File

@ -34,6 +34,10 @@ class OneSixUpdate;
class InstanceList;
class BaseInstancePrivate;
// pointer for lazy people
class BaseInstance;
typedef std::shared_ptr<BaseInstance> InstancePtr;
/*!
* \brief Base class for instances.
* This class implements many functions that are common between instances and
@ -163,6 +167,8 @@ public:
*/
InstanceList *instList() const;
InstancePtr getSharedPtr();
/*!
* \brief Gets a pointer to this instance's version list.
* \return A pointer to the available version list for this instance.
@ -193,11 +199,14 @@ public:
enum InstanceFlag
{
NoFlags = 0x00,
VersionBrokenFlag = 0x01
VersionBrokenFlag = 0x01,
UpdateAvailable = 0x02
};
QSet<InstanceFlag> flags() const;
void setFlags(const QSet<InstanceFlag> &flags);
Q_DECLARE_FLAGS(InstanceFlags, InstanceFlag)
InstanceFlags flags() const;
void setFlags(const InstanceFlags &flags);
void setFlag(const InstanceFlag flag);
void unsetFlag(const InstanceFlag flag);
bool canLaunch() const;
@ -226,7 +235,6 @@ protected:
std::shared_ptr<BaseInstancePrivate> inst_d;
};
// pointer for lazy people
typedef std::shared_ptr<BaseInstance> InstancePtr;
Q_DECLARE_METATYPE(std::shared_ptr<BaseInstance>)
Q_DECLARE_METATYPE(BaseInstance::InstanceFlag)
Q_DECLARE_OPERATORS_FOR_FLAGS(BaseInstance::InstanceFlags)

View File

@ -31,6 +31,6 @@ public:
QString m_rootDir;
QString m_group;
std::shared_ptr<SettingsObject> m_settings;
QSet<BaseInstance::InstanceFlag> m_flags;
BaseInstance::InstanceFlags m_flags;
bool m_isRunning = false;
};

View File

@ -24,6 +24,7 @@
*/
struct BaseVersion
{
virtual ~BaseVersion() {}
/*!
* A string used to identify this version in config files.
* This should be unique within the version list or shenanigans will occur.

View File

@ -52,19 +52,19 @@ InstanceFactory::InstLoadError InstanceFactory::loadInstance(InstancePtr &inst,
// FIXME: replace with a map lookup, where instance classes register their types
if (inst_type == "OneSix" || inst_type == "Nostalgia")
{
inst.reset(new OneSixInstance(instDir, m_settings, this));
inst.reset(new OneSixInstance(instDir, m_settings));
}
else if (inst_type == "Legacy")
{
inst.reset(new LegacyInstance(instDir, m_settings, this));
inst.reset(new LegacyInstance(instDir, m_settings));
}
else if (inst_type == "LegacyFTB")
{
inst.reset(new LegacyFTBInstance(instDir, m_settings, this));
inst.reset(new LegacyFTBInstance(instDir, m_settings));
}
else if (inst_type == "OneSixFTB")
{
inst.reset(new OneSixFTBInstance(instDir, m_settings, this));
inst.reset(new OneSixFTBInstance(instDir, m_settings));
}
else
{
@ -82,11 +82,15 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(InstancePtr &in
QLOG_DEBUG() << instDir.toUtf8();
if (!rootDir.exists() && !rootDir.mkpath("."))
{
QLOG_ERROR() << "Can't create instance folder" << instDir;
return InstanceFactory::CantCreateDir;
}
auto mcVer = std::dynamic_pointer_cast<MinecraftVersion>(version);
if (!mcVer)
{
QLOG_ERROR() << "Can't create instance for non-existing MC version";
return InstanceFactory::NoSuchVersion;
}
auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg"));
m_settings->registerSetting("InstanceType", "Legacy");
@ -94,7 +98,7 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(InstancePtr &in
if (type == NormalInst)
{
m_settings->set("InstanceType", "OneSix");
inst.reset(new OneSixInstance(instDir, m_settings, this));
inst.reset(new OneSixInstance(instDir, m_settings));
inst->setIntendedVersionId(version->descriptor());
inst->setShouldUseCustomBaseJar(false);
}
@ -103,14 +107,14 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(InstancePtr &in
if(mcVer->usesLegacyLauncher())
{
m_settings->set("InstanceType", "LegacyFTB");
inst.reset(new LegacyFTBInstance(instDir, m_settings, this));
inst.reset(new LegacyFTBInstance(instDir, m_settings));
inst->setIntendedVersionId(version->descriptor());
inst->setShouldUseCustomBaseJar(false);
}
else
{
m_settings->set("InstanceType", "OneSixFTB");
inst.reset(new OneSixFTBInstance(instDir, m_settings, this));
inst.reset(new OneSixFTBInstance(instDir, m_settings));
inst->setIntendedVersionId(version->descriptor());
inst->setShouldUseCustomBaseJar(false);
}

View File

@ -26,7 +26,7 @@ struct BaseVersion;
class BaseInstance;
/*!
* The \bInstanceFactory\b is a singleton that manages loading and creating instances.
* The \b InstanceFactory\b is a singleton that manages loading and creating instances.
*/
class InstanceFactory : public QObject
{

View File

@ -7,7 +7,7 @@ LegacyFTBInstance::LegacyFTBInstance(const QString &rootDir, SettingsObject *set
QString LegacyFTBInstance::getStatusbarDescription()
{
if (flags().contains(VersionBrokenFlag))
if (flags() & VersionBrokenFlag)
{
return "Legacy FTB: " + intendedVersionId() + " (broken)";
}

View File

@ -287,7 +287,7 @@ QString LegacyInstance::defaultCustomBaseJar() const
QString LegacyInstance::getStatusbarDescription()
{
if (flags().contains(VersionBrokenFlag))
if (flags() & VersionBrokenFlag)
{
return tr("Legacy : %1 (broken)").arg(intendedVersionId());
}

View File

@ -1,13 +1,26 @@
#include "MMCJson.h"
#include <QString>
#include <QUrl>
#include <QStringList>
#include <math.h>
QJsonDocument MMCJson::parseDocument(const QByteArray &data, const QString &what)
{
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError)
{
throw JSONValidationError(what + " is not valid JSON: " + error.errorString() + " at " + error.offset);
}
return doc;
}
bool MMCJson::ensureBoolean(const QJsonValue val, const QString what)
{
if (!val.isBool())
throw JSONValidationError(what + " is not boolean");
return val.isBool();
return val.toBool();
}
QJsonValue MMCJson::ensureExists(QJsonValue val, const QString what)
@ -24,6 +37,15 @@ QJsonArray MMCJson::ensureArray(const QJsonValue val, const QString what)
return val.toArray();
}
QJsonArray MMCJson::ensureArray(const QJsonDocument &val, const QString &what)
{
if (!val.isArray())
{
throw JSONValidationError(what + " is not an array");
}
return val.array();
}
double MMCJson::ensureDouble(const QJsonValue val, const QString what)
{
if (!val.isDouble())
@ -60,9 +82,36 @@ QString MMCJson::ensureString(const QJsonValue val, const QString what)
return val.toString();
}
QUrl MMCJson::ensureUrl(const QJsonValue &val, const QString &what)
{
const QUrl url = QUrl(ensureString(val, what));
if (!url.isValid())
{
throw JSONValidationError(what + " is not an url");
}
return url;
}
QJsonDocument MMCJson::parseFile(const QString &filename, const QString &what)
{
QFile f(filename);
if (!f.open(QFile::ReadOnly))
{
throw FileOpenError(f);
}
return parseDocument(f.readAll(), what);
}
int MMCJson::ensureInteger(const QJsonValue val, QString what, const int def)
{
if (val.isUndefined())
return def;
return ensureInteger(val, what);
}
void MMCJson::writeString(QJsonObject &to, QString key, QString value)
{
if(value.size())
if (!value.isEmpty())
{
to.insert(key, value);
}
@ -70,7 +119,7 @@ void MMCJson::writeString(QJsonObject &to, QString key, QString value)
void MMCJson::writeStringList(QJsonObject &to, QString key, QStringList values)
{
if(values.size())
if (!values.isEmpty())
{
QJsonArray array;
for(auto value: values)
@ -81,3 +130,13 @@ void MMCJson::writeStringList(QJsonObject &to, QString key, QStringList values)
}
}
QStringList MMCJson::ensureStringList(const QJsonValue val, QString what)
{
const QJsonArray array = ensureArray(val, what);
QStringList out;
for (const auto value : array)
{
out.append(ensureString(value));
}
return out;
}

View File

@ -9,17 +9,29 @@
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
#include <QFile>
#include <memory>
#include "MMCError.h"
class JSONValidationError : public MMCError
{
public:
JSONValidationError(QString cause) : MMCError(cause) {};
virtual ~JSONValidationError() noexcept {}
JSONValidationError(QString cause) : MMCError(cause) {}
};
class FileOpenError : public MMCError
{
public:
FileOpenError(const QFile &file) : MMCError(QObject::tr("Error opening %1: %2").arg(file.fileName(), file.errorString())) {}
};
namespace MMCJson
{
/// parses the data into a json document. throws if there's a parse error
QJsonDocument parseDocument(const QByteArray &data, const QString &what);
/// tries to open and then parses the specified file. throws if there's an error
QJsonDocument parseFile(const QString &filename, const QString &what);
/// make sure the value exists. throw otherwise.
QJsonValue ensureExists(QJsonValue val, const QString what = "value");
@ -27,39 +39,63 @@ QJsonValue ensureExists(QJsonValue val, const QString what = "value");
QJsonObject ensureObject(const QJsonValue val, const QString what = "value");
/// make sure the document is converted into an object. throw otherwise.
QJsonObject ensureObject(const QJsonDocument val, const QString what = "value");
QJsonObject ensureObject(const QJsonDocument val, const QString what = "document");
/// make sure the value is converted into an array. throw otherwise.
QJsonArray ensureArray(const QJsonValue val, QString what = "value");
/// make sure the document is converted into an array. throw otherwise.
QJsonArray ensureArray(const QJsonDocument &val, const QString &what = "document");
/// make sure the value is converted into a string. throw otherwise.
QString ensureString(const QJsonValue val, QString what = "value");
/// make sure the value is converted into a string that's parseable as an url. throw otherwise.
QUrl ensureUrl(const QJsonValue &val, const QString &what = "value");
/// make sure the value is converted into a boolean. throw otherwise.
bool ensureBoolean(const QJsonValue val, QString what = "value");
/// make sure the value is converted into an integer. throw otherwise.
int ensureInteger(const QJsonValue val, QString what = "value");
/// make sure the value is converted into an integer. throw otherwise. this version will return the default value if the field is undefined.
int ensureInteger(const QJsonValue val, QString what, const int def);
/// make sure the value is converted into a double precision floating number. throw otherwise.
double ensureDouble(const QJsonValue val, QString what = "value");
QStringList ensureStringList(const QJsonValue val, QString what);
void writeString(QJsonObject & to, QString key, QString value);
void writeStringList (QJsonObject & to, QString key, QStringList values);
void writeStringList(QJsonObject & to, QString key, QStringList values);
template <typename T>
void writeObjectList (QJsonObject & to, QString key, QList<T> values)
void writeObjectList(QJsonObject & to, QString key, QList<std::shared_ptr<T>> values)
{
if(values.size())
if (!values.isEmpty())
{
QJsonArray array;
for(auto value: values)
for (auto value: values)
{
array.append(value->toJson());
}
to.insert(key, array);
}
}
template <typename T>
void writeObjectList(QJsonObject & to, QString key, QList<T> values)
{
if (!values.isEmpty())
{
QJsonArray array;
for (auto value: values)
{
array.append(value.toJson());
}
to.insert(key, array);
}
}
}

View File

@ -118,7 +118,7 @@ bool OneSixFTBInstance::providesVersionFile() const
QString OneSixFTBInstance::getStatusbarDescription()
{
if (flags().contains(VersionBrokenFlag))
if (flags() & VersionBrokenFlag)
{
return "OneSix FTB: " + intendedVersionId() + " (broken)";
}

View File

@ -418,7 +418,7 @@ void OneSixInstance::reloadVersion()
try
{
d->version->reload(externalPatches());
d->m_flags.remove(VersionBrokenFlag);
unsetFlag(VersionBrokenFlag);
emit versionReloaded();
}
catch (VersionIncomplete &error)
@ -427,7 +427,7 @@ void OneSixInstance::reloadVersion()
catch (MMCError &error)
{
d->version->clear();
d->m_flags.insert(VersionBrokenFlag);
setFlag(VersionBrokenFlag);
// TODO: rethrow to show some error message(s)?
emit versionReloaded();
throw;
@ -464,7 +464,7 @@ QString OneSixInstance::getStatusbarDescription()
{
traits.append(tr("custom"));
}
if (flags().contains(VersionBrokenFlag))
if (flags() & VersionBrokenFlag)
{
traits.append(tr("broken"));
}
@ -569,3 +569,8 @@ QStringList OneSixInstance::extraArguments() const
}
return list;
}
std::shared_ptr<OneSixInstance> OneSixInstance::getSharedPtr()
{
return std::dynamic_pointer_cast<OneSixInstance>(BaseInstance::getSharedPtr());
}

View File

@ -96,8 +96,11 @@ public:
virtual bool providesVersionFile() const;
bool reload() override;
virtual QStringList extraArguments() const override;
std::shared_ptr<OneSixInstance> getSharedPtr();
signals:
void versionReloaded();
@ -105,3 +108,5 @@ private:
QStringList processMinecraftArgs(AuthSessionPtr account);
QDir reconstructAssets(std::shared_ptr<InstanceVersion> version);
};
Q_DECLARE_METATYPE(std::shared_ptr<OneSixInstance>)

View File

@ -29,11 +29,11 @@ class ForgeInstaller : public BaseInstaller
friend class ForgeInstallTask;
public:
ForgeInstaller();
virtual ~ForgeInstaller(){};
virtual ~ForgeInstaller(){}
virtual ProgressProvider *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) override;
virtual QString id() const override { return "net.minecraftforge"; }
protected:
virtual QString id() const override { return "net.minecraftforge"; }
void prepare(const QString &filename, const QString &universalUrl);
bool add(OneSixInstance *to) override;
bool addLegacy(OneSixInstance *to);

View File

@ -38,3 +38,5 @@ struct ForgeVersion : public BaseVersion
QString installer_filename;
bool is_recommended = false;
};
Q_DECLARE_METATYPE(ForgeVersionPtr)

View File

@ -59,22 +59,10 @@ public:
{
return javacheckers.size();
}
virtual void getProgress(qint64 &current, qint64 &total)
{
current = current_progress;
total = total_progress;
}
;
virtual QString getStatus() const
{
return m_job_name;
}
;
virtual bool isRunning() const
{
return m_running;
}
;
signals:
void started();

View File

@ -28,13 +28,10 @@ public:
void prepare(LiteLoaderVersionPtr version);
bool add(OneSixInstance *to) override;
virtual QString id() const override { return "com.mumfrey.liteloader"; }
ProgressProvider *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) override;
private:
virtual QString id() const override
{
return "com.mumfrey.liteloader";
}
LiteLoaderVersionPtr m_version;
};

View File

@ -111,3 +111,5 @@ protected:
CacheDownloadPtr listDownload;
LiteLoaderVersionList *m_list;
};
Q_DECLARE_METATYPE(LiteLoaderVersionPtr)

View File

@ -264,6 +264,14 @@ QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNormalLibs()
{
if (lib->isActive() && !lib->isNative())
{
for (auto other : output)
{
if (other->rawName() == lib->rawName())
{
QLOG_WARN() << "Multiple libraries with name" << lib->rawName() << "in library list!";
continue;
}
}
output.append(lib);
}
}

View File

@ -140,10 +140,10 @@ public:
QString appletClass;
/// the list of libs - both active and inactive, native and java
QList<std::shared_ptr<OneSixLibrary>> libraries;
QList<OneSixLibraryPtr> libraries;
/// same, but only vanilla.
QList<std::shared_ptr<OneSixLibrary>> vanillaLibraries;
QList<OneSixLibraryPtr> vanillaLibraries;
/// traits, collected from all the version files (version files can only add)
QSet<QString> traits;

View File

@ -116,15 +116,10 @@ void MinecraftVersionList::loadBuiltinList()
{
QLOG_INFO() << "Loading builtin version list.";
// grab the version list data from internal resources.
QResource versionList(":/versions/minecraft.json");
QFile filez(versionList.absoluteFilePath());
filez.open(QIODevice::ReadOnly);
auto data = filez.readAll();
// parse the data as json
QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
QJsonObject root = jsonDoc.object();
const QJsonDocument doc =
MMCJson::parseFile(":/versions/minecraft.json",
"builtin version list");
const QJsonObject root = doc.object();
// parse all the versions
for (const auto version : MMCJson::ensureArray(root.value("versions")))

View File

@ -48,5 +48,4 @@ public:
/// Constructor
OneSixLibrary(RawLibraryPtr base);
static OneSixLibraryPtr fromRawLibrary(RawLibraryPtr lib);
};

View File

@ -288,6 +288,11 @@ static const int currentOrderFileVersion = 1;
bool VersionBuilder::readOverrideOrders(OneSixInstance *instance, PatchOrder &order)
{
QFile orderFile(instance->instanceRoot() + "/order.json");
if (!orderFile.exists())
{
QLOG_WARN() << "Order file doesn't exist. Ignoring.";
return false;
}
if (!orderFile.open(QFile::ReadOnly))
{
QLOG_ERROR() << "Couldn't open" << orderFile.fileName()

View File

@ -22,8 +22,7 @@ int findLibraryByName(QList<OneSixLibraryPtr> haystack, const GradleSpecifier &n
int retval = -1;
for (int i = 0; i < haystack.size(); ++i)
{
if(haystack.at(i)->rawName().matchName(needle))
if (haystack.at(i)->rawName().matchName(needle))
{
// only one is allowed.
if (retval != -1)
@ -67,7 +66,7 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
out->mcVersion = root.value("mcVersion").toString();
out->filename = filename;
auto readString = [root](const QString & key, QString & variable)
auto readString = [root](const QString &key, QString &variable)
{
if (root.contains(key))
{
@ -75,15 +74,14 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
}
};
auto readStringRet = [root](const QString & key)->QString
auto readStringRet = [root](const QString &key) -> QString
{
if (root.contains(key))
{
return ensureString(root.value(key));
}
return QString();
}
;
};
// FIXME: This should be ignored when applying.
if (!isFTB)

View File

@ -53,16 +53,42 @@ void ByteArrayDownload::downloadError(QNetworkReply::NetworkError error)
QLOG_ERROR() << "Error getting URL:" << m_url.toString().toLocal8Bit()
<< "Network error: " << error;
m_status = Job_Failed;
m_errorString = m_reply->errorString();
}
void ByteArrayDownload::downloadFinished()
{
if (m_followRedirects)
{
QVariant redirect = m_reply->header(QNetworkRequest::LocationHeader);
QString redirectURL;
if(redirect.isValid())
{
redirectURL = redirect.toString();
}
// FIXME: This is a hack for https://bugreports.qt-project.org/browse/QTBUG-41061
else if(m_reply->hasRawHeader("Location"))
{
auto data = m_reply->rawHeader("Location");
if(data.size() > 2 && data[0] == '/' && data[1] == '/')
redirectURL = m_reply->url().scheme() + ":" + data;
}
if (!redirectURL.isEmpty())
{
m_url = QUrl(redirect.toString());
QLOG_INFO() << "Following redirect to " << m_url.toString();
start();
return;
}
}
// if the download succeeded
if (m_status != Job_Failed)
{
// nothing went wrong...
m_status = Job_Finished;
m_data = m_reply->readAll();
m_content_type = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
m_reply.reset();
emit succeeded(m_index_within_job);
return;

View File

@ -31,6 +31,10 @@ public:
/// if not saving to file, downloaded data is placed here
QByteArray m_data;
QString m_errorString;
bool m_followRedirects = false;
public
slots:
virtual void start();

View File

@ -101,6 +101,30 @@ void CacheDownload::downloadError(QNetworkReply::NetworkError error)
}
void CacheDownload::downloadFinished()
{
if (m_followRedirects)
{
QVariant redirect = m_reply->header(QNetworkRequest::LocationHeader);
QString redirectURL;
if(redirect.isValid())
{
redirectURL = redirect.toString();
}
// FIXME: This is a hack for https://bugreports.qt-project.org/browse/QTBUG-41061
else if(m_reply->hasRawHeader("Location"))
{
auto data = m_reply->rawHeader("Location");
if(data.size() > 2 && data[0] == '/' && data[1] == '/')
redirectURL = m_reply->url().scheme() + ":" + data;
}
if (!redirectURL.isEmpty())
{
m_url = QUrl(redirect.toString());
QLOG_INFO() << "Following redirect to " << m_url.toString();
start();
return;
}
}
// if the download succeeded
if (m_status == Job_Failed)
{

View File

@ -36,6 +36,8 @@ private:
bool wroteAnyData = false;
public:
bool m_followRedirects = false;
explicit CacheDownload(QUrl url, MetaEntryPtr entry);
static CacheDownloadPtr make(QUrl url, MetaEntryPtr entry)
{

View File

@ -55,6 +55,9 @@ public:
/// the network reply
std::shared_ptr<QNetworkReply> m_reply;
/// the content of the content-type header
QString m_content_type;
/// source URL
QUrl m_url;

View File

@ -30,8 +30,8 @@ class NetJob : public ProgressProvider
{
Q_OBJECT
public:
explicit NetJob(QString job_name) : ProgressProvider(), m_job_name(job_name) {};
virtual ~NetJob() {};
explicit NetJob(QString job_name) : ProgressProvider(), m_job_name(job_name) {}
virtual ~NetJob() {}
template <typename T> bool addNetAction(T action)
{
NetActionPtr base = std::static_pointer_cast<NetAction>(action);
@ -62,7 +62,10 @@ public:
{
return downloads[index];
}
;
const NetActionPtr at(const int index)
{
return downloads.at(index);
}
NetActionPtr first()
{
if (downloads.size())
@ -73,21 +76,10 @@ public:
{
return downloads.size();
}
virtual void getProgress(qint64 &current, qint64 &total)
{
current = current_progress;
total = total_progress;
}
;
virtual QString getStatus() const
{
return m_job_name;
}
virtual bool isRunning() const
{
return m_running;
}
;
QStringList getFailedFiles();
signals:
void started();

View File

@ -32,9 +32,7 @@ signals:
void status(QString status);
public:
virtual ~ProgressProvider() {};
virtual QString getStatus() const = 0;
virtual void getProgress(qint64 &current, qint64 &total) = 0;
virtual ~ProgressProvider() {}
virtual bool isRunning() const = 0;
public
slots:

View File

@ -1,31 +1,7 @@
#include "SequentialTask.h"
SequentialTask::SequentialTask(QObject *parent) :
Task(parent), m_currentIndex(-1)
SequentialTask::SequentialTask(QObject *parent) : Task(parent), m_currentIndex(-1)
{
}
QString SequentialTask::getStatus() const
{
if (m_queue.isEmpty() || m_currentIndex >= m_queue.size())
{
return QString();
}
return m_queue.at(m_currentIndex)->getStatus();
}
void SequentialTask::getProgress(qint64 &current, qint64 &total)
{
current = 0;
total = 0;
for (int i = 0; i < m_queue.size(); ++i)
{
qint64 subCurrent, subTotal;
m_queue.at(i)->getProgress(subCurrent, subTotal);
current += subCurrent;
total += subTotal;
}
}
void SequentialTask::addTask(std::shared_ptr<ProgressProvider> task)
@ -55,10 +31,9 @@ void SequentialTask::startNext()
std::shared_ptr<ProgressProvider> next = m_queue[m_currentIndex];
connect(next.get(), SIGNAL(failed(QString)), this, SLOT(subTaskFailed(QString)));
connect(next.get(), SIGNAL(status(QString)), this, SLOT(subTaskStatus(QString)));
connect(next.get(), SIGNAL(progress(qint64,qint64)), this, SLOT(subTaskProgress()));
connect(next.get(), SIGNAL(progress(qint64, qint64)), this, SLOT(subTaskProgress(qint64, qint64)));
connect(next.get(), SIGNAL(succeeded()), this, SLOT(startNext()));
next->start();
emit status(getStatus());
}
void SequentialTask::subTaskFailed(const QString &msg)
@ -69,16 +44,16 @@ void SequentialTask::subTaskStatus(const QString &msg)
{
setStatus(msg);
}
void SequentialTask::subTaskProgress()
void SequentialTask::subTaskProgress(qint64 current, qint64 total)
{
qint64 current, total;
getProgress(current, total);
if (total == 0)
if(total == 0)
{
setProgress(0);
return;
}
else
{
setProgress(100 * current / total);
}
auto dcurrent = (double) current;
auto dtotal = (double) total;
auto partial = ((dcurrent / dtotal) * 100.0f)/* / double(m_queue.size())*/;
// auto bigpartial = double(m_currentIndex) * 100.0f / double(m_queue.size());
setProgress(partial);
}

View File

@ -11,9 +11,6 @@ class SequentialTask : public Task
public:
explicit SequentialTask(QObject *parent = 0);
virtual QString getStatus() const;
virtual void getProgress(qint64 &current, qint64 &total);
void addTask(std::shared_ptr<ProgressProvider> task);
protected:
@ -24,7 +21,7 @@ slots:
void startNext();
void subTaskFailed(const QString &msg);
void subTaskStatus(const QString &msg);
void subTaskProgress();
void subTaskProgress(qint64 current, qint64 total);
private:
QQueue<std::shared_ptr<ProgressProvider> > m_queue;

View File

@ -20,29 +20,16 @@ Task::Task(QObject *parent) : ProgressProvider(parent)
{
}
QString Task::getStatus() const
{
return m_statusString;
}
void Task::setStatus(const QString &new_status)
{
m_statusString = new_status;
emit status(new_status);
}
void Task::setProgress(int new_progress)
{
m_progress = new_progress;
emit progress(new_progress, 100);
}
void Task::getProgress(qint64 &current, qint64 &total)
{
current = m_progress;
total = 100;
}
void Task::start()
{
m_running = true;
@ -61,6 +48,7 @@ void Task::emitFailed(QString reason)
void Task::emitSucceeded()
{
if (!m_running) { return; } // Don't succeed twice.
m_running = false;
m_succeeded = true;
QLOG_INFO() << "Task succeeded";

View File

@ -26,8 +26,6 @@ public:
explicit Task(QObject *parent = 0);
virtual ~Task() {};
virtual QString getStatus() const;
virtual void getProgress(qint64 &current, qint64 &total);
virtual bool isRunning() const;
/*!
@ -50,6 +48,7 @@ slots:
protected:
virtual void executeTask() = 0;
protected slots:
virtual void emitSucceeded();
virtual void emitFailed(QString reason);
@ -59,9 +58,8 @@ slots:
void setProgress(int progress);
protected:
QString m_statusString;
int m_progress = 0;
bool m_running = false;
bool m_succeeded = false;
QString m_failReason = "";
};

View File

@ -43,7 +43,7 @@ public:
virtual QString name() const = 0;
virtual void registerSettings(SettingsObject *settings) = 0;
virtual void registerSettings(std::shared_ptr<SettingsObject> settings) = 0;
virtual BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) = 0;

View File

@ -40,7 +40,7 @@ void JProfiler::beginProfilingImpl(MinecraftProcess *process)
m_profilerProcess = profiler;
}
void JProfilerFactory::registerSettings(SettingsObject *settings)
void JProfilerFactory::registerSettings(std::shared_ptr<SettingsObject> settings)
{
settings->registerSetting("JProfilerPath");
settings->registerSetting("JProfilerPort", 42042);

View File

@ -16,7 +16,7 @@ class JProfilerFactory : public BaseProfilerFactory
{
public:
QString name() const override { return "JProfiler"; }
void registerSettings(SettingsObject *settings) override;
void registerSettings(std::shared_ptr<SettingsObject> settings) override;
BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) override;
bool check(QString *error) override;
bool check(const QString &path, QString *error) override;

View File

@ -37,7 +37,7 @@ void JVisualVM::beginProfilingImpl(MinecraftProcess *process)
m_profilerProcess = profiler;
}
void JVisualVMFactory::registerSettings(SettingsObject *settings)
void JVisualVMFactory::registerSettings(std::shared_ptr<SettingsObject> settings)
{
QString defaultValue = QStandardPaths::findExecutable("jvisualvm");
if (defaultValue.isNull())

View File

@ -16,7 +16,7 @@ class JVisualVMFactory : public BaseProfilerFactory
{
public:
QString name() const override { return "JVisualVM"; }
void registerSettings(SettingsObject *settings) override;
void registerSettings(std::shared_ptr<SettingsObject> settings) override;
BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) override;
bool check(QString *error) override;
bool check(const QString &path, QString *error) override;

View File

@ -43,7 +43,7 @@ void MCEditTool::runImpl()
#endif
}
void MCEditFactory::registerSettings(SettingsObject *settings)
void MCEditFactory::registerSettings(std::shared_ptr<SettingsObject> settings)
{
settings->registerSetting("MCEditPath");
}

View File

@ -16,7 +16,7 @@ class MCEditFactory : public BaseDetachedToolFactory
{
public:
QString name() const override { return "MCEdit"; }
void registerSettings(SettingsObject *settings) override;
void registerSettings(std::shared_ptr<SettingsObject> settings) override;
BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) override;
bool check(QString *error) override;
bool check(const QString &path, QString *error) override;

View File

@ -38,6 +38,9 @@
<file>herobrine.png</file>
<file>derp.png</file>
<!-- Update. GPLv2, https://code.google.com/p/gnome-colors/ -->
<file>updateavailable.png</file>
<!-- Source: http://www.iconarchive.com/show/cat-icons-by-fasticon/Cat-Brown-icon.html -->
<file>kitten.png</file>
<!-- Source: http://www.iconarchive.com/show/crystal-clear-icons-by-everaldo/Filesystem-file-broken-icon.html -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -24,6 +24,7 @@ endmacro()
add_unit_test(pathutils tst_pathutils.cpp)
add_unit_test(gradlespecifier tst_gradlespecifier.cpp)
add_unit_test(userutils tst_userutils.cpp)
add_unit_test(modutils tst_modutils.cpp)
add_unit_test(inifile tst_inifile.cpp)
add_unit_test(UpdateChecker tst_UpdateChecker.cpp)
add_unit_test(DownloadUpdateTask tst_DownloadUpdateTask.cpp)

View File

@ -9,29 +9,30 @@
#include "test_config.h"
struct TestsInternal
class TestsInternal
{
static QByteArray readFile(const QString &fileName)
{
QFile f(fileName);
f.open(QFile::ReadOnly);
return f.readAll();
}
static QString readFileUtf8(const QString &fileName)
{
return QString::fromUtf8(readFile(fileName));
}
public:
static QByteArray readFile(const QString &fileName)
{
QFile f(fileName);
f.open(QFile::ReadOnly);
return f.readAll();
}
static QString readFileUtf8(const QString &fileName)
{
return QString::fromUtf8(readFile(fileName));
}
};
#define MULTIMC_GET_TEST_FILE(file) TestsInternal::readFile(QFINDTESTDATA( file ))
#define MULTIMC_GET_TEST_FILE_UTF8(file) TestsInternal::readFileUtf8(QFINDTESTDATA( file ))
#define MULTIMC_GET_TEST_FILE(file) TestsInternal::readFile(QFINDTESTDATA(file))
#define MULTIMC_GET_TEST_FILE_UTF8(file) TestsInternal::readFileUtf8(QFINDTESTDATA(file))
#ifdef Q_OS_LINUX
# define _MMC_EXTRA_ARGV , "-platform", "offscreen"
# define _MMC_EXTRA_ARGC 2
#define _MMC_EXTRA_ARGV , "-platform", "offscreen"
#define _MMC_EXTRA_ARGC 2
#else
# define _MMC_EXTRA_ARGV
# define _MMC_EXTRA_ARGC 0
#define _MMC_EXTRA_ARGV
#define _MMC_EXTRA_ARGC 0
#endif

153
tests/tst_modutils.cpp Normal file
View File

@ -0,0 +1,153 @@
/* Copyright 2013 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <QTest>
#include "modutils.h"
#include "TestUtil.h"
class ModUtilsTest : public QObject
{
Q_OBJECT
void setupVersions()
{
QTest::addColumn<QString>("first");
QTest::addColumn<QString>("second");
QTest::addColumn<bool>("lessThan");
QTest::addColumn<bool>("equal");
QTest::newRow("equal, explicit") << "1.2.0" << "1.2.0" << false << true;
QTest::newRow("equal, implicit 1") << "1.2" << "1.2.0" << false << true;
QTest::newRow("equal, implicit 2") << "1.2.0" << "1.2" << false << true;
QTest::newRow("equal, two-digit") << "1.42" << "1.42" << false << true;
QTest::newRow("lessThan, explicit 1") << "1.2.0" << "1.2.1" << true << false;
QTest::newRow("lessThan, explicit 2") << "1.2.0" << "1.3.0" << true << false;
QTest::newRow("lessThan, explicit 3") << "1.2.0" << "2.2.0" << true << false;
QTest::newRow("lessThan, implicit 1") << "1.2" << "1.2.1" << true << false;
QTest::newRow("lessThan, implicit 2") << "1.2" << "1.3.0" << true << false;
QTest::newRow("lessThan, implicit 3") << "1.2" << "2.2.0" << true << false;
QTest::newRow("lessThan, two-digit") << "1.41" << "1.42" << true << false;
QTest::newRow("greaterThan, explicit 1") << "1.2.1" << "1.2.0" << false << false;
QTest::newRow("greaterThan, explicit 2") << "1.3.0" << "1.2.0" << false << false;
QTest::newRow("greaterThan, explicit 3") << "2.2.0" << "1.2.0" << false << false;
QTest::newRow("greaterThan, implicit 1") << "1.2.1" << "1.2" << false << false;
QTest::newRow("greaterThan, implicit 2") << "1.3.0" << "1.2" << false << false;
QTest::newRow("greaterThan, implicit 3") << "2.2.0" << "1.2" << false << false;
QTest::newRow("greaterThan, two-digit") << "1.42" << "1.41" << false << false;
}
private slots:
void initTestCase()
{
}
void cleanupTestCase()
{
}
void test_versionIsInInterval_data()
{
QTest::addColumn<QString>("version");
QTest::addColumn<QString>("interval");
QTest::addColumn<bool>("result");
QTest::newRow("empty, true") << "1.2.3" << "" << true;
QTest::newRow("one version, true") << "1.2.3" << "1.2.3" << true;
QTest::newRow("one version, false") << "1.2.3" << "1.2.2" << false;
QTest::newRow("one version inclusive <-> infinity, true") << "1.2.3" << "[1.2.3,)" << true;
QTest::newRow("one version exclusive <-> infinity, true") << "1.2.3" << "(1.2.2,)" << true;
QTest::newRow("one version inclusive <-> infitity, false") << "1.2.3" << "[1.2.4,)" << false;
QTest::newRow("one version exclusive <-> infinity, false") << "1.2.3" << "(1.2.3,)" << false;
QTest::newRow("infinity <-> one version inclusive, true") << "1.2.3" << "(,1.2.3]" << true;
QTest::newRow("infinity <-> one version exclusive, true") << "1.2.3" << "(,1.2.4)" << true;
QTest::newRow("infinity <-> one version inclusive, false") << "1.2.3" << "(,1.2.2]" << false;
QTest::newRow("infinity <-> one version exclusive, false") << "1.2.3" << "(,1.2.3)" << false;
QTest::newRow("inclusive <-> inclusive, true") << "1.2.3" << "[1.2.2,1.2.3]" << true;
QTest::newRow("inclusive <-> exclusive, true") << "1.2.3" << "[1.2.3,1.2.4)" << true;
QTest::newRow("exclusive <-> inclusive, true") << "1.2.3" << "(1.2.2,1.2.3]" << true;
QTest::newRow("exclusive <-> exclusive, true") << "1.2.3" << "(1.2.2,1.2.4)" << true;
QTest::newRow("inclusive <-> inclusive, false") << "1.2.3" << "[1.0.0,1.2.2]" << false;
QTest::newRow("inclusive <-> exclusive, false") << "1.2.3" << "[1.0.0,1.2.3)" << false;
QTest::newRow("exclusive <-> inclusive, false") << "1.2.3" << "(1.2.3,2.0.0]" << false;
QTest::newRow("exclusive <-> exclusive, false") << "1.2.3" << "(1.0.0,1.2.3)" << false;
}
void test_versionIsInInterval()
{
QFETCH(QString, version);
QFETCH(QString, interval);
QFETCH(bool, result);
QCOMPARE(Util::versionIsInInterval(version, interval), result);
}
void test_versionCompareLessThan_data()
{
setupVersions();
}
void test_versionCompareLessThan()
{
QFETCH(QString, first);
QFETCH(QString, second);
QFETCH(bool, lessThan);
QFETCH(bool, equal);
const auto v1 = Util::Version(first);
const auto v2 = Util::Version(second);
QCOMPARE(v1 < v2, lessThan);
}
void test_versionCompareGreaterThan_data()
{
setupVersions();
}
void test_versionCompareGreaterThan()
{
QFETCH(QString, first);
QFETCH(QString, second);
QFETCH(bool, lessThan);
QFETCH(bool, equal);
const auto v1 = Util::Version(first);
const auto v2 = Util::Version(second);
QCOMPARE(v1 > v2, !lessThan && !equal);
}
void test_versionCompareEqual_data()
{
setupVersions();
}
void test_versionCompareEqual()
{
QFETCH(QString, first);
QFETCH(QString, second);
QFETCH(bool, lessThan);
QFETCH(bool, equal);
const auto v1 = Util::Version(first);
const auto v2 = Util::Version(second);
QCOMPARE(v1 == v2, equal);
}
};
QTEST_GUILESS_MAIN(ModUtilsTest)
#include "tst_modutils.moc"