diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ca3e38..e6b95f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,3 +38,4 @@ enable_testing() add_test(NAME semver200_parser_tests COMMAND semver200_parser_tests) add_test(NAME semver200_comparator_tests COMMAND semver200_comparator_tests) add_test(NAME semver200_version_tests COMMAND semver200_version_tests) +add_test(NAME semver200_modifier_tests COMMAND semver200_modifier_tests) diff --git a/README.md b/README.md index 7cdf7f1..5d0997c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # About -This project is MIT-licensed, C++14 implementation of [semantic versioning](http://semver.org) parser and comparator. Semantic versioning 2.0.0 specification is supported out-of-the-box and the code should be flexible-enough to support future revisions or other similar versioning schemes. +This project is MIT-licensed, C++14 implementation of [semantic versioning](http://semver.org) parser and comparator with support for modifying parsed version strings. Semantic versioning 2.0.0 specification is supported out-of-the-box and the code should be flexible-enough to support future revisions or other similar versioning schemes. # Usage Parsing and comparing two version strings: @@ -42,8 +42,46 @@ Pre-release: alpha.1 Build: build.no.123 ``` +Parsed version object supports a few modification methods. All modification methods are non-destructive i.e. they return new objects with modified properties and original objects are never changed. You can: + +- set major, minor, patch, pre-release or build version to desired value while keeping other fields unchanged; +- reset major, minor, patch, pre-release or build version to desired value by resetting lower-priority fields to zero/empty values (Priority is major > minor > patch > pre-release > build); +- increase/decrease major, minor or patch version by desired increment (can be negative); this is reset-type operation which will zero/empty lower priority fields. + +A few examples of version modifications: + +```c++ +#include "semver200.h" + +void main(int, char**) { + version::Semver200_version v("1.2.3-alpha.1+build.no.123"); + std::cout << "Next major version: " << v.inc_major() << std::endl; + std::cout << "Next but one major: " << v.inc_major(2) << std::endl; + std::cout << "Next minor version: " << v.inc_minor() << std::endl; + std::cout << "Previous minor version: " << v.inc_minor(-1) << std::endl; + std::cout << "Next patch version: " << v.inc_patch() << std::endl; + std::cout << "Change pre-release: " << v.set_prerelease("beta.3") << std::endl; + std::cout << "Change build: " << v.set_build("170105") << std::endl; + std::cout << "Set major to 3, minor to 1: " << v.set_major(3).set_minor(1) << std::endl; + std::cout << "Reset major to 3, minor to 1: " << v.reset_major(3).reset_minor(1) << std::endl; +} +``` + +should generate following output: +``` +Next major version: 2.0.0 +Next but one major: 3.0.0 +Next minor version: 1.3.0 +Previous minor version: 1.1.0 +Next patch version: 1.2.4 +Change pre-release: 1.2.3-beta.3+build.no.123 +Change build: 1.2.3-alpha.1+170105 +Set major to 3, minor to 1: 3.1.3-alpha.1+build.no.123 +Reset major to 3, minor to 1: 3.1.0 +``` + # Build -The code is written in C++14, so, fairly recent compiler is required to build it. Following compiler were tested: +The code is written in C++14, so, fairly recent compiler is required to build it. Following compilers were tested: - Microsoft Visual Studio 2015 - GCC 5.1.1 - Clang 3.7.0 diff --git a/include/semver200.h b/include/semver200.h index 7f5bbc4..813dbdb 100644 --- a/include/semver200.h +++ b/include/semver200.h @@ -38,14 +38,51 @@ namespace version { int compare(const Version_data&, const Version_data&) const; }; + /// Implementation of various version modification methods. + /** + All methods are non-destructive, i.e. they return a new object with modified properties; + original object is never modified. + */ + struct Semver200_modifier { + /// Set major version to specified value leaving all other components unchanged.. + Version_data set_major(const Version_data&, const int) const; + + /// Set minor version to specified value leaving all other components unchanged. + Version_data set_minor(const Version_data&, const int) const; + + /// Set patch version to specified value leaving all other components unchanged. + Version_data set_patch(const Version_data&, const int) const; + + /// Set pre-release version to specified value leaving all other components unchanged. + Version_data set_prerelease(const Version_data&, const Prerelease_identifiers&) const; + + /// Set build version to specified value leaving all other components unchanged. + Version_data set_build(const Version_data&, const Build_identifiers&) const; + + /// Set major version to specified value resetting all lower-priority components to zero/empty values. + Version_data reset_major(const Version_data&, const int) const; + + /// Set minor version to specified value resetting all lower-priority components to zero/empty values. + Version_data reset_minor(const Version_data&, const int) const; + + /// Set patch version to specified value resetting all lower-priority components to zero/empty values. + Version_data reset_patch(const Version_data&, const int) const; + + /// Set pre-release version to specified value resetting all lower-priority components to zero/empty values. + Version_data reset_prerelease(const Version_data&, const Prerelease_identifiers&) const; + + /// Set build version to specified value. + Version_data reset_build(const Version_data&, const Build_identifiers&) const; + }; + /// Concrete version class that binds all semver 2.0.0 functionality together. - class Semver200_version : public Basic_version { + class Semver200_version : public Basic_version { public: Semver200_version() - : Basic_version{ Semver200_parser(), Semver200_comparator() } {} + : Basic_version{ Semver200_parser(), Semver200_comparator(), Semver200_modifier() } {} Semver200_version(const std::string& v) - : Basic_version{ v, Semver200_parser(), Semver200_comparator() } {} + : Basic_version{ v, Semver200_parser(), Semver200_comparator(), Semver200_modifier() } {} }; } \ No newline at end of file diff --git a/include/version.h b/include/version.h index 58e2613..0922a61 100644 --- a/include/version.h +++ b/include/version.h @@ -35,6 +35,11 @@ namespace version { using std::runtime_error::runtime_error; }; + /// Any error in manipulating version data will result in Modification_error exception being thrown. + class Modification_error : public std::runtime_error { + using std::runtime_error::runtime_error; + }; + /// Type of prerelease identifier: alphanumeric or numeric. /** Type of identifier affects comparison: alphanumeric identifiers are compared as ASCII strings, while @@ -64,6 +69,10 @@ namespace version { /// Description of version broken into parts, as per semantic versioning specification. struct Version_data { + + Version_data(const int M, const int m, const int p, const Prerelease_identifiers& pr, const Build_identifiers& b) + : major{ M }, minor{ m }, patch{ p }, prerelease_ids{ pr }, build_ids{ b } {} + int major; ///< Major version, change only on incompatible API modifications. int minor; ///< Minor version, change on backwards-compatible API modifications. int patch; ///< Patch version, change only on bugfixes. @@ -76,59 +85,62 @@ namespace version { }; // Forward declaration required for operators' template declarations. - template + template class Basic_version; /// Test if left-hand version operand is of lower precedence than the right-hand version. - template - bool operator<(const Basic_version&, - const Basic_version&); + template + bool operator<(const Basic_version&, + const Basic_version&); /// Test if left-hand version operand if of equal precedence as the right-hand version. - template - bool operator==(const Basic_version&, - const Basic_version&); + template + bool operator==(const Basic_version&, + const Basic_version&); /// Output version object to stream using standard semver format (X.Y.Z-PR+B). - template + template std::ostream& operator<<(std::ostream&, - const Basic_version&); + const Basic_version&); /// Test if left-hand version and right-hand version are of different precedence. - template - bool operator!=(const Basic_version&, - const Basic_version&); + template + bool operator!=(const Basic_version&, + const Basic_version&); /// Test if left-hand version operand is of higher precedence than the right-hand version. - template - bool operator>(const Basic_version&, - const Basic_version&); + template + bool operator>(const Basic_version&, + const Basic_version&); /// Test if left-hand version operand is of higher or equal precedence as the right-hand version. - template - bool operator>=(const Basic_version&, - const Basic_version&); + template + bool operator>=(const Basic_version&, + const Basic_version&); /// Test if left-hand version operand is of lower or equal precedence as the right-hand version. - template - bool operator<=(const Basic_version&, - const Basic_version&); + template + bool operator<=(const Basic_version&, + const Basic_version&); - /// Base class for various version parsing and precedence ordering schemes. + /// Base class for various version parsing, precedence ordering and data manipulation schemes. /** Basic_version class describes general version object without prescribing parsing, - validation and comparison rules. These rules are implemented by supplied Parser and - Comparator objects. + validation, comparison and modification rules. These rules are implemented by supplied Parser, Comparator + and Modifier objects. */ - template + template class Basic_version { public: - /// Construct Basic_version object using Parser object to parse default ("0.0.0") version string and Comparator for comparison. - Basic_version(Parser, Comparator); + /// Construct Basic_version object using Parser object to parse default ("0.0.0") version string, Comparator for comparison and Modifier for modification. + Basic_version(Parser, Comparator, Modifier); - /// Construct Basic_version object using Parser to parse supplied version string and Comparator for comparison. - Basic_version(const std::string&, Parser, Comparator); + /// Construct Basic_version object using Parser to parse supplied version string, Comparator for comparison and Modifier for modification. + Basic_version(const std::string&, Parser, Comparator, Modifier); + + /// Construct Basic_version object using supplied Version_data, Parser, Comparator and Modifier objects. + Basic_version(const Version_data&, Parser, Comparator, Modifier); /// Construct Basic_version by copying data from another one. Basic_version(const Basic_version&); @@ -142,6 +154,55 @@ namespace version { const std::string prerelease() const; ///< Get prerelease version string. const std::string build() const; ///< Get build version string. + /// Return a copy of version with major component set to specified value. + Basic_version set_major(const int) const; + + /// Return a copy of version with the minor component set to specified value. + Basic_version set_minor(const int) const; + + /// Return a copy of version with the patch component set to specified value. + Basic_version set_patch(const int) const; + + /// Return a copy of version with the pre-release component set to specified value. + Basic_version set_prerelease(const std::string&) const; + + /// Return a copy of version with the build component set to specified value. + Basic_version set_build(const std::string&) const; + + /// Return a copy of version with the major component reset to specified value. + /** + Exact implementation of reset is delegated to Modifier object. + */ + Basic_version reset_major(const int) const; + + /// Return a copy of version with the minor component reset to specified value. + /** + Exact implementation of reset is delegated to Modifier object. + */ + Basic_version reset_minor(const int) const; + + /// Return a copy of version with the patch component reset to specified value. + /** + Exact implementation of reset is delegated to Modifier object. + */ + Basic_version reset_patch(const int) const; + + /// Return a copy of version with the pre-release component reset to specified value. + /** + Exact implementation of reset is delegated to Modifier object. + */ + Basic_version reset_prerelease(const std::string&) const; + + /// Return a copy of version with the build component reset to specified value. + /** + Exact implementation of reset is delegated to Modifier object. + */ + Basic_version reset_build(const std::string&) const; + + Basic_version inc_major(const int = 1) const; + Basic_version inc_minor(const int = 1) const; + Basic_version inc_patch(const int = 1) const; + friend bool operator< <>(const Basic_version&, const Basic_version&); friend bool operator== <>(const Basic_version&, const Basic_version&); friend std::ostream& operator<< <>(std::ostream&s, const Basic_version&); @@ -149,6 +210,7 @@ namespace version { private: Parser parser_; Comparator comparator_; + Modifier modifier_; Version_data ver_; }; } diff --git a/include/version.inl b/include/version.inl index c2e5e76..edaa2ff 100644 --- a/include/version.inl +++ b/include/version.inl @@ -45,66 +45,140 @@ namespace version { } } - template - Basic_version::Basic_version(Parser p, Comparator c) - : parser_(p), comparator_(c), ver_(parser_.parse("0.0.0")) {} + template + Basic_version::Basic_version(Parser p, Comparator c, Modifier m) + : parser_(p), comparator_(c), modifier_(m), ver_(parser_.parse("0.0.0")) {} - template - Basic_version::Basic_version(const std::string& v, Parser p, Comparator c) - : parser_(p), comparator_(c), ver_(parser_.parse(v)) {} + template + Basic_version::Basic_version(const std::string& v, Parser p, Comparator c, Modifier m) + : parser_(p), comparator_(c), modifier_(m), ver_(parser_.parse(v)) {} - template - Basic_version::Basic_version(const Basic_version&) = default; + template + Basic_version::Basic_version(const Version_data& v, Parser p, Comparator c, Modifier m) + : parser_(p), comparator_(c), modifier_(m), ver_(v) {} - template - Basic_version& Basic_version::operator=( - const Basic_version&) = default; + template + Basic_version::Basic_version(const Basic_version&) = default; - template - int Basic_version::major() const { + template + Basic_version& Basic_version::operator=( + const Basic_version&) = default; + + template + int Basic_version::major() const { return ver_.major; } - template - int Basic_version::minor() const { + template + int Basic_version::minor() const { return ver_.minor; } - template - int Basic_version::patch() const { + template + int Basic_version::patch() const { return ver_.patch; } - template - const std::string Basic_version::prerelease() const { + template + const std::string Basic_version::prerelease() const { std::stringstream ss; splice(ss, ver_.prerelease_ids, ".", [](const auto& id) { return id.first;}); return ss.str(); } - template - const std::string Basic_version::build() const { + template + const std::string Basic_version::build() const { std::stringstream ss; splice(ss, ver_.build_ids, ".", [](const auto& id) { return id;}); return ss.str(); } + template + Basic_version Basic_version::set_major(const int m) const { + return Basic_version(modifier_.set_major(ver_, m), parser_, comparator_, modifier_); + } - template - bool operator<(const Basic_version& l, - const Basic_version& r) { + template + Basic_version Basic_version::set_minor(const int m) const { + return Basic_version(modifier_.set_minor(ver_, m), parser_, comparator_, modifier_); + } + + template + Basic_version Basic_version::set_patch(const int p) const { + return Basic_version(modifier_.set_patch(ver_, p), parser_, comparator_, modifier_); + } + + template + Basic_version Basic_version::set_prerelease(const std::string& pr) const { + auto vd = parser_.parse("0.0.0-" + pr); + return Basic_version(modifier_.set_prerelease(ver_, vd.prerelease_ids), parser_, comparator_, modifier_); + } + + template + Basic_version Basic_version::set_build(const std::string& b) const { + auto vd = parser_.parse("0.0.0+" + b); + return Basic_version(modifier_.set_build(ver_, vd.build_ids), parser_, comparator_, modifier_); + } + + template + Basic_version Basic_version::reset_major(const int m) const { + return Basic_version(modifier_.reset_major(ver_, m), parser_, comparator_, modifier_); + } + + template + Basic_version Basic_version::reset_minor(const int m) const { + return Basic_version(modifier_.reset_minor(ver_, m), parser_, comparator_, modifier_); + } + + template + Basic_version Basic_version::reset_patch(const int p) const { + return Basic_version(modifier_.reset_patch(ver_, p), parser_, comparator_, modifier_); + } + + template + Basic_version Basic_version::reset_prerelease(const std::string& pr) const { + std::string ver = "0.0.0-" + pr; + auto vd = parser_.parse(ver); + return Basic_version(modifier_.reset_prerelease(ver_, vd.prerelease_ids), parser_, comparator_, modifier_); + } + + template + Basic_version Basic_version::reset_build(const std::string& b) const { + std::string ver = "0.0.0+" + b; + auto vd = parser_.parse(ver); + return Basic_version(modifier_.reset_build(ver_, vd.build_ids), parser_, comparator_, modifier_); + } + + template + Basic_version Basic_version::inc_major(const int i) const { + return reset_major(ver_.major + i); + } + + template + Basic_version Basic_version::inc_minor(const int i) const { + return reset_minor(ver_.minor + i); + } + + template + Basic_version Basic_version::inc_patch(const int i) const { + return reset_patch(ver_.patch + i); + } + + template + bool operator<(const Basic_version& l, + const Basic_version& r) { return l.comparator_.compare(l.ver_, r.ver_) == -1; } - template - bool operator==(const Basic_version& l, - const Basic_version& r) { + template + bool operator==(const Basic_version& l, + const Basic_version& r) { return l.comparator_.compare(l.ver_, r.ver_) == 0; } - template + template std::ostream& operator<<(std::ostream& os, - const Basic_version& v) { + const Basic_version& v) { os << v.ver_.major << "." << v.ver_.minor << "." << v.ver_.patch; std::string prl = v.prerelease(); if (!prl.empty()) { @@ -117,27 +191,27 @@ namespace version { return os; } - template - inline bool operator!=(const Basic_version& l, - const Basic_version& r) { + template + inline bool operator!=(const Basic_version& l, + const Basic_version& r) { return !(l == r); } - template - inline bool operator>(const Basic_version& l, - const Basic_version& r) { + template + inline bool operator>(const Basic_version& l, + const Basic_version& r) { return r < l; } - template - inline bool operator>=(const Basic_version& l, - const Basic_version& r) { + template + inline bool operator>=(const Basic_version& l, + const Basic_version& r) { return !(l < r); } - template - inline bool operator<=(const Basic_version& l, - const Basic_version& r) { + template + inline bool operator<=(const Basic_version& l, + const Basic_version& r) { return !(l > r); } } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f02845b..9059c49 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,5 +3,5 @@ include_directories( ) add_library(semver - Semver200_comparator.cpp Semver200_parser.cpp + Semver200_comparator.cpp Semver200_parser.cpp Semver200_modifier.cpp ) diff --git a/src/Semver200_modifier.cpp b/src/Semver200_modifier.cpp new file mode 100644 index 0000000..af9423a --- /dev/null +++ b/src/Semver200_modifier.cpp @@ -0,0 +1,75 @@ +/* +The MIT License (MIT) + +Copyright (c) 2015 Marko Zivanovic + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include +#include "semver200.h" + +namespace version { + + Version_data Semver200_modifier::set_major(const Version_data& s, const int m) const { + if (m < 0) throw Modification_error("major version cannot be less than 0"); + return Version_data{ m, s.minor, s.patch, s.prerelease_ids, s.build_ids }; + } + + Version_data Semver200_modifier::set_minor(const Version_data& s, const int m) const { + if (m < 0) throw Modification_error("minor version cannot be less than 0"); + return Version_data{ s.major, m, s.patch, s.prerelease_ids, s.build_ids }; + } + + Version_data Semver200_modifier::set_patch(const Version_data& s, const int p) const { + if (p < 0) throw Modification_error("patch version cannot be less than 0"); + return Version_data{ s.major, s.minor, p, s.prerelease_ids, s.build_ids }; + } + + Version_data Semver200_modifier::set_prerelease(const Version_data& s, const Prerelease_identifiers& pr) const { + return Version_data{ s.major, s.minor, s.patch, pr, s.build_ids }; + } + + Version_data Semver200_modifier::set_build(const Version_data& s, const Build_identifiers& b) const { + return Version_data{ s.major, s.minor, s.patch, s.prerelease_ids, b }; + } + + Version_data Semver200_modifier::reset_major(const Version_data& s, const int m) const { + if (m < 0) throw Modification_error("major version cannot be less than 0"); + return Version_data{ m, 0, 0, Prerelease_identifiers{}, Build_identifiers{} }; + } + + Version_data Semver200_modifier::reset_minor(const Version_data& s, const int m) const { + if (m < 0) throw Modification_error("minor version cannot be less than 0"); + return Version_data{ s.major, m, 0, Prerelease_identifiers{}, Build_identifiers{} }; + } + + Version_data Semver200_modifier::reset_patch(const Version_data& s, const int p) const { + if (p < 0) throw Modification_error("patch version cannot be less than 0"); + return Version_data{ s.major, s.minor, p, Prerelease_identifiers{}, Build_identifiers{} }; + } + + Version_data Semver200_modifier::reset_prerelease(const Version_data& s, const Prerelease_identifiers& pr) const { + return Version_data{ s.major, s.minor, s.patch, pr, Build_identifiers{} }; + } + + Version_data Semver200_modifier::reset_build(const Version_data& s, const Build_identifiers& b) const { + return Version_data{ s.major, s.minor, s.patch, s.prerelease_ids, b }; + } +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index dc8cbd2..b2fefe8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -26,3 +26,9 @@ target_link_libraries(semver200_version_tests ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} semver ) + +add_executable(semver200_modifier_tests semver200_modifier_tests.cpp clang_fixes.cpp) +target_link_libraries(semver200_modifier_tests + ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} + semver +) diff --git a/test/semver200_modifier_tests.cpp b/test/semver200_modifier_tests.cpp new file mode 100644 index 0000000..9bdb868 --- /dev/null +++ b/test/semver200_modifier_tests.cpp @@ -0,0 +1,314 @@ + +/* +The MIT License (MIT) + +Copyright (c) 2017 Marko Zivanovic + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#define BOOST_TEST_MODULE semver200_modifier_tests + +#include +#include +#include "semver200.h" + +using namespace version; + +Semver200_comparator c; +Semver200_parser p; +Semver200_modifier m; + +#define CHECK_SRC { \ + BOOST_CHECK(v.major() == 1); \ + BOOST_CHECK(v.minor() == 2); \ + BOOST_CHECK(v.patch() == 3); \ + BOOST_CHECK(v.prerelease() == "pre.rel.0"); \ + BOOST_CHECK(v.build() == "build.no.321"); \ +} + +BOOST_AUTO_TEST_CASE(set_major) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + auto v2 = v.set_major(2); + + // Check if setter works as expected + BOOST_CHECK(v2.major() == 2); + BOOST_CHECK(v2.minor() == 2); + BOOST_CHECK(v2.patch() == 3); + BOOST_CHECK(v2.prerelease() == "pre.rel.0"); + BOOST_CHECK(v2.build() == "build.no.321"); + + // Check invalid values + BOOST_CHECK_THROW(v.set_major(-1), version::Modification_error); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(set_minor) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + auto v2 = v.set_minor(3); + + // Check if setter works as expected + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 3); + BOOST_CHECK(v2.patch() == 3); + BOOST_CHECK(v2.prerelease() == "pre.rel.0"); + BOOST_CHECK(v2.build() == "build.no.321"); + + // Check invalid values + BOOST_CHECK_THROW(v.set_minor(-1), version::Modification_error); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(set_patch) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + auto v2 = v.set_patch(4); + + // Check if setter works as expected + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 2); + BOOST_CHECK(v2.patch() == 4); + BOOST_CHECK(v2.prerelease() == "pre.rel.0"); + BOOST_CHECK(v2.build() == "build.no.321"); + + // Check invalid values + BOOST_CHECK_THROW(v.set_patch(-1), version::Modification_error); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(set_prerelease) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + auto v2 = v.set_prerelease("alpha.1"); + + // Check if setter works as expected + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 2); + BOOST_CHECK(v2.patch() == 3); + BOOST_CHECK(v2.prerelease() == "alpha.1"); + BOOST_CHECK(v2.build() == "build.no.321"); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(set_build) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + auto v2 = v.set_build("b123"); + + // Check if setter works as expected + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 2); + BOOST_CHECK(v2.patch() == 3); + BOOST_CHECK(v2.prerelease() == "pre.rel.0"); + BOOST_CHECK(v2.build() == "b123"); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(reset_major) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + auto v2 = v.reset_major(2); + + // Check if setter works as expected + BOOST_CHECK(v2.major() == 2); + BOOST_CHECK(v2.minor() == 0); + BOOST_CHECK(v2.patch() == 0); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check invalid values + BOOST_CHECK_THROW(v.reset_major(-1), version::Modification_error); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(reset_minor) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + auto v2 = v.reset_minor(3); + + // Check if setter works as expected + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 3); + BOOST_CHECK(v2.patch() == 0); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check invalid values + BOOST_CHECK_THROW(v.reset_minor(-1), version::Modification_error); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(reset_patch) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + auto v2 = v.reset_patch(4); + + // Check if setter works as expected + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 2); + BOOST_CHECK(v2.patch() == 4); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check invalid values + BOOST_CHECK_THROW(v.reset_patch(-1), version::Modification_error); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(reset_prerelease) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + auto v2 = v.reset_prerelease("alpha.1"); + + // Check if setter works as expected + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 2); + BOOST_CHECK(v2.patch() == 3); + BOOST_CHECK(v2.prerelease() == "alpha.1"); + BOOST_CHECK(v2.build() == ""); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(reset_build) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + auto v2 = v.reset_build("b123"); + + // Check if setter works as expected + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 2); + BOOST_CHECK(v2.patch() == 3); + BOOST_CHECK(v2.prerelease() == "pre.rel.0"); + BOOST_CHECK(v2.build() == "b123"); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(inc_major) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + + // Check default increment + auto v2 = v.inc_major(); + BOOST_CHECK(v2.major() == 2); + BOOST_CHECK(v2.minor() == 0); + BOOST_CHECK(v2.patch() == 0); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check non-default increment + auto v2 = v.inc_major(3); + BOOST_CHECK(v2.major() == 4); + BOOST_CHECK(v2.minor() == 0); + BOOST_CHECK(v2.patch() == 0); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check negative increment + v2 = v.inc_major(-1); + BOOST_CHECK(v2.major() == 0); + BOOST_CHECK(v2.minor() == 0); + BOOST_CHECK(v2.patch() == 0); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check too negative increment + BOOST_CHECK_THROW(v.inc_major(-2), version::Modification_error); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(inc_minor) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + + // Check default increment + auto v2 = v.inc_minor(); + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 3); + BOOST_CHECK(v2.patch() == 0); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check non-default increment + auto v2 = v.inc_minor(3); + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 5); + BOOST_CHECK(v2.patch() == 0); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check negative increment + v2 = v.inc_minor(-1); + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 1); + BOOST_CHECK(v2.patch() == 0); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check too negative increment + BOOST_CHECK_THROW(v.inc_minor(-3), version::Modification_error); + + // Check source version is unaffected + CHECK_SRC +} + +BOOST_AUTO_TEST_CASE(inc_patch) { + Semver200_version v("1.2.3-pre.rel.0+build.no.321"); + + // Check default increment + auto v2 = v.inc_patch(); + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 2); + BOOST_CHECK(v2.patch() == 4); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check default increment + auto v2 = v.inc_patch(3); + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 2); + BOOST_CHECK(v2.patch() == 6); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check negative increment + v2 = v.inc_patch(-1); + BOOST_CHECK(v2.major() == 1); + BOOST_CHECK(v2.minor() == 2); + BOOST_CHECK(v2.patch() == 2); + BOOST_CHECK(v2.prerelease() == ""); + BOOST_CHECK(v2.build() == ""); + + // Check too negative increment + BOOST_CHECK_THROW(v.inc_patch(-4), version::Modification_error); + + // Check source version is unaffected + CHECK_SRC +}