diff options
-rw-r--r-- | libbutl/standard-version.ixx | 34 | ||||
-rw-r--r-- | libbutl/standard-version.mxx | 54 | ||||
-rw-r--r-- | tests/standard-version/driver.cxx | 117 | ||||
-rw-r--r-- | tests/standard-version/testscript | 130 |
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 : |