diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ab9bb42..d3dee285 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ ACTIVATE_CPP14() ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64) -ADD_GIT_VERSION(Version.h) +ADD_GIT_VERSION(git_version.h) ENABLE_STYLE_WARNINGS() diff --git a/src/main.cpp b/src/main.cpp index b0ffa199..01ad65dd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,7 @@ #include "filesystem/CryDevice.h" #include "config/CryConfigLoader.h" -#include "Version.h" +#include "version/VersionHandler.h" namespace bf = boost::filesystem; @@ -23,7 +23,13 @@ using std::endl; int main (int argc, char *argv[]) { - cout << "CryFS Version "<(bf::path("/home/heinzi/cryfstest/root")); auto config = cryfs::CryConfigLoader().loadOrCreate(bf::path("/home/heinzi/cryfstest/config.json")); cryfs::CryDevice device(std::move(config), std::move(blockStore)); diff --git a/src/version/Version.h b/src/version/Version.h new file mode 100644 index 00000000..042a47aa --- /dev/null +++ b/src/version/Version.h @@ -0,0 +1,61 @@ +#ifndef MESSMER_CRYFS_VERSION_H +#define MESSMER_CRYFS_VERSION_H + +#include + +namespace version { + enum class VersionTag : unsigned char { + ALPHA, BETA, RC1, FINAL + }; + + constexpr const char *VersionTagToString(VersionTag tag) { + return (tag == VersionTag::ALPHA) ? "alpha" : + (tag == VersionTag::BETA) ? "beta" : + (tag == VersionTag::RC1) ? "rc1" : + (tag == VersionTag::FINAL) ? "" : + throw std::logic_error("Unknown version tag"); + } + + class Version { + public: + constexpr Version(unsigned int major, unsigned int minor, VersionTag tag) + : _major(major), _minor(minor), _tag(tag) { } + + constexpr unsigned int major() { + return _major; + } + + constexpr unsigned int minor() { + return _minor; + } + + constexpr VersionTag tag() { + return _tag; + } + + constexpr bool is_stable() { + return _tag == VersionTag::FINAL; + } + + constexpr bool operator==(const Version &rhs) { + return _major == rhs._major && _minor == rhs._minor && _tag == rhs._tag; + } + + constexpr bool operator!=(const Version &rhs) { + return !operator==(rhs); + } + + std::string toString() const { + return std::to_string(_major) + "." + std::to_string(_minor) + VersionTagToString(_tag); + } + + private: + + const unsigned int _major; + const unsigned int _minor; + const VersionTag _tag; + }; +} + + +#endif diff --git a/src/version/VersionHandler.h b/src/version/VersionHandler.h new file mode 100644 index 00000000..a9fb94e0 --- /dev/null +++ b/src/version/VersionHandler.h @@ -0,0 +1,17 @@ +#ifndef MESSMER_CRYFS_VERSIONHANDLER_H +#define MESSMER_CRYFS_VERSIONHANDLER_H + +#include "Version.h" +#include "VersionParser.h" + +namespace git_version_builder { +#include "git_version.h" +} + +namespace version { + constexpr unsigned int COMMITS_SINCE_TAG = git_version_builder::version::COMMITS_SINCE_TAG; + constexpr const char *GIT_COMMIT_ID = git_version_builder::version::GIT_COMMIT_ID; + constexpr const Version VERSION = VersionParser::parse(git_version_builder::version::TAG_NAME); +} + +#endif diff --git a/src/version/VersionParser.h b/src/version/VersionParser.h new file mode 100644 index 00000000..886cbd7a --- /dev/null +++ b/src/version/VersionParser.h @@ -0,0 +1,78 @@ +#ifndef MESSMER_CRYFS_VERSIONPARSER_H +#define MESSMER_CRYFS_VERSIONPARSER_H + +#include +#include +#include "Version.h" + +namespace version { + class VersionParser { + public: + static constexpr Version parse(const char *input) { + return Version(VersionParser::extractMajor(input), + VersionParser::extractMinor(input), + parseTag(extractTag(input))); + } + + static constexpr unsigned int extractMajor(const char *input) { + return parseNumber(input); + } + + static constexpr unsigned int extractMinor(const char *input) { + return (skipNumber(input)[0] == '.') ? parseNumber(skipNumber(input) + 1) + : throw std::logic_error("Minor version should be separated by a dot"); + } + + static constexpr unsigned int parseNumber(const char *input) { + return (isDigit(input[0])) ? parseNumberBackwards(input + numDigits(input) - 1, numDigits(input)) + : throw std::logic_error("Not a valid number"); + } + + static constexpr unsigned int numDigits(const char *input) { + return (isDigit(input[0])) ? (1 + numDigits(input + 1)) : 0; + } + + static constexpr bool isDigit(char digit) { + return digit == '0' || digit == '1' || digit == '2' || digit == '3' || digit == '4' || digit == '5' || + digit == '6' || digit == '7' || digit == '8' || digit == '9'; + } + + static constexpr unsigned char parseDigit(char digit) { + return (digit == '0') ? 0 : + (digit == '1') ? 1 : + (digit == '2') ? 2 : + (digit == '3') ? 3 : + (digit == '4') ? 4 : + (digit == '5') ? 5 : + (digit == '6') ? 6 : + (digit == '7') ? 7 : + (digit == '8') ? 8 : + (digit == '9') ? 9 : + throw std::logic_error("Not a valid digit"); + } + + static constexpr const char *extractTag(const char *input) { + return skipNumber(skipNumber(input) + 1); + } + + static constexpr VersionTag parseTag(const char *input) { + return (0 == strcmp(VersionTagToString(VersionTag::ALPHA), input)) ? VersionTag::ALPHA : + (0 == strcmp(VersionTagToString(VersionTag::BETA), input)) ? VersionTag::BETA : + (0 == strcmp(VersionTagToString(VersionTag::RC1), input)) ? VersionTag::RC1 : + (0 == strcmp(VersionTagToString(VersionTag::FINAL), input)) ? VersionTag::FINAL : + throw std::logic_error("Not a valid version tag"); + } + + static constexpr const char *skipNumber(const char *input) { + return (isDigit(input[0])) ? skipNumber(input + 1) : input; + } + + private: + static constexpr unsigned int parseNumberBackwards(const char *input, unsigned int numDigits) { + return (numDigits == 0) ? 0 : (parseDigit(*input) + 10 * parseNumberBackwards(input - 1, numDigits - 1)); + } + }; +} + +#endif + diff --git a/test/version/Version.cpp b/test/version/Version.cpp new file mode 100644 index 00000000..cf338081 --- /dev/null +++ b/test/version/Version.cpp @@ -0,0 +1,33 @@ +#include "../../src/version/Version.h" + +#include +#include + +using namespace version; + +static_assert(0 == strcmp("alpha", VersionTagToString(VersionTag::ALPHA)), "VersionTag::ALPHA toString"); +static_assert(0 == strcmp("beta", VersionTagToString(VersionTag::BETA)), "VersionTag::BETA toString"); +static_assert(0 == strcmp("rc1", VersionTagToString(VersionTag::RC1)), "VersionTag::RC1 toString"); +static_assert(0 == strlen(VersionTagToString(VersionTag::FINAL)), "VersionTag::FINAL toString"); + +static_assert(Version(1, 0, VersionTag::ALPHA) == Version(1, 0, VersionTag::ALPHA), "Equality for equals"); +static_assert(!(Version(1, 0, VersionTag::ALPHA) != Version(1, 0, VersionTag::ALPHA)), "Inequality for equals"); + +static_assert(!(Version(1, 0, VersionTag::ALPHA) == Version(2, 0, VersionTag::ALPHA)), "Equality for inequal major"); +static_assert(!(Version(1, 0, VersionTag::ALPHA) == Version(1, 1, VersionTag::ALPHA)), "Equality for inequal minor"); +static_assert(!(Version(1, 0, VersionTag::ALPHA) == Version(1, 0, VersionTag::FINAL)), "Equality for inequal tag"); +static_assert(Version(1, 0, VersionTag::ALPHA) != Version(2, 0, VersionTag::ALPHA), "Inequality for inequal major"); +static_assert(Version(1, 0, VersionTag::ALPHA) != Version(1, 1, VersionTag::ALPHA), "Inequality for inequal minor"); +static_assert(Version(1, 0, VersionTag::ALPHA) != Version(1, 0, VersionTag::FINAL), "Inequality for inequal tag"); + +static_assert(!Version(1, 0, VersionTag::ALPHA).is_stable(), "Alpha is not stable"); +static_assert(!Version(1, 0, VersionTag::BETA).is_stable(), "Beta is not stable"); +static_assert(!Version(1, 0, VersionTag::RC1).is_stable(), "RC1 is not stable"); +static_assert(Version(1, 0, VersionTag::FINAL).is_stable(), "Final is stable"); + +TEST(VersionTest, ToString) { + EXPECT_EQ("0.8alpha", Version(0, 8, VersionTag::ALPHA).toString()); + EXPECT_EQ("1.2beta", Version(1, 2, VersionTag::BETA).toString()); + EXPECT_EQ("12.0rc1", Version(12, 0, VersionTag::RC1).toString()); + EXPECT_EQ("12.34", Version(12, 34, VersionTag::FINAL).toString()); +} diff --git a/test/version/VersionParser.cpp b/test/version/VersionParser.cpp new file mode 100644 index 00000000..f93f3564 --- /dev/null +++ b/test/version/VersionParser.cpp @@ -0,0 +1,89 @@ +#include "../../src/version/VersionParser.h" +#include + +using namespace version; + +static_assert(VersionParser::isDigit('0'), "'0' should be recognized as a digit"); +static_assert(VersionParser::isDigit('1'), "'1' should be recognized as a digit"); +static_assert(VersionParser::isDigit('2'), "'2' should be recognized as a digit"); +static_assert(VersionParser::isDigit('3'), "'3' should be recognized as a digit"); +static_assert(VersionParser::isDigit('4'), "'4' should be recognized as a digit"); +static_assert(VersionParser::isDigit('5'), "'5' should be recognized as a digit"); +static_assert(VersionParser::isDigit('6'), "'6' should be recognized as a digit"); +static_assert(VersionParser::isDigit('7'), "'7' should be recognized as a digit"); +static_assert(VersionParser::isDigit('8'), "'8' should be recognized as a digit"); +static_assert(VersionParser::isDigit('9'), "'9' should be recognized as a digit"); +static_assert(!VersionParser::isDigit('a'), "'a' should not be recognized as a digit"); +static_assert(!VersionParser::isDigit('.'), "'.' should not be recognized as a digit"); +static_assert(!VersionParser::isDigit('-'), "'-' should not be recognized as a digit"); +static_assert(!VersionParser::isDigit('/'), "'/' should not be recognized as a digit"); +static_assert(!VersionParser::isDigit(' '), "' ' should not be recognized as a digit"); + +static_assert(0 == VersionParser::parseDigit('0'), "'0' should be correctly parsed"); +static_assert(1 == VersionParser::parseDigit('1'), "'1' should be correctly parsed"); +static_assert(2 == VersionParser::parseDigit('2'), "'2' should be correctly parsed"); +static_assert(3 == VersionParser::parseDigit('3'), "'3' should be correctly parsed"); +static_assert(4 == VersionParser::parseDigit('4'), "'4' should be correctly parsed"); +static_assert(5 == VersionParser::parseDigit('5'), "'5' should be correctly parsed"); +static_assert(6 == VersionParser::parseDigit('6'), "'6' should be correctly parsed"); +static_assert(7 == VersionParser::parseDigit('7'), "'7' should be correctly parsed"); +static_assert(8 == VersionParser::parseDigit('8'), "'8' should be correctly parsed"); +static_assert(9 == VersionParser::parseDigit('9'), "'9' should be correctly parsed"); + +static_assert(0 == VersionParser::numDigits("ab"), "\"ab\" doesn't have any digits"); +static_assert(0 == VersionParser::numDigits(""), "\"\" doesn't have any digits"); +static_assert(1 == VersionParser::numDigits("5"), "\"5\" has 1 digit"); +static_assert(1 == VersionParser::numDigits("5a"), "\"5\" has 1 digit"); +static_assert(10 == VersionParser::numDigits("5594839203a"), "\"5594839203a\" has 1 digit"); +static_assert(10 == VersionParser::numDigits("5594839203"), "\"5594839203\" has 1 digit"); + +static_assert(0 == VersionParser::parseNumber("0"), "\"0\" should be correctly parsed"); +static_assert(0 == VersionParser::parseNumber("0a"), "\"0a\" should be correctly parsed"); +static_assert(0 == VersionParser::parseNumber("0."), "\"0.\" should be correctly parsed"); +static_assert(3 == VersionParser::parseNumber("3"), "\"3\" should be correctly parsed"); +static_assert(12 == VersionParser::parseNumber("12"), "\"12\" should be correctly parsed"); +static_assert(123 == VersionParser::parseNumber("123"), "\"123\" should be correctly parsed"); +static_assert(123 == VersionParser::parseNumber("0123"), "\"0123\" should be correctly parsed"); +static_assert(1 == VersionParser::parseNumber("001a"), "\"001a\" should be correctly parsed"); +static_assert(1230 == VersionParser::parseNumber("1230"), "\"1230\" should be correctly parsed"); +static_assert(1230 == VersionParser::parseNumber("1230beta"), "\"1230beta\" should be correctly parsed"); +static_assert(357532 == VersionParser::parseNumber("357532"), "\"357532\" should be correctly parsed"); +static_assert(357532 == VersionParser::parseNumber("357532alpha"), "\"357532alpha\" should be correctly parsed"); +static_assert(357532 == VersionParser::parseNumber("357532.4"), "\"357532.4\" should be correctly parsed"); + +static_assert(0 == strcmp("bla", VersionParser::skipNumber("bla")), "\"bla\" has no number to skip"); +static_assert(0 == strcmp("alpha", VersionParser::skipNumber("0alpha")), "\"0alpha\" should skip the 0"); +static_assert(0 == strcmp(".3alpha", VersionParser::skipNumber("12.3alpha")), "\"12.3alpha\" should skip the 12"); + +static_assert(0 == VersionParser::extractMajor("0.8"), "\"0.8\" has major version 0"); +static_assert(0 == VersionParser::extractMajor("0.8alpha"), "\"0.8alpha\" has major version 0"); +static_assert(1 == VersionParser::extractMajor("1.0"), "\"1.0\" has major version 1"); +static_assert(1 == VersionParser::extractMajor("1.0alpha"), "\"1.0alpha\" has major version 1"); +static_assert(1 == VersionParser::extractMajor("01.0"), "\"01.0\" has major version 1"); +static_assert(12 == VersionParser::extractMajor("12.3"), "\"12.3\" has major version 12"); +static_assert(12 == VersionParser::extractMajor("12.3alpha"), "\"12.3alpha\" has major version 12"); + +static_assert(0 == VersionParser::extractMinor("0.0"), "\"0.0\" has minor version 0"); +static_assert(1 == VersionParser::extractMinor("0.01"), "\"0.01\" has minor version 1"); +static_assert(34 == VersionParser::extractMinor("12.34"), "\"12.34\" has minor version 34"); +static_assert(34 == VersionParser::extractMinor("12.34alpha"), "\"12.34alpha\" has minor version 34"); + +static_assert(0 == strlen(VersionParser::extractTag("0.0")), "\"0.0\" has no version tag"); +static_assert(0 == strlen(VersionParser::extractTag("0.01")), "\"0.01\" has no version tag"); +static_assert(0 == strlen(VersionParser::extractTag("12.34")), "\"12.34\" has no version tag"); +static_assert(0 == strcmp("alpha", VersionParser::extractTag("12.34alpha")), "\"12.34alpha\" has alpha version tag"); +static_assert(0 == strcmp("rc1", VersionParser::extractTag("12.34rc1")), "\"12.34rc1\" has rc1 version tag"); +static_assert(0 == strcmp("rc1", VersionParser::extractTag("1.0rc1")), "\"1.0rc1\" has rc1 version tag"); + +static_assert(VersionTag::ALPHA == VersionParser::parseTag("alpha"), "alpha version tag should be parseable"); +static_assert(VersionTag::BETA == VersionParser::parseTag("beta"), "beta version tag should be parseable"); +static_assert(VersionTag::RC1 == VersionParser::parseTag("rc1"), "rc1 version tag should be parseable"); +static_assert(VersionTag::FINAL == VersionParser::parseTag(""), "final version tag should be parseable"); + +static_assert(Version(1, 0, VersionTag::ALPHA) == VersionParser::parse("1.0alpha"), "1.0alpha should parse correctly"); +static_assert(Version(12, 34, VersionTag::BETA) == VersionParser::parse("12.34beta"), "12.34beta should parse correctly"); +static_assert(Version(0, 8, VersionTag::RC1) == VersionParser::parse("0.8rc1"), "0.8rc1 should parse correctly"); +static_assert(Version(1, 2, VersionTag::FINAL) == VersionParser::parse("1.2"), "1.2 should parse correctly"); +static_assert(Version(1, 2, VersionTag::FINAL) == VersionParser::parse("1.02"), "1.02 should parse correctly"); +static_assert(Version(1, 20, VersionTag::FINAL) == VersionParser::parse("1.20"), "1.20 should parse correctly"); +static_assert(Version(1, 20, VersionTag::FINAL) == VersionParser::parse("1.020"), "1.020 should parse correctly");