commit 0008d74cc7b5066dbb954459b0c4dabddf9e21e6
parent f79b8e1f0fbe1b0c0019989f68069107e8880f7a
Author: cfillion <cfillion@users.noreply.github.com>
Date: Wed, 20 Apr 2016 22:51:47 -0400
Merge branch 'prereleases'
Diffstat:
17 files changed, 345 insertions(+), 245 deletions(-)
diff --git a/src/browser.cpp b/src/browser.cpp
@@ -461,9 +461,12 @@ void Browser::transferActions()
}
auto Browser::makeEntry(const Package *pkg, const Registry::Entry ®Entry)
- -> Entry
+ const -> Entry
{
- const Version *latest = pkg->lastVersion();
+ const auto &instOpts = *m_reapack->config()->install();
+ const bool includePre = instOpts.bleedingEdge ||
+ (regEntry && !regEntry.version.isStable());
+ const Version *latest = pkg->lastVersion(includePre);
const Version *current = nullptr;
int flags = 0;
@@ -471,13 +474,17 @@ auto Browser::makeEntry(const Package *pkg, const Registry::Entry ®Entry)
if(regEntry) {
flags |= InstalledFlag;
- if(regEntry.version < *latest)
+ if(latest && regEntry.version < *latest)
flags |= OutOfDateFlag;
current = pkg->findVersion(regEntry.version);
}
- else
+ else {
+ if(!latest) // show prerelases if no stable version is available
+ latest = pkg->lastVersion(true);
+
flags |= UninstalledFlag;
+ }
return {flags, regEntry, pkg, latest, current};
}
diff --git a/src/browser.hpp b/src/browser.hpp
@@ -89,7 +89,7 @@ private:
Uninstalled,
};
- static Entry makeEntry(const Package *, const Registry::Entry &);
+ Entry makeEntry(const Package *, const Registry::Entry &) const;
void populate();
void transferActions();
diff --git a/src/config.cpp b/src/config.cpp
@@ -33,6 +33,7 @@ static const char *VERSION_KEY = "version";
static const char *INSTALL_GRP = "install";
static const char *AUTOINSTALL_KEY = "autoinstall";
+static const char *PRERELEASES_KEY = "prereleases";
static const char *BROWSER_GRP = "browser";
static const char *TYPEFILTER_KEY = "typefilter";
@@ -50,7 +51,7 @@ static string ArrayKey(const string &key, const unsigned int i)
static const int BUFFER_SIZE = 2083;
Config::Config()
- : m_isFirstRun(false), m_version(0), m_autoInstall(false), m_browser(),
+ : m_isFirstRun(false), m_version(0), m_install(), m_browser(),
m_remotesIniSize(0)
{
}
@@ -90,7 +91,10 @@ void Config::read(const Path &path)
{
m_path = path.join();
- m_autoInstall = getUInt(INSTALL_GRP, AUTOINSTALL_KEY) > 0;
+ m_install = {
+ getUInt(INSTALL_GRP, AUTOINSTALL_KEY) > 0,
+ getUInt(INSTALL_GRP, PRERELEASES_KEY) > 0,
+ };
m_browser = {
getUInt(BROWSER_GRP, TYPEFILTER_KEY),
@@ -105,7 +109,8 @@ void Config::write()
{
setUInt(GENERAL_GRP, VERSION_KEY, m_version);
- setUInt(INSTALL_GRP, AUTOINSTALL_KEY, m_autoInstall);
+ setUInt(INSTALL_GRP, AUTOINSTALL_KEY, m_install.autoInstall);
+ setUInt(INSTALL_GRP, PRERELEASES_KEY, m_install.bleedingEdge);
setUInt(BROWSER_GRP, TYPEFILTER_KEY, m_browser.typeFilter);
diff --git a/src/config.hpp b/src/config.hpp
@@ -24,7 +24,12 @@
class Path;
-struct BrowserConfig {
+struct InstallOpts {
+ bool autoInstall;
+ bool bleedingEdge;
+};
+
+struct BrowserOpts {
unsigned int typeFilter;
};
@@ -36,10 +41,9 @@ public:
void write();
bool isFirstRun() const { return m_isFirstRun; }
- bool autoInstall() const { return m_autoInstall; }
- void setAutoInstall(const bool enable) { m_autoInstall = enable; }
RemoteList *remotes() { return &m_remotes; }
- BrowserConfig *browser() { return &m_browser; }
+ InstallOpts *install() { return &m_install; }
+ BrowserOpts *browser() { return &m_browser; }
private:
std::string getString(const char *, const std::string &) const;
@@ -55,8 +59,8 @@ private:
std::string m_path;
bool m_isFirstRun;
unsigned int m_version;
- bool m_autoInstall;
- BrowserConfig m_browser;
+ InstallOpts m_install;
+ BrowserOpts m_browser;
void readRemotes();
void restoreSelfRemote();
diff --git a/src/manager.cpp b/src/manager.cpp
@@ -30,7 +30,7 @@
using namespace std;
enum { ACTION_ENABLE = 80, ACTION_DISABLE, ACTION_UNINSTALL, ACTION_ABOUT,
- ACTION_AUTOINSTALL, ACTION_SELECT, ACTION_UNSELECT };
+ ACTION_AUTOINSTALL, ACTION_BLEEDINGEDGE, ACTION_SELECT, ACTION_UNSELECT };
Manager::Manager(ReaPack *reapack)
: Dialog(IDD_CONFIG_DIALOG),
@@ -77,7 +77,11 @@ void Manager::onCommand(const int id, int)
uninstall();
break;
case ACTION_AUTOINSTALL:
- m_autoInstall = !m_autoInstall.value_or(m_config->autoInstall());
+ m_autoInstall = !m_autoInstall.value_or(m_config->install()->autoInstall);
+ enable(m_apply);
+ break;
+ case ACTION_BLEEDINGEDGE:
+ m_bleedingEdge = !m_bleedingEdge.value_or(m_config->install()->bleedingEdge);
enable(m_apply);
break;
case ACTION_SELECT:
@@ -247,10 +251,14 @@ void Manager::options()
Menu menu;
- const UINT index = menu.addAction(
+ UINT index = menu.addAction(
AUTO_STR("&Install new packages automatically"), ACTION_AUTOINSTALL);
+ if(m_autoInstall.value_or(m_config->install()->autoInstall))
+ menu.check(index);
- if(m_autoInstall.value_or(m_config->autoInstall()))
+ index = menu.addAction(
+ AUTO_STR("Enable &pre-releases (bleeding edge mode)"), ACTION_BLEEDINGEDGE);
+ if(m_bleedingEdge.value_or(m_config->install()->bleedingEdge))
menu.check(index);
menu.show(rect.left, rect.bottom - 1, handle());
@@ -278,7 +286,10 @@ bool Manager::confirm() const
void Manager::apply()
{
if(m_autoInstall)
- m_config->setAutoInstall(m_autoInstall.value());
+ m_config->install()->autoInstall = m_autoInstall.value();
+
+ if(m_bleedingEdge)
+ m_config->install()->bleedingEdge = m_bleedingEdge.value();
for(const auto &pair : m_enableOverrides) {
const Remote &remote = pair.first;
@@ -294,7 +305,11 @@ void Manager::apply()
m_reapack->uninstall(remote);
m_config->write();
- m_reapack->runTasks();
+
+ if(m_reapack->isRunning())
+ m_reapack->runTasks();
+ else
+ m_reapack->refreshBrowser();
}
void Manager::reset()
diff --git a/src/manager.hpp b/src/manager.hpp
@@ -63,6 +63,7 @@ private:
std::map<Remote, bool> m_enableOverrides;
std::set<Remote> m_uninstall;
boost::optional<bool> m_autoInstall;
+ boost::optional<bool> m_bleedingEdge;
};
#endif
diff --git a/src/package.cpp b/src/package.cpp
@@ -21,7 +21,7 @@
#include "index.hpp"
#include <algorithm>
-#include <sstream>
+#include <boost/range/adaptor/reversed.hpp>
using namespace std;
@@ -99,12 +99,14 @@ const Version *Package::version(const size_t index) const
return *it;
}
-const Version *Package::lastVersion() const
+const Version *Package::lastVersion(const bool prerelease) const
{
- if(m_versions.empty())
- return nullptr;
+ for(const Version *ver : m_versions | boost::adaptors::reversed) {
+ if(ver->isStable() || prerelease)
+ return ver;
+ }
- return *m_versions.rbegin();
+ return nullptr;
}
const Version *Package::findVersion(const Version &ver) const
diff --git a/src/package.hpp b/src/package.hpp
@@ -51,7 +51,7 @@ public:
void addVersion(const Version *ver);
const VersionSet &versions() const { return m_versions; }
const Version *version(size_t index) const;
- const Version *lastVersion() const;
+ const Version *lastVersion(bool prerelease = true) const;
const Version *findVersion(const Version &) const;
private:
diff --git a/src/reapack.cpp b/src/reapack.cpp
@@ -147,7 +147,7 @@ void ReaPack::synchronizeAll()
return;
for(const Remote &remote : remotes)
- t->synchronize(remote, m_config->autoInstall());
+ t->synchronize(remote, *m_config->install());
t->runTasks();
}
@@ -159,13 +159,12 @@ void ReaPack::setRemoteEnabled(const Remote &original, const bool enable)
const auto apply = [=] {
m_config->remotes()->add(remote);
-
- if(m_manager)
- m_manager->refresh();
+ refreshManager();
};
if(!hitchhikeTransaction()) {
apply();
+ refreshBrowser();
return;
}
@@ -196,6 +195,7 @@ void ReaPack::uninstall(const Remote &remote)
if(!hitchhikeTransaction()) {
apply();
+ refreshBrowser();
return;
}
@@ -280,11 +280,8 @@ void ReaPack::import(const Remote &remote, HWND parent)
remotes->add(remote);
m_config->write();
- if(m_manager)
- m_manager->refresh();
-
- if(m_browser)
- m_browser->refresh();
+ refreshManager();
+ refreshBrowser();
const string msg = remote.name() +
" has been successfully imported into your repository list.";
@@ -332,8 +329,11 @@ void ReaPack::about(const Remote &remote, HWND parent)
if(ret == About::InstallResult) {
enable(remote);
- if(m_transaction) // transaction is created by enable()
- m_transaction->synchronize(remote, true);
+ if(m_transaction) { // transaction is created by enable()
+ InstallOpts opts = *m_config->install();
+ opts.autoInstall = true;
+ m_transaction->synchronize(remote, opts);
+ }
runTasks();
}
@@ -526,8 +526,7 @@ Transaction *ReaPack::createTransaction()
m_transaction = nullptr;
// refresh only once all onFinish slots were ran
- if(m_browser)
- m_browser->refresh();
+ refreshBrowser();
});
return m_transaction;
@@ -547,6 +546,18 @@ void ReaPack::runTasks()
m_transaction->runTasks();
}
+void ReaPack::refreshManager()
+{
+ if(m_manager)
+ m_manager->refresh();
+}
+
+void ReaPack::refreshBrowser()
+{
+ if(m_browser)
+ m_browser->refresh();
+}
+
void ReaPack::registerSelf()
{
// hard-coding galore!
diff --git a/src/reapack.hpp b/src/reapack.hpp
@@ -69,6 +69,7 @@ public:
void install(const Version *);
void uninstall(const Remote &);
void uninstall(const Registry::Entry &);
+
void importRemote();
void import(const Remote &, HWND = nullptr);
void manageRemotes();
@@ -76,6 +77,9 @@ public:
void about(const std::string &, HWND parent);
void about(const Remote &, HWND parent);
void browsePackages();
+ void refreshManager();
+ void refreshBrowser();
+
void fetchIndex(const Remote &remote, const IndexCallback &,
HWND parent, bool stale = false);
void fetchIndexes(const std::vector<Remote> &,
diff --git a/src/transaction.cpp b/src/transaction.cpp
@@ -17,6 +17,7 @@
#include "transaction.hpp"
+#include "config.hpp"
#include "encoding.hpp"
#include "errors.hpp"
#include "filesystem.hpp"
@@ -64,7 +65,7 @@ Transaction::~Transaction()
delete m_registry;
}
-void Transaction::synchronize(const Remote &remote, const bool autoInstall)
+void Transaction::synchronize(const Remote &remote, const InstallOpts &opts)
{
// show the report dialog or "nothing to do" even if no task are ran
m_receipt.setEnabled(true);
@@ -82,20 +83,22 @@ void Transaction::synchronize(const Remote &remote, const bool autoInstall)
}
for(const Package *pkg : ri->packages())
- synchronize(pkg, autoInstall);
+ synchronize(pkg, opts);
});
}
-void Transaction::synchronize(const Package *pkg, const bool autoInstall)
+void Transaction::synchronize(const Package *pkg, const InstallOpts &opts)
{
const auto ®Entry = m_registry->getEntry(pkg);
- if(!regEntry && !autoInstall)
+ if(!regEntry && !opts.autoInstall)
return;
- const Version *latest = pkg->lastVersion();
+ const bool includePre = opts.bleedingEdge ||
+ (regEntry && !regEntry.version.isStable());
+ const Version *latest = pkg->lastVersion(includePre);
- if(regEntry.version == *latest) {
+ if(latest && regEntry.version == *latest) {
if(allFilesExists(latest->files()))
return; // latest version is really installed, nothing to do here!
}
diff --git a/src/transaction.hpp b/src/transaction.hpp
@@ -32,6 +32,7 @@ class Index;
class Path;
class Remote;
class Task;
+struct InstallOpts;
typedef std::shared_ptr<const Index> IndexPtr;
@@ -56,7 +57,7 @@ public:
void onFinish(const VoidSignal::slot_type &slot) { m_onFinish.connect(slot); }
void setCleanupHandler(const CleanupHandler &cb) { m_cleanupHandler = cb; }
- void synchronize(const Remote &, bool autoInstall);
+ void synchronize(const Remote &, const InstallOpts &);
void install(const Version *);
void uninstall(const Remote &);
void uninstall(const Registry::Entry &);
@@ -78,7 +79,7 @@ private:
void fetchIndex(const Remote &, const IndexCallback &cb);
void saveIndex(Download *, const std::string &remoteName);
- void synchronize(const Package *, bool autoInstall);
+ void synchronize(const Package *, const InstallOpts &);
void install(const Version *, const Registry::Entry &);
void installTicket(const InstallTicket &);
void addTask(Task *);
diff --git a/src/version.cpp b/src/version.cpp
@@ -21,26 +21,26 @@
#include "package.hpp"
#include "source.hpp"
-#include <algorithm>
-#include <cmath>
+#include <boost/lexical_cast.hpp>
+#include <cctype>
#include <regex>
using namespace std;
Version::Version()
- : m_code(0), m_time(), m_package(nullptr), m_mainSource(nullptr)
+ : m_stable(false), m_time(), m_package(nullptr), m_mainSource(nullptr)
{
}
Version::Version(const string &str, const Package *pkg)
- : m_code(0), m_time(), m_package(pkg), m_mainSource(nullptr)
+ : m_time(), m_package(pkg), m_mainSource(nullptr)
{
parse(str);
}
Version::Version(const Version &o, const Package *pkg)
- : m_name(o.name()), m_code(o.code()),
- m_author(o.author()), m_changelog(o.changelog()), m_time(o.time()),
+ : m_name(o.m_name), m_segments(o.m_segments), m_stable(o.m_stable),
+ m_author(o.m_author), m_changelog(o.m_changelog), m_time(o.m_time),
m_package(pkg), m_mainSource(nullptr)
{
}
@@ -53,30 +53,39 @@ Version::~Version()
void Version::parse(const string &str)
{
- static const regex pattern("(\\d+)");
-
- auto begin = sregex_iterator(str.begin(), str.end(), pattern);
- auto end = sregex_iterator();
-
- // set the major version by default
- // even if there are less than 4 numeric components in the string
- const size_t size = max((size_t)4, (size_t)distance(begin, end));
+ static const regex pattern("\\d+|[a-zA-Z]+");
+
+ const auto &begin = sregex_iterator(str.begin(), str.end(), pattern);
+ const sregex_iterator end;
+
+ size_t numeric = 0, alpha = 0;
+ vector<Segment> segments;
+
+ for(sregex_iterator it = begin; it != end; it++) {
+ const string match = it->str(0);
+ const char first = tolower(match[0]);
+
+ if(first >= 'a' || first >= 'z') {
+ segments.push_back(match);
+ alpha++;
+ }
+ else {
+ try {
+ segments.push_back(boost::lexical_cast<Numeric>(match));
+ numeric++;
+ }
+ catch(const boost::bad_lexical_cast &) {
+ throw reapack_error("version segment overflow");
+ }
+ }
+ }
- if(begin == end || size > 4L)
+ if(!numeric)
throw reapack_error("invalid version name");
- size_t index = 0;
-
- for(sregex_iterator it = begin; it != end; it++, index++) {
- const string match = it->str(1);
-
- if(match.size() > 4)
- throw reapack_error("version component overflow");
-
- m_code += stoi(match) * (Code)pow(10000, size - index - 1);
- }
-
m_name = str;
+ swap(m_segments, segments);
+ m_stable = alpha < 1;
}
bool Version::tryParse(const string &str)
@@ -183,32 +192,44 @@ const Source *Version::source(const size_t index) const
return it->second;
}
-bool Version::operator<(const Version &o) const
-{
- return m_code < o.code();
-}
-
-bool Version::operator<=(const Version &o) const
-{
- return !(m_code > o.code());
-}
-
-bool Version::operator>(const Version &o) const
-{
- return m_code > o.code();
-}
-
-bool Version::operator>=(const Version &o) const
-{
- return !(m_code < o.code());
-}
-
-bool Version::operator==(const Version &o) const
+auto Version::segment(const size_t index) const -> Segment
{
- return m_code == o.code();
-}
+ if(index < size())
+ return m_segments[index];
+ else
+ return 0;
+}
+
+int Version::compare(const Version &o) const
+{
+ const size_t biggest = max(size(), o.size());
+
+ for(size_t i = 0; i < biggest; i++) {
+ const Segment &lseg = segment(i);
+ const Numeric *lnum = boost::get<Numeric>(&lseg);
+ const string *lstr = boost::get<string>(&lseg);
+
+ const Segment &rseg = o.segment(i);
+ const Numeric *rnum = boost::get<Numeric>(&rseg);
+ const string *rstr = boost::get<string>(&rseg);
+
+ if(lnum && rnum) {
+ if(*lnum < *rnum)
+ return -1;
+ else if(*lnum > *rnum)
+ return 1;
+ }
+ else if(lstr && rstr) {
+ if(*lstr < *rstr)
+ return -1;
+ else if(*lstr > *rstr)
+ return 1;
+ }
+ else if(lnum && rstr)
+ return 1;
+ else if(lstr && rnum)
+ return -1;
+ }
-bool Version::operator!=(const Version &o) const
-{
- return !(*this == o);
+ return 0;
}
diff --git a/src/version.hpp b/src/version.hpp
@@ -18,6 +18,7 @@
#ifndef REAPACK_VERSION_HPP
#define REAPACK_VERSION_HPP
+#include <boost/variant.hpp>
#include <cstdint>
#include <ctime>
#include <map>
@@ -31,7 +32,6 @@ class Path;
class Version {
public:
- typedef uint64_t Code;
typedef std::vector<Source *> SourceList;
typedef std::multimap<Path, const Source *> SourceMap;
@@ -45,7 +45,8 @@ public:
const std::string &name() const { return m_name; }
std::string fullName() const;
- uint64_t code() const { return m_code; }
+ size_t size() const { return m_segments.size(); }
+ bool isStable() const { return m_stable; }
const Package *package() const { return m_package; }
@@ -67,16 +68,23 @@ public:
const std::set<Path> &files() const { return m_files; }
- bool operator<(const Version &) const;
- bool operator<=(const Version &) const;
- bool operator>(const Version &) const;
- bool operator>=(const Version &) const;
- bool operator==(const Version &) const;
- bool operator!=(const Version &) const;
+ int compare(const Version &) const;
+ bool operator<(const Version &o) const { return compare(o) < 0; }
+ bool operator<=(const Version &o) const { return compare(o) <= 0; }
+ bool operator>(const Version &o) const { return compare(o) > 0; }
+ bool operator>=(const Version &o) const { return compare(o) >= 0; }
+ bool operator==(const Version &o) const { return compare(o) == 0; }
+ bool operator!=(const Version &o) const { return compare(o) != 0; }
private:
+ typedef uint16_t Numeric;
+ typedef boost::variant<Numeric, std::string> Segment;
+
+ Segment segment(size_t i) const;
+
std::string m_name;
- Code m_code;
+ std::vector<Segment> m_segments;
+ bool m_stable;
std::string m_author;
std::string m_changelog;
@@ -89,7 +97,7 @@ private:
std::set<Path> m_files;
};
-class VersionCompare {
+class VersionPtrCompare {
public:
bool operator()(const Version *l, const Version *r) const
{
@@ -97,6 +105,6 @@ public:
}
};
-typedef std::set<const Version *, VersionCompare> VersionSet;
+typedef std::set<const Version *, VersionPtrCompare> VersionSet;
#endif
diff --git a/test/index_v1.cpp b/test/index_v1.cpp
@@ -74,7 +74,7 @@ TEST_CASE("read version author", M) {
IndexPtr ri = Index::load("author");
CHECK(ri->packages().size() == 1);
- REQUIRE(ri->category(0)->package(0)->lastVersion()->author()
+ REQUIRE(ri->category(0)->package(0)->version(0)->author()
== "Watanabe Saki");
}
@@ -84,7 +84,7 @@ TEST_CASE("read version time", M) {
IndexPtr ri = Index::load("time");
CHECK(ri->packages().size() == 1);
- const tm &time = ri->category(0)->package(0)->lastVersion()->time();
+ const tm &time = ri->category(0)->package(0)->version(0)->time();
REQUIRE(time.tm_year == 2016 - 1900);
REQUIRE(time.tm_mon == 2 - 1);
REQUIRE(time.tm_mday == 12);
diff --git a/test/package.cpp b/test/package.cpp
@@ -94,6 +94,30 @@ TEST_CASE("package versions are sorted", M) {
REQUIRE(pack.lastVersion() == final);
}
+TEST_CASE("get latest stable version", M) {
+ Index ri("Remote Name");
+ Category cat("Category Name", &ri);
+ Package pack(Package::ScriptType, "a", &cat);
+
+ Version *alpha = new Version("2.0-alpha", &pack);
+ alpha->addSource(new Source({}, "google.com", alpha));
+ pack.addVersion(alpha);
+
+ SECTION("only prereleases are available")
+ REQUIRE(pack.lastVersion(false) == nullptr);
+
+ SECTION("an older stable release is available") {
+ Version *final = new Version("1.0", &pack);
+ final->addSource(new Source({}, "google.com", final));
+ pack.addVersion(final);
+
+ REQUIRE(pack.lastVersion(false) == final);
+ }
+
+ REQUIRE(pack.lastVersion() == alpha);
+ REQUIRE(pack.lastVersion(true) == alpha);
+}
+
TEST_CASE("drop empty version", M) {
Package pack(Package::ScriptType, "a");
pack.addVersion(new Version("1", &pack));
diff --git a/test/version.cpp b/test/version.cpp
@@ -25,52 +25,67 @@ static Source *mksource(Source::Platform p, Version *parent)
static const char *M = "[version]";
-TEST_CASE("invalid", M) {
- try {
- Version ver("hello");
- FAIL();
+TEST_CASE("construct null version", M) {
+ const Version ver;
+
+ REQUIRE(ver.size() == 0);
+ REQUIRE_FALSE(ver.isStable());
+ REQUIRE(ver.displayTime().empty());
+ REQUIRE(ver.package() == nullptr);
+ REQUIRE(ver.mainSource() == nullptr);
+}
+
+TEST_CASE("parse version", M) {
+ Version ver;
+
+ SECTION("valid") {
+ ver.parse("1.0.1");
+ REQUIRE(ver.name() == "1.0.1");
+ REQUIRE(ver.size() == 3);
}
- catch(const reapack_error &e) {
- REQUIRE(string(e.what()) == "invalid version name");
+
+ SECTION("prerelease set/unset") {
+ ver.parse("1.0beta");
+ REQUIRE_FALSE(ver.isStable());
+ ver.parse("1.0");
+ REQUIRE(ver.isStable());
}
-}
-TEST_CASE("major minor patch version", M) {
- Version ver("1.2.3");
- REQUIRE(ver.name() == "1.2.3");
- REQUIRE(ver.code() == UINT64_C(1000200030000));
-}
+ SECTION("invalid") {
+ try { ver.parse("hello"); FAIL(); }
+ catch(const reapack_error &) {}
-TEST_CASE("major minor version", M) {
- Version ver("1.2");
- REQUIRE(ver.name() == "1.2");
- REQUIRE(ver.code() == UINT64_C(1000200000000));
+ REQUIRE(ver.name().empty());
+ REQUIRE(ver.size() == 0);
+ }
}
-TEST_CASE("major version", M) {
- Version ver("1");
- REQUIRE(ver.name() == "1");
- REQUIRE(ver.code() == UINT64_C(1000000000000));
-}
+TEST_CASE("parse version failsafe", M) {
+ Version ver;
-TEST_CASE("version with string suffix", M) {
- Version ver("1.2pre3");
- REQUIRE(ver.name() == "1.2pre3");
- REQUIRE(ver.code() == UINT64_C(1000200030000));
-}
+ SECTION("valid") {
+ REQUIRE(ver.tryParse("1.0"));
-TEST_CASE("version with 4 components", M) {
- Version ver("1.2.3.4");
- REQUIRE(ver.name() == "1.2.3.4");
- REQUIRE(ver.code() == UINT64_C(1000200030004));
- REQUIRE(ver < Version("1.2.4"));
+ REQUIRE(ver.name() == "1.0");
+ REQUIRE(ver.size() == 2);
+ }
+
+ SECTION("invalid") {
+ REQUIRE_FALSE(ver.tryParse("hello"));
+
+ REQUIRE(ver.name().empty());
+ REQUIRE(ver.size() == 0);
+ }
}
-TEST_CASE("version with repeated digits", M) {
- Version ver("1.1.1");
- REQUIRE(ver.name() == "1.1.1");
- REQUIRE(ver.code() == UINT64_C(1000100010000));
- REQUIRE(ver < Version("1.1.2"));
+TEST_CASE("construct invalid version", M) {
+ try {
+ Version ver("hello");
+ FAIL();
+ }
+ catch(const reapack_error &e) {
+ REQUIRE(string(e.what()) == "invalid version name");
+ }
}
TEST_CASE("decimal version", M) {
@@ -79,29 +94,88 @@ TEST_CASE("decimal version", M) {
REQUIRE(ver < Version("5.50"));
}
-TEST_CASE("4 digits version component", M) {
- Version ver("0.2015.12.25");
- REQUIRE(ver.name() == "0.2015.12.25");
- REQUIRE(ver.code() == UINT64_C(201500120025));
+TEST_CASE("5 version segments", M) {
+ REQUIRE(Version("1.1.1.1.0") < Version("1.1.1.1.1"));
+ REQUIRE(Version("1.1.1.1.1") == Version("1.1.1.1.1"));
+ REQUIRE(Version("1.1.1.1.1") < Version("1.1.1.1.2"));
+ REQUIRE(Version("1.1.1.1.1") < Version("1.1.1.2.0"));
}
-TEST_CASE("5 digits version component", M) {
+TEST_CASE("version segment overflow", M) {
try {
- Version ver("12345.1");
+ Version ver("9999999999999999999999");
FAIL();
}
catch(const reapack_error &e) {
- REQUIRE(string(e.what()) == "version component overflow");
+ REQUIRE(string(e.what()) == "version segment overflow");
}
}
-TEST_CASE("version with 5 components", M) {
- try {
- Version ver("1.2.3.4.5");
- FAIL();
+TEST_CASE("compare versions", M) {
+ SECTION("equality") {
+ REQUIRE(Version("1.0").compare(Version("1.0")) == 0);
+
+ REQUIRE(Version("1.0") == Version("1.0"));
+ REQUIRE_FALSE(Version("1.0") == Version("1.1"));
}
- catch(const reapack_error &e) {
- REQUIRE(string(e.what()) == "invalid version name");
+
+ SECTION("inequality") {
+ REQUIRE_FALSE(Version("1.0") != Version("1.0"));
+ REQUIRE(Version("1.0") != Version("1.1"));
+ }
+
+ SECTION("less than") {
+ REQUIRE(Version("1.0").compare(Version("1.1")) == -1);
+
+ REQUIRE(Version("1.0") < Version("1.1"));
+ REQUIRE_FALSE(Version("1.0") < Version("1.0"));
+ REQUIRE_FALSE(Version("1.1") < Version("1.0"));
+ }
+
+ SECTION("less than or equal") {
+ REQUIRE(Version("1.0") <= Version("1.1"));
+ REQUIRE(Version("1.0") <= Version("1.0"));
+ REQUIRE_FALSE(Version("1.1") <= Version("1.0"));
+ }
+
+ SECTION("greater than") {
+ REQUIRE(Version("1.1").compare(Version("1.0")) == 1);
+
+ REQUIRE_FALSE(Version("1.0") > Version("1.1"));
+ REQUIRE_FALSE(Version("1.0") > Version("1.0"));
+ REQUIRE(Version("1.1") > Version("1.0"));
+ }
+
+ SECTION("greater than or equal") {
+ REQUIRE_FALSE(Version("1.0") >= Version("1.1"));
+ REQUIRE(Version("1.0") >= Version("1.0"));
+ REQUIRE(Version("1.1") >= Version("1.0"));
+ }
+}
+
+TEST_CASE("compare versions with more or less segments", M) {
+ REQUIRE(Version("1") == Version("1.0.0.0"));
+ REQUIRE(Version("1") != Version("1.0.0.1"));
+
+ REQUIRE(Version("1.0.0.0") == Version("1"));
+ REQUIRE(Version("1.0.0.1") != Version("1"));
+}
+
+TEST_CASE("prerelease versions", M) {
+ SECTION("detect") {
+ REQUIRE(Version("1.0").isStable());
+ REQUIRE_FALSE(Version("1.0b").isStable());
+ REQUIRE_FALSE(Version("1.0-beta").isStable());
+ REQUIRE_FALSE(Version("1.0-beta1").isStable());
+ }
+
+ SECTION("compare") {
+ REQUIRE(Version("0.9") < Version("1.0a"));
+ REQUIRE(Version("1.0a.2") < Version("1.0b.1"));
+ REQUIRE(Version("1.0-beta1") < Version("1.0"));
+
+ REQUIRE(Version("1.0b") < Version("1.0.1"));
+ REQUIRE(Version("1.0.1") > Version("1.0b"));
}
}
@@ -236,62 +310,18 @@ TEST_CASE("version date", M) {
}
}
-TEST_CASE("construct null version", M) {
- const Version ver;
-
- REQUIRE(ver.code() == 0);
- REQUIRE(ver.displayTime().empty());
- REQUIRE(ver.package() == nullptr);
- REQUIRE(ver.mainSource() == nullptr);
-}
-
-TEST_CASE("parse version", M) {
- Version ver;
-
- SECTION("valid") {
- ver.parse("1.0");
- REQUIRE(ver.name() == "1.0");
- REQUIRE(ver.code() == UINT64_C(1000000000000));
- }
-
- SECTION("invalid") {
- try { ver.parse("hello"); FAIL(); }
- catch(const reapack_error &) {}
-
- REQUIRE(ver.name().empty());
- REQUIRE(ver.code() == 0);
- }
-}
-
-TEST_CASE("parse version failsafe", M) {
- Version ver;
-
- SECTION("valid") {
- REQUIRE(ver.tryParse("1.0"));
-
- REQUIRE(ver.name() == "1.0");
- REQUIRE(ver.code() == UINT64_C(1000000000000));
- }
-
- SECTION("invalid") {
- REQUIRE_FALSE(ver.tryParse("hello"));
-
- REQUIRE(ver.name().empty());
- REQUIRE(ver.code() == 0);
- }
-}
-
TEST_CASE("copy version constructor", M) {
const Package pkg(Package::UnknownType, "Hello");
- Version original("1.1", &pkg);
+ Version original("1.1test", &pkg);
original.setAuthor("John Doe");
original.setChangelog("Initial release");
original.setTime("2016-02-12T01:16:40Z");
const Version copy1(original);
- REQUIRE(copy1.name() == "1.1");
- REQUIRE(copy1.code() == original.code());
+ REQUIRE(copy1.name() == "1.1test");
+ REQUIRE(copy1.size() == original.size());
+ REQUIRE(copy1.isStable() == original.isStable());
REQUIRE(copy1.author() == original.author());
REQUIRE(copy1.changelog() == original.changelog());
REQUIRE(copy1.displayTime() == original.displayTime());
@@ -303,42 +333,6 @@ TEST_CASE("copy version constructor", M) {
REQUIRE(copy2.package() == &pkg);
}
-TEST_CASE("version operators", M) {
- SECTION("equality") {
- REQUIRE(Version("1.0") == Version("1.0"));
- REQUIRE_FALSE(Version("1.0") == Version("1.1"));
- }
-
- SECTION("inequality") {
- REQUIRE_FALSE(Version("1.0") != Version("1.0"));
- REQUIRE(Version("1.0") != Version("1.1"));
- }
-
- SECTION("less than") {
- REQUIRE(Version("1.0") < Version("1.1"));
- REQUIRE_FALSE(Version("1.0") < Version("1.0"));
- REQUIRE_FALSE(Version("1.1") < Version("1.0"));
- }
-
- SECTION("less than or equal") {
- REQUIRE(Version("1.0") <= Version("1.1"));
- REQUIRE(Version("1.0") <= Version("1.0"));
- REQUIRE_FALSE(Version("1.1") <= Version("1.0"));
- }
-
- SECTION("greater than") {
- REQUIRE_FALSE(Version("1.0") > Version("1.1"));
- REQUIRE_FALSE(Version("1.0") > Version("1.0"));
- REQUIRE(Version("1.1") > Version("1.0"));
- }
-
- SECTION("greater than or equal") {
- REQUIRE_FALSE(Version("1.0") >= Version("1.1"));
- REQUIRE(Version("1.0") >= Version("1.0"));
- REQUIRE(Version("1.1") >= Version("1.0"));
- }
-}
-
#ifdef __APPLE__
TEST_CASE("drop windows sources on os x", M) {
MAKE_VERSION