diff --git a/Makefile.am b/Makefile.am
index 37c66c2723..ead0a906a2 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -82,6 +82,7 @@ src_libbitcoin_system_la_SOURCES = \
src/config/transaction.cpp \
src/config/url.cpp \
src/config/utilities.cpp \
+ src/config/version.cpp \
src/crypto/aes256.cpp \
src/crypto/der_parser.cpp \
src/crypto/ec_context.cpp \
@@ -261,6 +262,7 @@ test_libbitcoin_system_test_SOURCES = \
test/config/printer.cpp \
test/config/url.cpp \
test/config/utilities.cpp \
+ test/config/version.cpp \
test/crypto/aes256.cpp \
test/crypto/elliptic_curve.cpp \
test/crypto/pseudo_random.cpp \
@@ -533,7 +535,8 @@ include_bitcoin_system_config_HEADERS = \
include/bitcoin/system/config/script.hpp \
include/bitcoin/system/config/transaction.hpp \
include/bitcoin/system/config/url.hpp \
- include/bitcoin/system/config/utilities.hpp
+ include/bitcoin/system/config/utilities.hpp \
+ include/bitcoin/system/config/version.hpp
include_bitcoin_system_cryptodir = ${includedir}/bitcoin/system/crypto
include_bitcoin_system_crypto_HEADERS = \
diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt
index 5c4ddbe36a..c39ed1cfbc 100644
--- a/builds/cmake/CMakeLists.txt
+++ b/builds/cmake/CMakeLists.txt
@@ -515,6 +515,7 @@ add_library( ${CANONICAL_LIB_NAME}
"../../src/config/transaction.cpp"
"../../src/config/url.cpp"
"../../src/config/utilities.cpp"
+ "../../src/config/version.cpp"
"../../src/crypto/aes256.cpp"
"../../src/crypto/der_parser.cpp"
"../../src/crypto/ec_context.cpp"
@@ -740,6 +741,7 @@ if (with-tests)
"../../test/config/printer.cpp"
"../../test/config/url.cpp"
"../../test/config/utilities.cpp"
+ "../../test/config/version.cpp"
"../../test/crypto/aes256.cpp"
"../../test/crypto/elliptic_curve.cpp"
"../../test/crypto/pseudo_random.cpp"
diff --git a/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj b/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj
index bf96c9857f..034c8c48fc 100644
--- a/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj
@@ -161,6 +161,7 @@
+
diff --git a/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj.filters
index 43f0d7bbaf..55ea6c40bb 100644
--- a/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj.filters
@@ -219,6 +219,9 @@
src\config
+
+ src\config
+
src
diff --git a/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj b/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj
index 29d3fa8ec5..f60c785e59 100644
--- a/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj
@@ -195,6 +195,7 @@
+
@@ -357,6 +358,7 @@
+
diff --git a/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj.filters
index 05e1e4e235..96733c97c8 100644
--- a/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj.filters
@@ -381,6 +381,9 @@
src\config
+
+ src\config
+
src\crypto
@@ -821,6 +824,9 @@
include\bitcoin\system\config
+
+ include\bitcoin\system\config
+
include\bitcoin\system
diff --git a/include/bitcoin/system/chain/header.hpp b/include/bitcoin/system/chain/header.hpp
index 96806ca82e..00fd8cb509 100644
--- a/include/bitcoin/system/chain/header.hpp
+++ b/include/bitcoin/system/chain/header.hpp
@@ -81,7 +81,6 @@ class BC_API header
void to_data(std::ostream& stream) const NOEXCEPT;
void to_data(writer& sink) const NOEXCEPT;
-
/// Properties.
/// -----------------------------------------------------------------------
/// Native properties.
@@ -96,6 +95,7 @@ class BC_API header
/// Computed properties.
uint256_t proof() const NOEXCEPT;
hash_digest hash() const NOEXCEPT;
+ double difficulty() const NOEXCEPT;
/// Cache and metadata.
/// -----------------------------------------------------------------------
diff --git a/include/bitcoin/system/config/config.hpp b/include/bitcoin/system/config/config.hpp
index 43f8f6acb4..9f7ab489cd 100644
--- a/include/bitcoin/system/config/config.hpp
+++ b/include/bitcoin/system/config/config.hpp
@@ -41,5 +41,6 @@
#include
#include
#include
+#include
#endif
diff --git a/include/bitcoin/system/config/version.hpp b/include/bitcoin/system/config/version.hpp
new file mode 100644
index 0000000000..86fda560e8
--- /dev/null
+++ b/include/bitcoin/system/config/version.hpp
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#ifndef LIBBITCOIN_SYSTEM_CONFIG_VERSION_HPP
+#define LIBBITCOIN_SYSTEM_CONFIG_VERSION_HPP
+
+#include
+#include
+
+namespace libbitcoin {
+namespace system {
+namespace config {
+
+/// Container for a protocol version tuple with up to four segments.
+/// Segments are non-negative integers, padded with zeros for fewer than four.
+/// The format is major.minor[.subminor[.patch]] with at least one dot.
+class BC_API version
+{
+public:
+ typedef std::shared_ptr ptr;
+
+ DEFAULT_COPY_MOVE_DESTRUCT(version);
+
+ version() NOEXCEPT;
+
+ /// Deserialize from dotted string (throws on invalid format).
+ version(const std::string& version_str) THROWS;
+
+ /// Construct from individual segments (2 to 4, pads with zeros).
+ version(uint32_t major, uint32_t minor, uint32_t subminor={},
+ uint32_t patch={}) NOEXCEPT;
+
+ /// Properties.
+ /// -----------------------------------------------------------------------
+
+ /// Access to the internal segments array.
+ const std::array& segments() const NOEXCEPT;
+
+ /// Methods.
+ /// -----------------------------------------------------------------------
+
+ /// The version is 0.0.0.0.
+ bool is_default() const NOEXCEPT;
+
+ /// Serialize to dot string, omitting trailing zero segments (minimum 2).
+ std::string to_string() const NOEXCEPT;
+
+ /// Operators.
+ /// -----------------------------------------------------------------------
+
+ /// Deserialize from input stream (throws on invalid format).
+ friend std::istream& operator>>(std::istream& input, version& argument) THROWS;
+
+ /// Serialize to output stream.
+ friend std::ostream& operator<<(std::ostream& output,
+ const version& argument) NOEXCEPT;
+
+private:
+ // This is not thread safe.
+ std::array segments_;
+};
+
+/// Lexicographical comparison.
+BC_API bool operator==(const version& left, const version& right) NOEXCEPT;
+BC_API bool operator!=(const version& left, const version& right) NOEXCEPT;
+BC_API bool operator<(const version& left, const version& right) NOEXCEPT;
+BC_API bool operator<=(const version& left, const version& right) NOEXCEPT;
+BC_API bool operator>(const version& left, const version& right) NOEXCEPT;
+BC_API bool operator>=(const version& left, const version& right) NOEXCEPT;
+
+typedef std::vector versions;
+
+} // namespace config
+} // namespace system
+} // namespace libbitcoin
+
+namespace std
+{
+template<>
+struct hash
+{
+ size_t operator()(const bc::system::config::version& value) const NOEXCEPT
+ {
+ return std::hash{}(value.to_string());
+ }
+};
+} // namespace std
+
+#endif
diff --git a/include/bitcoin/system/impl/serial/deserialize.ipp b/include/bitcoin/system/impl/serial/deserialize.ipp
index 91718427d2..4f492c3a68 100644
--- a/include/bitcoin/system/impl/serial/deserialize.ipp
+++ b/include/bitcoin/system/impl/serial/deserialize.ipp
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -107,7 +108,14 @@ bool deserialize(Value& out, const std::string_view& text) NOEXCEPT
// This can convert garbage to zero, use is_ascii_number for pre-assurance.
try
{
- std::istringstream istream(trim_copy(text));
+ auto trimmed = trim_copy(text);
+ if constexpr (is_integer && !is_signed)
+ {
+ if (!trimmed.empty() && trimmed.front() == '-')
+ return false;
+ }
+
+ std::istringstream istream(std::move(trimmed));
istream >> out;
return !istream.fail();
}
diff --git a/src/chain/header.cpp b/src/chain/header.cpp
index 725a204cbb..4c414a87b8 100644
--- a/src/chain/header.cpp
+++ b/src/chain/header.cpp
@@ -268,6 +268,29 @@ hash_digest header::hash() const NOEXCEPT
return digest;
}
+// computed, not used in consensus.
+double header::difficulty() const NOEXCEPT
+{
+ auto shift = bit_and(shift_right(bits_, 24), 0xff_u32);
+ auto difference =
+ static_cast(0x0000ffff_u32) /
+ static_cast(bit_and(bits_, 0x00ffffff_u32));
+
+ while (shift < 29u)
+ {
+ difference *= 256.0;
+ ++shift;
+ }
+
+ while (shift > 29u)
+ {
+ difference /= 256.0;
+ --shift;
+ }
+
+ return difference;
+}
+
// Cache and metadata.
// ----------------------------------------------------------------------------
diff --git a/src/config/version.cpp b/src/config/version.cpp
new file mode 100644
index 0000000000..95d7e209c4
--- /dev/null
+++ b/src/config/version.cpp
@@ -0,0 +1,154 @@
+/**
+ * Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace libbitcoin {
+namespace system {
+namespace config {
+
+// Contructors.
+// ----------------------------------------------------------------------------
+
+// Default version is 0.0.0.0 and serializes as "0.0".
+version::version() NOEXCEPT
+ : segments_{}
+{
+}
+
+version::version(const std::string& version) THROWS
+ : segments_{}
+{
+ std::istringstream(version) >> (*this);
+}
+
+version::version(uint32_t major, uint32_t minor, uint32_t subminor,
+ uint32_t patch) NOEXCEPT
+ : segments_{ major, minor, subminor, patch }
+{
+}
+
+// Properties.
+// ----------------------------------------------------------------------------
+
+const std::array& version::segments() const NOEXCEPT
+{
+ return segments_;
+}
+
+// Methods.
+// ----------------------------------------------------------------------------
+
+bool version::is_default() const NOEXCEPT
+{
+ constexpr std::array default_{};
+ return segments_ == default_;
+}
+
+std::string version::to_string() const NOEXCEPT
+{
+ std::ostringstream value{};
+ value << (*this);
+ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
+ return value.str();
+ BC_POP_WARNING()
+}
+
+// Operators.
+// ----------------------------------------------------------------------------
+
+bool operator==(const version& left, const version& right) NOEXCEPT
+{
+ return left.segments() == right.segments();
+}
+
+bool operator!=(const version& left, const version& right) NOEXCEPT
+{
+ return !(left == right);
+}
+
+bool operator<(const version& left, const version& right) NOEXCEPT
+{
+ return std::lexicographical_compare(
+ left.segments().begin(), left.segments().end(),
+ right.segments().begin(), right.segments().end());
+}
+
+bool operator<=(const version& left, const version& right) NOEXCEPT
+{
+ return left < right || left == right;
+}
+
+bool operator>(const version& left, const version& right) NOEXCEPT
+{
+ return right < left;
+}
+
+bool operator>=(const version& left, const version& right) NOEXCEPT
+{
+ return right <= left;
+}
+
+std::istream& operator>>(std::istream& input,
+ version& argument) THROWS
+{
+ std::string value;
+ input >> value;
+
+ using namespace system;
+ const auto tokens = system::split(value, ".");
+ const auto count = tokens.size();
+ if (count < 2u || count > 4u)
+ throw istream_exception(value);
+
+ argument = {};
+ for (size_t index{}; index < count; ++index)
+ if (!deserialize(argument.segments_.at(index), tokens.at(index)))
+ throw istream_exception(value);
+
+ return input;
+}
+
+std::ostream& operator<<(std::ostream& output,
+ const version& argument) NOEXCEPT
+{
+ size_t last{ 3 };
+ while (last > 1u && is_zero(argument.segments_.at(last)))
+ --last;
+
+ for (size_t index{}; index <= last; ++index)
+ {
+ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
+ if (!is_zero(index)) output << '.';
+ output << argument.segments_.at(index);
+ BC_POP_WARNING()
+ }
+
+ return output;
+}
+
+} // namespace config
+} // namespace system
+} // namespace libbitcoin
diff --git a/test/chain/header.cpp b/test/chain/header.cpp
index 9c268e02ea..799bc7cbda 100644
--- a/test/chain/header.cpp
+++ b/test/chain/header.cpp
@@ -240,14 +240,20 @@ BOOST_AUTO_TEST_CASE(header__to_data__writer__expected)
// properties
// ----------------------------------------------------------------------------
-// hash
-
BOOST_AUTO_TEST_CASE(header__proof__genesis_block__expected)
{
const chain::block block{ settings(selection::mainnet).genesis_block };
BOOST_REQUIRE_EQUAL(block.header().proof(), 0x0000000100010001);
}
+// hash
+
+BOOST_AUTO_TEST_CASE(header__difficulty__genesis_block__expected)
+{
+ const chain::block block{ settings(selection::mainnet).genesis_block };
+ BOOST_REQUIRE_EQUAL(block.header().difficulty(), 1.0);
+}
+
// validation (public)
// ----------------------------------------------------------------------------
diff --git a/test/config/version.cpp b/test/config/version.cpp
new file mode 100644
index 0000000000..762eb78347
--- /dev/null
+++ b/test/config/version.cpp
@@ -0,0 +1,284 @@
+/**
+ * Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#include "../test.hpp"
+#include
+
+BOOST_AUTO_TEST_SUITE(version_tests)
+
+using namespace bc::system::config;
+using namespace boost::program_options;
+
+BOOST_AUTO_TEST_CASE(version__construct__default__zero_segments)
+{
+ const version instance;
+ const auto& segments = instance.segments();
+ BOOST_REQUIRE_EQUAL(segments[0], 0u);
+ BOOST_REQUIRE_EQUAL(segments[1], 0u);
+ BOOST_REQUIRE_EQUAL(segments[2], 0u);
+ BOOST_REQUIRE_EQUAL(segments[3], 0u);
+ BOOST_REQUIRE(instance.is_default());
+}
+
+BOOST_AUTO_TEST_CASE(version__construct__non_default__expected_segments)
+{
+ const version instance("1.2.3.4");
+ const auto& segments = instance.segments();
+ BOOST_REQUIRE_EQUAL(segments[0], 1u);
+ BOOST_REQUIRE_EQUAL(segments[1], 2u);
+ BOOST_REQUIRE_EQUAL(segments[2], 3u);
+ BOOST_REQUIRE_EQUAL(segments[3], 4u);
+ BOOST_REQUIRE(!instance.is_default());
+}
+
+BOOST_AUTO_TEST_CASE(version__construct__string_invalid_too_few_segments__throws_istream_exception)
+{
+ BOOST_REQUIRE_THROW(version("1"), istream_exception);
+}
+
+BOOST_AUTO_TEST_CASE(version__construct__string_invalid_too_many_segments__throws_istream_exception)
+{
+ BOOST_REQUIRE_THROW(version("1.2.3.4.5"), istream_exception);
+}
+
+BOOST_AUTO_TEST_CASE(version__construct__string_invalid_non_numeric__throws_istream_exception)
+{
+ BOOST_REQUIRE_THROW(version("1.a"), istream_exception);
+}
+
+BOOST_AUTO_TEST_CASE(version__construct__string_invalid_negative__throws_istream_exception)
+{
+ BOOST_REQUIRE_THROW(version("1.-2"), istream_exception);
+}
+
+BOOST_AUTO_TEST_CASE(version__construct__string_invalid_out_of_range__throws_istream_exception)
+{
+ BOOST_REQUIRE_THROW(version("1.4294967296"), istream_exception);
+}
+
+BOOST_AUTO_TEST_CASE(version__construct__segments_two__padded_zeros)
+{
+ const version instance(1u, 2u);
+ const auto& segments = instance.segments();
+ BOOST_REQUIRE_EQUAL(segments[0], 1u);
+ BOOST_REQUIRE_EQUAL(segments[1], 2u);
+ BOOST_REQUIRE_EQUAL(segments[2], 0u);
+ BOOST_REQUIRE_EQUAL(segments[3], 0u);
+}
+
+BOOST_AUTO_TEST_CASE(version__construct__segments_three__padded_zero)
+{
+ const version instance(1u, 2u, 3u);
+ const auto& segments = instance.segments();
+ BOOST_REQUIRE_EQUAL(segments[0], 1u);
+ BOOST_REQUIRE_EQUAL(segments[1], 2u);
+ BOOST_REQUIRE_EQUAL(segments[2], 3u);
+ BOOST_REQUIRE_EQUAL(segments[3], 0u);
+}
+
+BOOST_AUTO_TEST_CASE(version__construct__segments_four__expected)
+{
+ const version instance(1u, 2u, 3u, 4u);
+ const auto& segments = instance.segments();
+ BOOST_REQUIRE_EQUAL(segments[0], 1u);
+ BOOST_REQUIRE_EQUAL(segments[1], 2u);
+ BOOST_REQUIRE_EQUAL(segments[2], 3u);
+ BOOST_REQUIRE_EQUAL(segments[3], 4u);
+}
+
+BOOST_AUTO_TEST_CASE(version__is_default__default__true)
+{
+ const version instance;
+ BOOST_REQUIRE(instance.is_default());
+}
+
+BOOST_AUTO_TEST_CASE(version__is_default__non_default__false)
+{
+ const version instance(1u, 0u);
+ BOOST_REQUIRE(!instance.is_default());
+}
+
+BOOST_AUTO_TEST_CASE(version__is_default__zero_segments__true)
+{
+ const version instance(0u, 0u, 0u, 0u);
+ BOOST_REQUIRE(instance.is_default());
+}
+
+BOOST_AUTO_TEST_CASE(version__is_default__partial_zeros__false)
+{
+ const version instance(0u, 0u, 1u, 0u);
+ BOOST_REQUIRE(!instance.is_default());
+}
+
+BOOST_AUTO_TEST_CASE(version__to_string__two_segments__expected)
+{
+ const version instance(1u, 2u);
+ BOOST_REQUIRE_EQUAL(instance.to_string(), "1.2");
+}
+
+BOOST_AUTO_TEST_CASE(version__to_string__three_segments__expected_no_trailing_zero)
+{
+ const version instance(1u, 2u, 3u);
+ BOOST_REQUIRE_EQUAL(instance.to_string(), "1.2.3");
+}
+
+BOOST_AUTO_TEST_CASE(version__to_string__four_segments_trailing_zero__omits_trailing_zero)
+{
+ const version instance(1u, 2u, 3u, 0u);
+ BOOST_REQUIRE_EQUAL(instance.to_string(), "1.2.3");
+}
+
+BOOST_AUTO_TEST_CASE(version__to_string__default__minimum_two_segments)
+{
+ const version instance;
+ BOOST_REQUIRE_EQUAL(instance.to_string(), "0.0");
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_shift_right__valid__deserializes)
+{
+ version instance;
+ std::istringstream input("1.2.3");
+ input >> instance;
+ const auto& segments = instance.segments();
+ BOOST_REQUIRE_EQUAL(segments[0], 1u);
+ BOOST_REQUIRE_EQUAL(segments[1], 2u);
+ BOOST_REQUIRE_EQUAL(segments[2], 3u);
+ BOOST_REQUIRE_EQUAL(segments[3], 0u);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_shift_right__invalid__throws_istream_exception)
+{
+ version instance;
+ std::istringstream input("1.a");
+ BOOST_REQUIRE_THROW(input >> instance, istream_exception);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_shift_left__valid__serializes)
+{
+ const version instance(1u, 2u, 3u);
+ std::ostringstream output;
+ output << instance;
+ BOOST_REQUIRE_EQUAL(output.str(), "1.2.3");
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_equal__same__true)
+{
+ const version a(1u, 2u, 3u, 4u);
+ const version b(1u, 2u, 3u, 4u);
+ BOOST_REQUIRE(a == b);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_equal__different__false)
+{
+ const version a(1u, 2u, 3u, 4u);
+ const version b(1u, 2u, 3u, 5u);
+ BOOST_REQUIRE(!(a == b));
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_not_equal__same__false)
+{
+ const version a(1u, 2u, 3u, 4u);
+ const version b(1u, 2u, 3u, 4u);
+ BOOST_REQUIRE(!(a != b));
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_not_equal__different__true)
+{
+ const version a(1u, 2u, 3u, 4u);
+ const version b(1u, 2u, 3u, 5u);
+ BOOST_REQUIRE(a != b);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_less__prefix_shorter__true)
+{
+ const version a(1u, 2u, 3u);
+ const version b(1u, 2u, 3u, 1u);
+ BOOST_REQUIRE(a < b);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_less__prefix_longer__false)
+{
+ const version a(1u, 2u, 3u, 1u);
+ const version b(1u, 2u, 3u);
+ BOOST_REQUIRE(!(a < b));
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_less__differing_component__expected)
+{
+ const version a(1u, 2u, 4u);
+ const version b(1u, 3u, 0u);
+ BOOST_REQUIRE(a < b);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_less_equal__equal__true)
+{
+ const version a(1u, 2u, 3u, 4u);
+ const version b(1u, 2u, 3u, 4u);
+ BOOST_REQUIRE(a <= b);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_less_equal__less__true)
+{
+ const version a(1u, 2u, 3u);
+ const version b(1u, 2u, 3u, 1u);
+ BOOST_REQUIRE(a <= b);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_less_equal__greater__false)
+{
+ const version a(1u, 2u, 3u, 1u);
+ const version b(1u, 2u, 3u);
+ BOOST_REQUIRE(!(a <= b));
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_greater__prefix_longer__true)
+{
+ const version a(1u, 2u, 3u, 1u);
+ const version b(1u, 2u, 3u);
+ BOOST_REQUIRE(a > b);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_greater__prefix_shorter__false)
+{
+ const version a(1u, 2u, 3u);
+ const version b(1u, 2u, 3u, 1u);
+ BOOST_REQUIRE(!(a > b));
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_greater_equal__equal__true)
+{
+ const version a(1u, 2u, 3u, 4u);
+ const version b(1u, 2u, 3u, 4u);
+ BOOST_REQUIRE(a >= b);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_greater_equal__greater__true)
+{
+ const version a(1u, 2u, 3u, 1u);
+ const version b(1u, 2u, 3u);
+ BOOST_REQUIRE(a >= b);
+}
+
+BOOST_AUTO_TEST_CASE(version__operator_greater_equal__less__false)
+{
+ const version a(1u, 2u, 3u);
+ const version b(1u, 2u, 3u, 1u);
+ BOOST_REQUIRE(!(a >= b));
+}
+
+BOOST_AUTO_TEST_SUITE_END()