aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2019-01-11 23:56:54 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2019-01-13 20:26:46 +0300
commitf7dc4934b04c062b1ce8aad09725a30707255e69 (patch)
tree08e147151569dce6475d1b60e35ebd0df4309253
parent17be80bea48c942c9496d079e07bc15a27a5d7a2 (diff)
Improve standard version API
-rw-r--r--libbutl/standard-version.ixx34
-rw-r--r--libbutl/standard-version.mxx54
-rw-r--r--tests/standard-version/driver.cxx117
-rw-r--r--tests/standard-version/testscript130
4 files changed, 258 insertions, 77 deletions
diff --git a/libbutl/standard-version.ixx b/libbutl/standard-version.ixx
index 66dccba..7e282f8 100644
--- a/libbutl/standard-version.ixx
+++ b/libbutl/standard-version.ixx
@@ -40,28 +40,38 @@ namespace butl
return static_cast<std::uint16_t> (v / 1000 % 1000);
}
- inline std::uint16_t standard_version::
- pre_release () const noexcept
+ inline bool standard_version::
+ release () const noexcept
{
- std::uint64_t ab (version / 10 % 1000);
- if (ab >= 500)
- ab -= 500;
+ return version % 10000 == 0;
+ }
- return static_cast<std::uint16_t> (ab);
+ inline optional<std::uint16_t> standard_version::
+ pre_release () const noexcept
+ {
+ return release () || stub ()
+ ? nullopt
+ : optional<std::uint16_t> (version / 10 % 1000);
}
- inline bool standard_version::
+ inline optional<std::uint16_t> standard_version::
alpha () const noexcept
{
- std::uint64_t abe (version % 10000);
- return abe > 0 && abe < 5000 && !stub ();
+ optional<std::uint16_t> pr (pre_release ());
+ return pr && *pr < 500 ? pr : nullopt;
}
- inline bool standard_version::
+ inline optional<std::uint16_t> standard_version::
beta () const noexcept
{
- std::uint64_t abe (version % 10000);
- return abe > 5000 && !stub ();
+ optional<std::uint16_t> pr (pre_release ());
+ return pr && *pr >= 500 ? optional<std::uint16_t> (*pr - 500) : nullopt;
+ }
+
+ inline bool standard_version::
+ final () const noexcept
+ {
+ return release () || !(snapshot () || stub ());
}
inline bool standard_version::
diff --git a/libbutl/standard-version.mxx b/libbutl/standard-version.mxx
index 1cc557b..ee8e89c 100644
--- a/libbutl/standard-version.mxx
+++ b/libbutl/standard-version.mxx
@@ -42,12 +42,16 @@ import butl.optional;
LIBBUTL_MODEXPORT namespace butl
{
- // The build2 "standard version" (specific, earliest and stub):
+ // The build2 "standard version" (normal, earliest, and stub):
//
// [+<epoch>-]<maj>.<min>.<patch>[-(a|b).<num>[.<snapsn>[.<snapid>]]][+<rev>]
// [+<epoch>-]<maj>.<min>.<patch>-
// 0[+<rev>]
//
+ // The normal version can be release, final pre-release, or a pre-release
+ // snapshot (release is naturally always final). Pre-release can be alpha or
+ // beta.
+ //
// The numeric version format is AAABBBCCCDDDE where:
//
// AAA - major version number
@@ -67,7 +71,7 @@ LIBBUTL_MODEXPORT namespace butl
// 3.0.0-b.2 0029999995020
// 2.2.0-a.1.z 0020019990011
//
- // Stub is represented as ~0.
+ // Stub is represented as ~0 (but is not considered a pre-release).
//
struct LIBBUTL_SYMEXPORT standard_version
{
@@ -93,18 +97,23 @@ LIBBUTL_MODEXPORT namespace butl
std::uint16_t minor () const noexcept;
std::uint16_t patch () const noexcept;
- // The alpha/beta number (decremented by 500 for betas). Note: 0 is
- // ambiguous (can be non-pre-release or -[ab].0.z).
+ // Return the alpha/beta version number if pre-release and nullopt
+ // otherwise.
+ //
+ // Can be used as a predicate and also to get the value.
+ //
+ optional<std::uint16_t> alpha () const noexcept;
+ optional<std::uint16_t> beta () const noexcept;
+
+ // Return the DDD version part if a pre-release and nullopt otherwise.
//
- // @@ Inconsistent with the pre_release argument in constructors
- // below. The whole pre-release interface feels off, maybe we should
- // redo it? I.e., return DDD from pre_release() (though 0 will still be
- // ambigous; maybe DDDE) and have separate functions to get alpha/beta
- // numbers? Maybe alpha()/beta() return optional<std::uint16_t>? Maybe
- // pre-release should return bool (or also optional)?
+ // Can be used as a predicate and also to get the value. Note that 0 is
+ // ambiguous (-[ab].0.z, or earliest version; see below).
//
- std::uint16_t pre_release () const noexcept;
+ optional<std::uint16_t> pre_release () const noexcept;
+ // String representations.
+ //
// Note: return empty if the corresponding component is unspecified.
//
std::string string () const; // Package version.
@@ -114,21 +123,18 @@ LIBBUTL_MODEXPORT namespace butl
std::string string_pre_release () const; // Pre-release part only (a.1).
std::string string_snapshot () const; // Snapshot part only (1234.1f23).
- bool empty () const noexcept {return version == 0;}
-
- bool alpha () const noexcept;
- bool beta () const noexcept;
- bool snapshot () const noexcept {return snapshot_sn != 0;}
-
- // Represented by DDDE in version being 0001 and snapshot_sn being 0.
+ // Predicates. See also alpha(), beta(), and pre_release() above.
//
- // Note that the earliest version is a final alpha pre-release.
+ // The earliest version is represented as the (otherwise illegal) DDDE
+ // value 0001 and snapshot_sn 0. Note that the earliest version is a final
+ // alpha pre-release.
//
- bool
- earliest () const noexcept;
-
- bool
- stub () const noexcept {return version == std::uint64_t (~0);}
+ bool empty () const noexcept {return version == 0;}
+ bool stub () const noexcept {return version == std::uint64_t (~0);}
+ bool earliest () const noexcept;
+ bool release () const noexcept;
+ bool snapshot () const noexcept {return snapshot_sn != 0;}
+ bool final () const noexcept;
// Comparison of empty or stub versions doesn't make sense.
//
diff --git a/tests/standard-version/driver.cxx b/tests/standard-version/driver.cxx
index 7ad5b00..f20eb28 100644
--- a/tests/standard-version/driver.cxx
+++ b/tests/standard-version/driver.cxx
@@ -7,6 +7,7 @@
#ifndef __cpp_lib_modules
#include <ios> // ios::failbit, ios::badbit
#include <string>
+#include <cstdint> // uint*_t
#include <iostream>
#include <stdexcept> // invalid_argument
#endif
@@ -19,16 +20,19 @@ import std.core;
import std.io;
#endif
import butl.utility; // operator<<(ostream,exception), eof()
+import butl.optional;
import butl.standard_version;
#else
#include <libbutl/utility.mxx>
+#include <libbutl/optional.mxx>
#include <libbutl/standard-version.mxx>
#endif
using namespace std;
using namespace butl;
-// Create standard version from string, and also test another ctors.
+// Return the standard version created from a string, and also perform some
+// resulting version tests (check other constructors, invariants, etc.).
//
static standard_version
version (const string& s,
@@ -37,6 +41,8 @@ version (const string& s,
{
standard_version r (s, f);
+ // Test the other constructors.
+ //
try
{
standard_version v (r.epoch,
@@ -76,6 +82,8 @@ version (const string& s,
assert (r == v);
}
+ // Test using the resulting version with shortcut operators.
+ //
if (!r.stub ())
{
auto max_ver = [&v] (char c) -> string
@@ -102,6 +110,29 @@ version (const string& s,
assert (c1 == c2);
}
}
+
+ // Check some invariants for the resulting version.
+ //
+ // Stub is not a final (pre-)release nor snapshot.
+ //
+ assert (!r.stub () || !(r.final () || r.snapshot ()));
+
+ // Earliest is a final alpha.
+ //
+ assert (!r.earliest () || (r.final () && r.alpha ()));
+
+ // Final is a release or a pre-release but not a snapshot.
+ //
+ assert (r.final () ==
+ (r.release () || (r.pre_release () && !r.snapshot ())));
+
+ // Snapshot is a pre-release.
+ //
+ assert (!r.snapshot () || r.pre_release ());
+
+ // Pre-release is either alpha or beta.
+ //
+ assert (r.pre_release ().has_value () == (r.alpha () || r.beta ()));
}
catch (const invalid_argument& e)
{
@@ -114,18 +145,24 @@ version (const string& s,
// Usages:
//
-// argv[0] -a <version>
-// argv[0] -b <version>
-// argv[0] -c <version> <version>
-// argv[0] -r
-// argv[0] -s <version> <constraint>
+// argv[0] (-rl|-pr|-al|-bt|-st|-el|-sn|-fn) <version>
+// argv[0] -cm <version> <version>
+// argv[0] -cr
+// argv[0] -sf <version> <constraint>
// argv[0]
//
-// -a output 'y' for alpha-version, 'n' otherwise
-// -b output 'y' for beta-version, 'n' otherwise
-// -c output 0 if versions are equal, -1 if the first one is less, 1 otherwise
-// -r create version constraints from stdin lines, and print them to stdout
-// -s output 'y' if version satisfies constraint, 'n' otherwise
+// -rl output 'y' for release, 'n' otherwise
+// -pr output DDD version part for pre-release, '-' otherwise
+// -al output alpha version number for alpha-version, '-' otherwise
+// -bt output beta version number for beta-version, '-' otherwise
+// -st output 'y' for stub, 'n' otherwise
+// -el output 'y' for earliest, 'n' otherwise
+// -sn output 'y' for snapshot, 'n' otherwise
+// -fn output 'y' for final, 'n' otherwise
+//
+// -cm output 0 if versions are equal, -1 if the first one is less, 1 otherwise
+// -cr create version constraints from stdin lines, and print them to stdout
+// -sf output 'y' if version satisfies constraint, 'n' otherwise
//
// If no options are specified, then create versions from stdin lines, and
// print them to stdout.
@@ -134,6 +171,8 @@ int
main (int argc, char* argv[])
try
{
+ using butl::optional;
+
cin.exceptions (ios::badbit);
cout.exceptions (ios::failbit | ios::badbit);
@@ -141,28 +180,66 @@ try
{
string o (argv[1]);
- if (o == "-a")
+ if (o == "-rl")
+ {
+ assert (argc == 3);
+ cout << (version (argv[2]).release () ? 'y' : 'n') << endl;
+ }
+ else if (o == "-pr")
{
assert (argc == 3);
- char r (version (argv[2]).alpha () ? 'y' : 'n');
- cout << r << endl;
+ if (optional<uint16_t> n = version (argv[2]).pre_release ())
+ cout << *n << endl;
+ else
+ cout << '-' << endl;
}
- else if (o == "-b")
+ else if (o == "-al")
{
assert (argc == 3);
- char r (version (argv[2]).beta () ? 'y' : 'n');
- cout << r << endl;
+ if (optional<uint16_t> n = version (argv[2]).alpha ())
+ cout << *n << endl;
+ else
+ cout << '-' << endl;
+ }
+ else if (o == "-bt")
+ {
+ assert (argc == 3);
+
+ if (optional<uint16_t> n = version (argv[2]).beta ())
+ cout << *n << endl;
+ else
+ cout << '-' << endl;
+ }
+ else if (o == "-st")
+ {
+ assert (argc == 3);
+ cout << (version (argv[2]).stub () ? 'y' : 'n') << endl;
+ }
+ else if (o == "-el")
+ {
+ assert (argc == 3);
+ cout << (version (argv[2]).earliest () ? 'y' : 'n') << endl;
+ }
+ else if (o == "-sn")
+ {
+ assert (argc == 3);
+ cout << (version (argv[2]).snapshot () ? 'y' : 'n') << endl;
+ }
+ else if (o == "-fn")
+ {
+ assert (argc == 3);
+ cout << (version (argv[2]).final () ? 'y' : 'n') << endl;
}
- else if (o == "-c")
+ else if (o == "-cm")
{
assert (argc == 4);
int r (version (argv[2]).compare (version (argv[3])));
cout << r << endl;
}
- else if (o == "-r")
+ else if (o == "-cr")
{
assert (argc == 2);
@@ -170,7 +247,7 @@ try
while (getline (cin, s))
cout << standard_version_constraint (s) << endl;
}
- else if (o == "-s")
+ else if (o == "-sf")
{
assert (argc == 4);
diff --git a/tests/standard-version/testscript b/tests/standard-version/testscript
index 5b1e8d4..2efec3c 100644
--- a/tests/standard-version/testscript
+++ b/tests/standard-version/testscript
@@ -168,42 +168,130 @@
}
}
+: release
+:
+{
+ test.options += -rl
+
+ $* '1.2.3' >'y' : release
+ $* '1.2.3-b.1' >'n' : beta-final
+ $* '1.2.3-a.1' >'n' : alpha-final
+ $* '1.2.3-a.0.1' >'n' : alpha-snapshot
+ $* '1.2.3-b.0.1' >'n' : beta-snapshot
+ $* '1.2.3-' >'n' : earliest
+ $* '0' >'n' : stub
+}
+
+: pre-release
+:
+{
+ test.options += -pr
+
+ $* '1.2.3' >'-' : release
+ $* '1.2.3-b.1' >'501' : beta-final
+ $* '1.2.3-a.1' >'1' : alpha-final
+ $* '1.2.3-a.0.1' >'0' : alpha-snapshot
+ $* '1.2.3-b.0.1' >'500' : beta-snapshot
+ $* '1.2.3-' >'0' : earliest
+ $* '0' >'-' : stub
+}
+
: alpha
:
{
- test.options += -a
-
- $* '1.2.3' >n: non-prerelease
- $* '1.2.3-b.1' >n: beta
- $* '1.2.3-a.1' >y: final
- $* '1.2.3-a.0.1' >y: snapshot
- $* '1.2.3-' >y: earliest
- $* '0' >n: stub
+ test.options += -al
+
+ $* '1.2.3' >'-' : release
+ $* '1.2.3-b.1' >'-' : beta-final
+ $* '1.2.3-a.1' >'1' : final
+ $* '1.2.3-a.0.1' >'0' : snapshot
+ $* '1.2.3-b.0.1' >'-' : beta-snapshot
+ $* '1.2.3-' >'0' : earliest
+ $* '0' >'-' : stub
}
: beta
:
{
- test.options += -b
-
- $* '1.2.3' >n: non-prerelease
- $* '1.2.3-a.1' >n: alpha
- $* '1.2.3-b.1' >y: final
- $* '1.2.3-b.0.1' >y: snapshot
- $* '1.2.3-' >n: earliest
- $* '0+1' >n: stub
+ test.options += -bt
+
+ $* '1.2.3' >'-' : release
+ $* '1.2.3-a.1' >'-' : alpha
+ $* '1.2.3-b.1' >'1' : final
+ $* '1.2.3-a.0.1' >'-' : alpha-snapshot
+ $* '1.2.3-b.0.1' >'0' : snapshot
+ $* '1.2.3-' >'-' : earliest
+ $* '0+1' >'-' : stub
+}
+
+: stub
+:
+{
+ test.options += -st
+
+ $* '1.2.3' >'n' : release
+ $* '1.2.3-b.1' >'n' : beta-final
+ $* '1.2.3-a.1' >'n' : alpha-final
+ $* '1.2.3-a.0.1' >'n' : alpha-snapshot
+ $* '1.2.3-b.0.1' >'n' : beta-snapshot
+ $* '1.2.3-' >'n' : earliest
+ $* '0' >'y' : stub
+ $* '0+1' >'y' : stub-1
+}
+
+: earliest
+:
+{
+ test.options += -el
+
+ $* '1.2.3' >'n' : release
+ $* '1.2.3-b.1' >'n' : beta-final
+ $* '1.2.3-a.1' >'n' : alpha-final
+ $* '1.2.3-a.0.1' >'n' : alpha-snapshot
+ $* '1.2.3-b.0.1' >'n' : beta-snapshot
+ $* '1.2.3-' >'y' : earliest
+ $* '0+2' >'n' : stub
+}
+
+: snapshot
+:
+{
+ test.options += -sn
+
+ $* '1.2.3' >'n' : release
+ $* '1.2.3-b.1' >'n' : beta-final
+ $* '1.2.3-a.1' >'n' : alpha-final
+ $* '1.2.3-a.0.1' >'y' : alpha
+ $* '1.2.3-b.0.1' >'y' : beta
+ $* '1.2.3-a.1.z' >'y' : latest
+ $* '1.2.3-' >'n' : earliest
+ $* '0' >'n' : stub
+}
+
+: final
+:
+{
+ test.options += -fn
+
+ $* '1.2.3' >'y' : release
+ $* '1.2.3-b.1' >'y' : beta-final
+ $* '1.2.3-a.1' >'y' : alpha-final
+ $* '1.2.3-a.0.1' >'n' : alpha
+ $* '1.2.3-b.0.1' >'n' : beta
+ $* '1.2.3-' >'y' : earliest
+ $* '0' >'n' : stub
}
: compare
:
{
- test.options += -c
+ test.options += -cm
: epoch
:
{
- $* '+4-1.2.3' '+4-1.2.3' >'0' : equal
- $* '1.2.4' '+4-1.2.3' >'-1': less
+ $* '+4-1.2.3' '+4-1.2.3' >'0' : equal
+ $* '1.2.4' '+4-1.2.3' >'-1' : less
}
: non-prerelease
@@ -233,7 +321,7 @@
: constraints
:
{
- test.options += -r
+ test.options += -cr
: range
:
@@ -381,7 +469,7 @@
: satisfaction
:
{
- test.options += -s
+ test.options += -sf
: comparison
: