aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-12-23 17:48:21 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-01-08 16:07:37 +0200
commit8e1998d8ebdb9ead5e432201998cb4db70918f95 (patch)
tree8ea6cc85665e77e65b8bfa4eb16a10256ed449c4
parent9863b40b7d3df92f1a6b975b372586fbc0c6b404 (diff)
Support version release
-rw-r--r--bpkg/manifest32
-rw-r--r--bpkg/manifest.cxx266
-rw-r--r--tests/manifest/packages20
-rw-r--r--tests/package-version/driver.cxx165
4 files changed, 358 insertions, 125 deletions
diff --git a/bpkg/manifest b/bpkg/manifest
index 1d554d4..e53bc69 100644
--- a/bpkg/manifest
+++ b/bpkg/manifest
@@ -7,6 +7,7 @@
#include <string>
#include <vector>
+#include <cassert>
#include <cstdint> // uint16_t
#include <ostream>
#include <algorithm> // move()
@@ -31,12 +32,17 @@ namespace bpkg
//
const std::uint16_t epoch;
const std::string upstream;
+ const std::string release;
const std::uint16_t revision;
// Upstream part canonical representation.
//
const std::string canonical_upstream;
+ // Release part canonical representation.
+ //
+ const std::string canonical_release;
+
// Create a special empty version.
//
version (): epoch (0), revision (0) {}
@@ -48,13 +54,14 @@ namespace bpkg
version (const std::string& v): version (v.c_str ()) {}
explicit
- version (const char* v): version (data_type (v, false)) {}
+ version (const char* v): version (data_type (v, data_type::parse::full)) {}
- // Create the version object from separate epoch, upstream, and
+ // Create the version object from separate epoch, upstream, release, and
// revision parts.
//
version (std::uint16_t epoch,
std::string upstream,
+ std::string release,
std::uint16_t revision);
version (version&&) = default;
@@ -92,6 +99,9 @@ namespace bpkg
if (int c = canonical_upstream.compare (v.canonical_upstream))
return c;
+ if (int c = canonical_release.compare (v.canonical_release))
+ return c;
+
if (!ignore_revision && revision != v.revision)
return revision < v.revision ? -1 : 1;
@@ -101,30 +111,34 @@ namespace bpkg
bool
empty () const noexcept
{
- // No sense to test epoch and revision for 0 as properly constructed
- // version object can not have them different from 0 if upstream is
- // empty.
- //
- return upstream.empty ();
+ bool e (upstream.empty ());
+ assert (!e || (epoch == 0 && release.empty () && revision == 0));
+ return e;
}
private:
struct data_type
{
- data_type (const char*, bool upstream_only);
+ enum class parse {full, upstream, release};
+
+ data_type (const char*, parse);
std::uint16_t epoch;
std::string upstream;
+ std::string release;
std::uint16_t revision;
std::string canonical_upstream;
+ std::string canonical_release;
};
explicit
version (data_type&& d)
: epoch (d.epoch),
upstream (std::move (d.upstream)),
+ release (std::move (d.release)),
revision (d.revision),
- canonical_upstream (std::move (d.canonical_upstream)) {}
+ canonical_upstream (std::move (d.canonical_upstream)),
+ canonical_release (std::move (d.canonical_release)) {}
};
inline std::ostream&
diff --git a/bpkg/manifest.cxx b/bpkg/manifest.cxx
index 20ded6d..cca4e9d 100644
--- a/bpkg/manifest.cxx
+++ b/bpkg/manifest.cxx
@@ -10,7 +10,7 @@
#include <ostream>
#include <sstream>
#include <cassert>
-#include <cstring> // strncmp()
+#include <cstring> // strncmp(), strcmp()
#include <utility> // move()
#include <cstdint> // uint64_t, uint16_t, UINT16_MAX
#include <iterator> // back_insert_iterator
@@ -178,17 +178,68 @@ namespace bpkg
// version
//
version::
- version (uint16_t e, std::string u, uint16_t r)
+ version (uint16_t e, std::string u, std::string l, uint16_t r)
: epoch (e),
upstream (move (u)),
+ release (move (l)),
revision (r),
canonical_upstream (
- data_type (upstream.c_str (), true).canonical_upstream)
+ data_type (upstream.c_str (), data_type::parse::upstream).
+ canonical_upstream),
+ canonical_release (
+ data_type (release.c_str (), data_type::parse::release).
+ canonical_release)
{
+ if (release.empty () && r != 0)
+ // Empty release signifies the earliest possible release. Revision is
+ // meaningless in such a context.
+ //
+ throw invalid_argument ("revision for earliest possible release");
}
+ // Builder of the upstream or release version part canonical representation.
+ //
+ struct canonical_part: string
+ {
+ string
+ final () const {return substr (0, len_);}
+
+ void
+ add (const char* begin, const char* end, bool numeric)
+ {
+ if (!empty ())
+ append (1, '.');
+
+ bool zo (false); // Digit-only zero component.
+ if (numeric)
+ {
+ if (end - begin > 8)
+ throw invalid_argument ("8 digits maximum allowed in a component");
+
+ append (8 - (end - begin), '0'); // Add padding spaces.
+
+ string c (begin, end);
+ append (c);
+ zo = stoul (c) == 0;
+ }
+ else
+ {
+ for (const char* i (begin); i != end; ++i)
+ append (1, lowercase (*i));
+ }
+
+ if (!zo)
+ len_ = size ();
+ }
+
+ private:
+ // Length without trailing digit-only zero components.
+ //
+ size_t len_{0};
+ };
+
version::data_type::
- data_type (const char* v, bool upstream_only): epoch (0), revision (0)
+ data_type (const char* v, parse pr): epoch (0), revision (0)
{
// Otherwise compiler gets confused with string() member.
//
@@ -196,6 +247,14 @@ namespace bpkg
assert (v != nullptr);
+ if (pr == parse::release && strcmp (v, "~") == 0)
+ {
+ // Special case: composing final version release part.
+ //
+ canonical_release = v;
+ return;
+ }
+
auto bad_arg ([](const string& d) {throw invalid_argument (d);});
auto uint16 (
@@ -209,58 +268,40 @@ namespace bpkg
return static_cast<uint16_t> (v);
});
- auto add_canonical_component (
- [this, &bad_arg](const char* b, const char* e, bool numeric) -> bool
- {
- auto& cu (canonical_upstream);
-
- if (!cu.empty ())
- cu.append (1, '.');
-
- if (numeric)
- {
- if (e - b > 8)
- bad_arg ("8 digits maximum allowed in a component");
+ enum class mode {epoch, upstream, release, revision};
+ mode m (pr == parse::full
+ ? mode::epoch
+ : pr == parse::upstream
+ ? mode::upstream
+ : mode::release);
- cu.append (8 - (e - b), '0'); // Add padding spaces.
+ canonical_part canon_upstream;
+ canonical_part canon_release;
- string c (b, e);
- cu.append (c);
- return stoul (c) != 0;
- }
- else
- {
- for (const char* i (b); i != e; ++i)
- cu.append (1, lowercase (*i));
-
- return true;
- }
- });
-
- enum class mode {epoch, upstream, revision} m (mode::epoch);
+ canonical_part* canon_part (
+ pr == parse::release ? &canon_release : &canon_upstream);
const char* cb (v); // Begin of a component.
- const char* ub (v); // Begin of upstream component.
- const char* ue (v); // End of upstream component.
+ const char* ub (v); // Begin of upstream part.
+ const char* ue (v); // End of upstream part.
+ const char* rb (v); // Begin of release part.
+ const char* re (v); // End of release part.
const char* lnn (v - 1); // Last non numeric char.
- // Length of upstream version canonical representation without trailing
- // digit-only zero components.
- //
- size_t cl (0);
-
const char* p (v);
for (char c; (c = *p) != '\0'; ++p)
{
switch (c)
{
- case '+':
+ case '~':
{
- if (upstream_only)
- bad_arg ("unexpected '+' character");
+ if (pr != parse::full)
+ bad_arg ("unexpected '~' character");
+ // Process the epoch part.
+ //
if (m != mode::epoch || p == v)
- bad_arg ("unexpected '+' character position");
+ bad_arg ("unexpected '~' character position");
if (lnn >= cb) // Contains non-digits.
bad_arg ("epoch should be 2-byte unsigned integer");
@@ -272,25 +313,52 @@ namespace bpkg
break;
}
+ case '+':
case '-':
+ case '.':
{
- if (upstream_only)
- bad_arg ("unexpected '-' character");
+ // Process the upsteam or release part component.
+ //
- // No break, go to the next case.
- }
+ // Characters '+', '-' are only valid for the full version parsing.
+ //
+ if (c != '.' && pr != parse::full)
+ bad_arg (string ("unexpected '") + c + "' character");
- case '.':
- {
- if ((m != mode::epoch && m != mode::upstream) || p == cb)
+ // Check if the component ending is valid for the current parsing
+ // state.
+ //
+ if (m == mode::revision || (c == '-' && m == mode::release) ||
+ p == cb)
bad_arg (string ("unexpected '") + c + "' character position");
- if (add_canonical_component (cb, p, lnn < cb))
- cl = canonical_upstream.size ();
+ // Append the component to the current canonical part.
+ //
+ canon_part->add (cb, p, lnn < cb);
- ue = p;
- m = c == '-' ? mode::revision : mode::upstream;
+ // Update the parsing state.
+ //
cb = p + 1;
+
+ if (m == mode::upstream || m == mode::epoch)
+ ue = p;
+ else if (m == mode::release)
+ re = p;
+ else
+ assert (false);
+
+ if (c == '+')
+ m = mode::revision;
+ else if (c == '-')
+ {
+ m = mode::release;
+ canon_part = &canon_release;
+ rb = cb;
+ re = cb;
+ }
+ else if (m == mode::epoch)
+ m = mode::upstream;
+
break;
}
default:
@@ -304,9 +372,15 @@ namespace bpkg
lnn = p;
}
- if (p == cb)
+ assert (p >= cb); // 'p' denotes the end of the last component.
+
+ // An empty component is valid for the release part only.
+ //
+ if (p == cb && m != mode::release)
bad_arg ("unexpected end");
+ // Parse the last component.
+ //
if (m == mode::revision)
{
if (lnn >= cb) // Contains non-digits.
@@ -314,20 +388,64 @@ namespace bpkg
revision = uint16 (cb, "revision");
}
- else
+ else if (cb != p)
{
- if (add_canonical_component (cb, p, lnn < cb))
- cl = canonical_upstream.size ();
+ canon_part->add (cb, p, lnn < cb);
- ue = p;
+ if (m == mode::epoch || m == mode::upstream)
+ ue = p;
+ else if (m == mode::release)
+ re = p;
}
- assert (ub != ue); // Can't happen if through all previous checks.
+ // Upstream and release pointer ranges are valid at the and of the day.
+ //
+ assert (ub <= ue && rb <= re);
- if (!upstream_only)
- upstream.assign (ub, ue);
+ if (pr != parse::release)
+ {
+ // Fill upstream original and canonical parts.
+ //
+ assert (ub != ue); // Can't happen if through all previous checks.
+ canonical_upstream = canon_upstream.final ();
- canonical_upstream.resize (cl);
+ if (pr == parse::full)
+ upstream.assign (ub, ue);
+ }
+
+ if (pr != parse::upstream)
+ {
+ // Fill release original and canonical parts.
+ //
+ if (!canon_release.empty ())
+ {
+ assert (rb != re); // Can't happen if through all previous checks.
+ canonical_release = canon_release.final ();
+
+ if (pr == parse::full)
+ release.assign (rb, re);
+ }
+ else
+ {
+ if (m == mode::release)
+ {
+ // Empty release part signifies the earliest possible version
+ // release. Do nothing, keep original and canonical representations
+ // empty.
+ //
+ }
+ else
+ {
+ // Absent release part signifies the final (max) version release.
+ // Assign the special value to canonical and original representations.
+ //
+ canonical_release = "~";
+
+ if (pr == parse::full)
+ release = "~";
+ }
+ }
+ }
}
version& version::
@@ -352,11 +470,19 @@ namespace bpkg
string version::
string (bool ignore_revision) const
{
- std::string v (epoch != 0 ? to_string (epoch) + "+" + upstream : upstream);
+ std::string v (epoch != 0 ? to_string (epoch) + "~" + upstream : upstream);
- if (!ignore_revision && revision != 0)
+ // The empty version represented as an empty string.
+ //
+ if (!empty () && release != "~")
{
v += '-';
+ v += release;
+ }
+
+ if (!ignore_revision && revision != 0)
+ {
+ v += '+';
v += to_string (revision);
}
@@ -476,6 +602,12 @@ namespace bpkg
{
bad_value (string ("invalid package version: ") + e.what ());
}
+
+ // Versions like 1.2.3- are forbidden in manifest as intended to be
+ // used for version constrains rather than actual releases.
+ //
+ if (version.release.empty ())
+ bad_name ("invalid package version release");
}
else if (n == "summary")
{
@@ -806,6 +938,7 @@ namespace bpkg
serialize (serializer& s) const
{
// @@ Should we check that all non-optional values are specified ?
+ // @@ Should we check the version release is not empty ?
//
s.next ("", "1"); // Start of manifest.
@@ -1382,8 +1515,9 @@ namespace bpkg
return *role;
}
else
- return location.empty () ?
- repository_role::base : repository_role::prerequisite;
+ return location.empty ()
+ ? repository_role::base
+ : repository_role::prerequisite;
}
// repository_manifests
diff --git a/tests/manifest/packages b/tests/manifest/packages
index 9ae65bc..d2058e3 100644
--- a/tests/manifest/packages
+++ b/tests/manifest/packages
@@ -1,20 +1,20 @@
: 1
name: libfoo
-version: 1.2.3-2
+version: 1.2.3+2
priority: high; Due to critical bug fix.
summary: Modern XML parser
license: LGPLv2, MIT; Both required.
license: BSD
tags: c++, xml, parser, serializer, pull, streaming, modern
description: libfoo is a very modern C++ XML parser.
-changes: 1.2.3-2: applied upstream patch for critical bug bar
-changes: 1.2.3-1: applied upstream patch for critical bug foo
+changes: 1.2.3+2: applied upstream patch for critical bug bar
+changes: 1.2.3+1: applied upstream patch for critical bug foo
changes-file: NEWS
url: http://www.example.org/projects/libfoo/; libfoo project page url
-package-url: http://www.example.org/projects/libbar/1.2.3-2; package url
+package-url: http://www.example.org/projects/libbar/1.2.3+2; package url
email: libfoo-users@example.org; Public mailing list, posts by non-members\
are allowed but moderated.
-package-email: libfoo-1.2.3-2@example.org; Bug reports are welcome.
+package-email: libfoo-1.2.3+2@example.org; Bug reports are welcome.
depends: libz
depends: libgnutls <= 1.2.3 | libopenssl >= 2.3.4
depends: ? libboost-regex >= 1.52.0; Only if C++ compiler doesn't support\
@@ -26,22 +26,22 @@ requires: ? ; VC++ 12.0 or later if targeting Windows.
requires: ? ; libc++ standard library if using Clang on Mac OS X.
requires: zlib; Most Linux/UNIX systems already have one; or get it at\
www.zlib.net.
-location: libfoo-1.2.3-2.tar.bz2
+location: libfoo-1.2.3+2.tar.bz2
:
name: libbar
-version: 3.4A.5-6
+version: 3.4A.5+6
summary: Modern bar management framework
license: LGPLv2
tags: c++, xml, modern
description-file: README; Comprehensive description
url: http://www.example.org/projects/libbar/
email: libbar-users@example.org
-location: bar/libbar-3.4A.5-6.tbz
+location: bar/libbar-3.4A.5+6.tbz
:
name: libbaz
-version: 2+3.4A.5-3
+version: 2~3.4A.5+3
summary: Modern baz system
license: LGPLv2
url: http://www.example.org/projects/libbar/
email: libbaz-users@example.org
-location: libbaz/libbaz-2+3.4A.5-3.tar.gz
+location: libbaz/libbaz-2~3.4A.5+3.tar.gz
diff --git a/tests/package-version/driver.cxx b/tests/package-version/driver.cxx
index df4d73b..d28fabf 100644
--- a/tests/package-version/driver.cxx
+++ b/tests/package-version/driver.cxx
@@ -29,11 +29,11 @@ bad_version (const string& v)
}
static bool
-bad_version (uint16_t e, const string& u, uint16_t r)
+bad_version (uint16_t e, const string& u, const string& l, uint16_t r)
{
try
{
- version bv (e, u, r);
+ version bv (e, u, l, r);
return false;
}
catch (const invalid_argument&)
@@ -45,7 +45,7 @@ bad_version (uint16_t e, const string& u, uint16_t r)
static bool
test_constructor (const version& v)
{
- return v == version (v.epoch, v.upstream, v.revision);
+ return v == version (v.epoch, v.upstream, v.release, v.revision);
}
int
@@ -60,31 +60,58 @@ main (int argc, char* argv[])
try
{
assert (bad_version ("")); // Empty upstream.
- assert (bad_version ("1+")); // Same.
- assert (bad_version ("1+-3")); // Same.
- assert (bad_version ("-3")); // Same.
- assert (bad_version ("+3.5")); // Empty epoch.
- assert (bad_version ("a-")); // Empty revision.
- assert (bad_version ("1+2+4.1-3")); // Extra epoch.
- assert (bad_version ("3.5-1-4")); // Extra revision.
- assert (bad_version ("1++2-3")); // Duplicated epoch separator.
- assert (bad_version ("1+2--3")); // Duplicated revision separator.
+ assert (bad_version ("1~")); // Same.
+ assert (bad_version ("1~+3")); // Same.
+ assert (bad_version ("+3")); // Same.
+ assert (bad_version ("1~-a")); // Same.
+ assert (bad_version ("1~-a+3")); // Same.
+ assert (bad_version ("-a+3")); // Same.
+ assert (bad_version ("~3.5")); // Empty epoch.
+ assert (bad_version ("a+")); // Empty revision.
+ assert (bad_version ("1~2~4.1+3")); // Extra epoch.
+ assert (bad_version ("3.5+1+4")); // Extra revision.
+ assert (bad_version ("1~~2+3")); // Duplicated epoch separator.
+ assert (bad_version ("1~2++3")); // Duplicated revision separator.
assert (bad_version ("a.394857391.3")); // Too long numeric component.
assert (bad_version ("a.000000000.3")); // Too long numeric zero component.
- assert (bad_version ("65536+q.3")); // Too big epoch.
- assert (bad_version ("1+q-65536")); // Too big revision.
- assert (bad_version ("3.5+1.4")); // Components in epoch.
- assert (bad_version ("3.5-1.4")); // Components in revision.
- assert (bad_version ("3 5-1")); // Non alpha-numeric in upstream.
- assert (bad_version ("1+ -3")); // Same.
- assert (bad_version ("3 5+4-1")); // Non alpha-numeric in epoch.
- assert (bad_version ("2b+a")); // Same.
- assert (bad_version ("1+34.1-3 5")); // Non alpha-numeric in revision.
- assert (bad_version ("a-3s")); // Same.
+ assert (bad_version ("1-a.000000000")); // Same.
+ assert (bad_version ("65536~q.3")); // Too big epoch.
+ assert (bad_version ("1+q+65536")); // Too big revision.
+ assert (bad_version ("3.5~1.4")); // Components in epoch.
+ assert (bad_version ("3.5+1.4")); // Components in revision.
+ assert (bad_version ("3 5+1")); // Non alpha-numeric in upstream.
+ assert (bad_version ("1~ +3")); // Same.
+ assert (bad_version ("1-3 5+1")); // Non alpha-numeric in release.
+ assert (bad_version ("1~1- +3")); // Same.
+ assert (bad_version ("3 5~4+1")); // Non alpha-numeric in epoch.
+ assert (bad_version ("2b~a")); // Same.
+ assert (bad_version ("1~34.1+3 5")); // Non numeric in revision.
+ assert (bad_version ("a+3s")); // Same.
assert (bad_version ("a.")); // Not completed upstream.
assert (bad_version ("a..b")); // Empty upstream component.
- assert (bad_version (1, "1+1.1", 2)); // Epoch in upstream.
- assert (bad_version (1, "1.1-1", 2)); // Revision in upstream.
+ assert (bad_version ("a.b-+1")); // Revision for empty release.
+
+ assert (bad_version (0, "", "", 0)); // Empty upstream.
+ assert (bad_version (0, "1", "", 1)); // Revision for empty release.
+ assert (bad_version (1, "1~1.1", "~", 2)); // Epoch in upstream.
+ assert (bad_version (1, "1.1-1", "~", 2)); // Release in upstream.
+ assert (bad_version (1, "1.1+1", "~", 2)); // Revision in upstream.
+ assert (bad_version (1, "1", "1~1.1", 2)); // Epoch in release.
+ assert (bad_version (1, "1", "1.1-1", 2)); // Release in release.
+ assert (bad_version (1, "1", "1.1+1", 2)); // Revision in release.
+
+ {
+ version v1;
+ assert (v1.empty ());
+ assert (v1.string ().empty ());
+
+ version v2 ("0.0.0");
+ assert (!v2.empty ());
+
+ // @@ It doesn't look nice.
+ //
+ assert (v1.canonical_upstream == v2.canonical_upstream);
+ }
{
version v ("a");
@@ -94,8 +121,8 @@ main (int argc, char* argv[])
}
{
- version v ("65535+ab-65535");
- assert (v.string () == "65535+ab-65535");
+ version v ("65535~ab+65535");
+ assert (v.string () == "65535~ab+65535");
assert (v.canonical_upstream == "ab");
assert (test_constructor (v));
}
@@ -150,33 +177,81 @@ main (int argc, char* argv[])
}
{
- version v ("1+0");
- assert (v.string () == "1+0");
+ version v ("1~0");
+ assert (v.string () == "1~0");
assert (v.canonical_upstream.empty ());
assert (test_constructor (v));
}
{
- version v ("0+A-1");
- assert (v.string () == "A-1");
+ version v ("0~A+1");
+ assert (v.string () == "A+1");
assert (v.canonical_upstream == "a");
assert (test_constructor (v));
}
{
- version v ("10+B-0");
- assert (v.string () == "10+B");
+ version v ("10~B+0");
+ assert (v.string () == "10~B");
assert (v.canonical_upstream == "b");
assert (test_constructor (v));
}
{
- version v ("3+1A.31.0.4.0-7");
- assert (v.string () == "3+1A.31.0.4.0-7");
+ version v ("3~1A.31.0.4.0+7");
+ assert (v.string () == "3~1A.31.0.4.0+7");
assert (v.canonical_upstream == "1a.00000031.00000000.00000004");
assert (test_constructor (v));
}
+ {
+ version v ("1.2.3");
+ assert (v.string () == "1.2.3");
+ assert (v.release == "~");
+ assert (v.canonical_release == "~");
+ assert (test_constructor (v));
+ }
+
+ {
+ version v ("1.2.3+1");
+ assert (v.string () == "1.2.3+1");
+ assert (v.release == "~");
+ assert (v.canonical_release == "~");
+ assert (test_constructor (v));
+ }
+
+ {
+ version v ("1.2.3-");
+ assert (v.string () == "1.2.3-");
+ assert (v.release.empty ());
+ assert (v.canonical_release.empty ());
+ assert (test_constructor (v));
+ }
+
+ {
+ version v ("1~A-1.2.3B.00+0");
+ assert (v.string () == "1~A-1.2.3B.00");
+ assert (v.release == "1.2.3B.00");
+ assert (v.canonical_release == "00000001.00000002.3b");
+ assert (test_constructor (v));
+ }
+
+ {
+ version v (1, "1", "~", 2);
+ assert (v.string () == "1~1+2");
+ assert (v.release == "~");
+ assert (v.canonical_release == "~");
+ assert (test_constructor (v));
+ }
+
+ {
+ version v (1, "1", "", 0);
+ assert (v.string () == "1~1-");
+ assert (v.release.empty ());
+ assert (v.canonical_release.empty ());
+ assert (test_constructor (v));
+ }
+
assert (version ("a") == version ("a"));
assert (version ("a") < version ("b"));
assert (version ("a") < version ("aa"));
@@ -184,13 +259,13 @@ main (int argc, char* argv[])
assert (version ("a") < version ("a.a"));
assert (version ("ab") == version ("ab"));
assert (version ("ac") < version ("bc"));
- assert (version ("ab-0") == version ("ab"));
- assert (version ("a.1-1") > version ("a.1"));
- assert (version ("0+ab") == version ("ab"));
+ assert (version ("ab+0") == version ("ab"));
+ assert (version ("a.1+1") > version ("a.1"));
+ assert (version ("0~ab") == version ("ab"));
assert (version ("1.2") > version ("1.1"));
- assert (version ("1+1.0") > version ("2.0"));
- assert (version ("0+ab-1") == version ("ab-1"));
- assert (version ("0+ab-1").compare (version ("0+ab-2"), true) == 0);
+ assert (version ("1~1.0") > version ("2.0"));
+ assert (version ("0~ab+1") == version ("ab+1"));
+ assert (version ("0~ab+1").compare (version ("0~ab+2"), true) == 0);
assert (version ("12") > version ("2"));
assert (version ("2") < version ("12"));
assert (version ("1") == version ("01"));
@@ -208,6 +283,16 @@ main (int argc, char* argv[])
assert (version ("1.0.0") == version ("01"));
assert (version ("0.1.00") == version ("00.1"));
assert (version ("0.0a.00") == version ("00.0a"));
+ assert (version ("1.0-alpha") < version ("1.0"));
+ assert (version ("1.0-") < version ("1.0"));
+ assert (version ("1.0-") < version ("1.0-alpha"));
+ assert (version ("1.0-alpha") < version ("1.1"));
+ assert (version ("1.0-alpha+1") < version ("1.0"));
+ assert (version ("1.0-alpha+1") < version ("1.1"));
+ assert (version ("1.0-alpha") > version ("1.0-1"));
+ assert (version ("1.0-alpha") == version ("1.0-alpha.0"));
+ assert (version (1, "2.0", "~", 3) == version ("1~2+3"));
+ assert (version (1, "2.0", "", 0) == version ("1~2-"));
}
catch (const exception& e)
{