using structs and refactoring

This commit is contained in:
maliakal_d committed 2026-10-21 13:07:38 +02:00
1 parent e7a9e94374
commit 0fadbb8a3e
3 files changed
+180 -72

No files matched your search

+30 -9
View File
@@ -2,36 +2,57 @@
// Copyright (C) 2021 Contributors to the SLS Detector Package
#pragma once
#include <iosfwd>
#include <stdint.h>
#include <string>
namespace sls {
struct SemanticVersion {
int major{0};
int minor{0};
int patch{0};
std::string prerelease{};
/**
* If empty, return {}
* If 0.0.0, only prerelease is returned (eg. developer, 0.0.0, other non
* semantic versioning) */
std::string toString() const;
bool operator==(const SemanticVersion &other) const;
bool operator<=(const SemanticVersion &other) const;
};
class Version {
private:
std::string version_;
/** Note: "0.0.0" is considered not semantic versioning here */
bool hasSemanticVersioning_{false};
SemanticVersion version_{};
std::string date_;
inline static const std::string defaultVersion_[] = {"developer", "0.0.0"};
SemanticVersion parseSemanticVersion(const std::string &version);
public:
explicit Version(const std::string &s);
static bool parseSemanticVersion(const std::string &version, int &major,
int &minor, int &patch,
std::string &extra);
std::string toString() const;
bool hasSemanticVersioning() const;
std::string getVersion() const;
std::string getDate() const;
std::string concise() const;
int getMajorVersion() const;
// expects semantic versioning
// throws if not semantic versioning
SemanticVersion getSemanticVersion() const;
int getMajorVersion() const;
int getMinorVersion() const;
int getPatchVersion() const;
std::string getPrereleaseVersion() const;
bool isBackwardCompatible(const Version &other) const;
bool operator!=(const Version &other) const;
bool operator==(const Version &other) const;
bool operator<=(const Version &other) const;
};
std::ostream &operator<<(std::ostream &out, const SemanticVersion &v);
std::ostream &operator<<(std::ostream &out, const Version &v);
} // namespace sls
+111 -60
View File
@@ -9,109 +9,160 @@
namespace sls {
bool Version::parseSemanticVersion(const std::string &version, int &major,
int &minor, int &patch, std::string &extra) {
char extraBuffer[256] = {'\0'};
// Parse major.minor.patch and capture any optional trailing suffix.
const int scanned = sscanf(version.c_str(), "%d.%d.%d%255s", &major, &minor,
&patch, extraBuffer);
std::string SemanticVersion::toString() const {
std::ostringstream oss;
oss << major << "." << minor << "." << patch;
if (!prerelease.empty()) {
oss << prerelease;
}
return oss.str();
}
if (scanned == 3) {
extra.clear();
return true;
bool SemanticVersion::operator==(const SemanticVersion &other) const {
return major == other.major && minor == other.minor &&
patch == other.patch && prerelease == other.prerelease;
}
bool SemanticVersion::operator<=(const SemanticVersion &other) const {
if (major != other.major)
return major < other.major;
if (minor != other.minor)
return minor < other.minor;
if (patch != other.patch)
return patch < other.patch;
return prerelease <= other.prerelease;
}
SemanticVersion Version::parseSemanticVersion(const std::string &version) {
SemanticVersion ver;
// assuming only released versions have semantic versioning
if (version == "developer" || version == "0.0.0") {
return ver;
}
if (scanned == 4) {
extra = extraBuffer;
return true;
char prereleaseBuffer[256] = {'\0'};
// Parse major.minor.patch and capture any optional trailing suffix.
const int scanned = sscanf(version.c_str(), "%d.%d.%d%255s", &ver.major,
&ver.minor, &ver.patch, prereleaseBuffer);
if (scanned == 3 || scanned == 4) {
hasSemanticVersioning_ = true;
if (scanned == 4)
ver.prerelease = prereleaseBuffer;
else
ver.prerelease.clear();
}
return false;
return ver;
}
Version::Version(const std::string &s) {
auto list = split(s, ' ');
// only date from previous releases
if (list.size() == 1) {
date_ = list[0];
}
// semantic versioning + date
else {
version_ = list[0];
auto version = list[0];
date_ = list[1];
version_ = parseSemanticVersion(version);
}
}
bool Version::hasSemanticVersioning() const {
return (version_ != defaultVersion_[0]) && (version_ != defaultVersion_[1]);
std::string Version::toString() const {
std::ostringstream oss;
oss << version_ << " " << getDate();
return oss.str();
}
std::string Version::getVersion() const { return version_; }
bool Version::hasSemanticVersioning() const { return hasSemanticVersioning_; }
std::string Version::getVersion() const { return version_.toString(); }
std::string Version::getDate() const { return date_; }
std::string Version::concise() const {
if (hasSemanticVersioning())
return version_;
if (hasSemanticVersioning_)
return version_.toString();
return date_;
}
int Version::getMajorVersion() const {
int major = 0, minor = 0, patch = 0;
if (sscanf(version_.c_str(), "%d.%d.%d", &major, &minor, &patch) == 3) {
return major;
SemanticVersion Version::getSemanticVersion() const {
if (!hasSemanticVersioning_) {
throw sls::RuntimeError("No semantic versioning available for " +
toString());
}
throw sls::RuntimeError("Could not get major version from " + version_);
return version_;
}
int Version::getMajorVersion() const {
if (!hasSemanticVersioning_) {
throw sls::RuntimeError("Could not get major version from " +
toString());
}
return version_.major;
}
int Version::getMinorVersion() const {
if (!hasSemanticVersioning_) {
throw sls::RuntimeError("Could not get minor version from " +
toString());
}
return version_.minor;
}
int Version::getPatchVersion() const {
if (!hasSemanticVersioning_) {
throw sls::RuntimeError("Could not get patch version from " +
toString());
}
return version_.patch;
}
std::string Version::getPrereleaseVersion() const {
if (!hasSemanticVersioning_) {
throw sls::RuntimeError("Could not get prerelease version from " +
toString());
}
return version_.prerelease;
}
bool Version::isBackwardCompatible(const Version &other) const {
if (!hasSemanticVersioning_ || !other.hasSemanticVersioning()) {
throw sls::RuntimeError("Cannot check backward compatibility without "
"semantic versioning for " +
toString() + " and " + other.toString());
}
return getMajorVersion() == other.getMajorVersion();
}
bool Version::operator==(const Version &other) const {
if (hasSemanticVersioning() && other.hasSemanticVersioning()) {
return version_ == other.getSemanticVersion();
}
return date_ == other.getDate();
}
bool Version::operator!=(const Version &other) const {
return !(*this == other);
}
bool Version::operator==(const Version &other) const {
// both have semantic versioning
if (hasSemanticVersioning() && other.hasSemanticVersioning()) {
return version_ == other.getVersion();
}
// compare dates
return date_ == other.getDate();
}
bool Version::operator<=(const Version &other) const {
// both have semantic versioning
if (hasSemanticVersioning() && other.hasSemanticVersioning()) {
int major = 0, minor = 0, patch = 0;
int otherMajor = 0, otherMinor = 0, otherPatch = 0;
std::string extra;
std::string otherExtra;
if (Version::parseSemanticVersion(version_, major, minor, patch,
extra) &&
Version::parseSemanticVersion(other.getVersion(), otherMajor,
otherMinor, otherPatch, otherExtra)) {
if (major != otherMajor)
return major < otherMajor;
if (minor != otherMinor)
return minor < otherMinor;
if (patch != otherPatch)
return patch < otherPatch;
return extra <= otherExtra;
}
LOG(logWARNING) << "Could not compare semantic versions: " << version_
<< " and " << other.getVersion()
<< ". Comparing dates instead.";
return version_ <= other.getSemanticVersion();
}
// compare dates
return date_ <= other.getDate();
}
std::ostream &operator<<(std::ostream &out, const SemanticVersion &v) {
return out << v.toString();
}
std::ostream &operator<<(std::ostream &out, const Version &v) {
std::ostringstream oss;
oss << v.getVersion() << " " << v.getDate();
return out << oss.str();
return out << v.toString();
}
} // namespace sls
+39 -3
View File
@@ -9,7 +9,9 @@ TEST_CASE("check if version is semantic", "[version]") {
auto [version_string, has_semantic_version] =
GENERATE(std::make_tuple("developer 0x250512", false),
std::make_tuple("0.0.0 0x250512", false));
std::make_tuple("0.0.0 0x250512", false),
std::make_tuple("10.1.1 0x250512", true),
std::make_tuple("0x250512", false));
Version version(version_string);
@@ -24,7 +26,7 @@ TEST_CASE("semantic version ordering compares numerically", "[version]") {
CHECK_FALSE(v10 <= v9);
}
TEST_CASE("semantic version compares extra suffix lexicographically",
TEST_CASE("semantic version compares prerelease lexicographically",
"[version]") {
Version rc("10.1.1.rc 0x250512");
Version zz("10.1.1.zz 0x250512");
@@ -33,6 +35,15 @@ TEST_CASE("semantic version compares extra suffix lexicographically",
CHECK_FALSE(zz <= rc);
}
TEST_CASE("semantic version compares prerelease with no prerelease",
"[version]") {
Version prerelease("10.1.1.rc 0x250512");
Version release("10.1.1 0x250512");
CHECK_FALSE(prerelease <= release);
CHECK(release <= prerelease);
}
TEST_CASE(
"semantic comparison falls back to date on malformed semantic version",
"[version]") {
@@ -43,7 +54,7 @@ TEST_CASE(
CHECK_FALSE(valid <= malformed);
}
TEST_CASE("semantic version compares extra suffix and without", "[version]") {
TEST_CASE("semantic version compares prerelease and without", "[version]") {
Version v1011rc("10.1.1.rc 0x250512");
Version v1010("10.1.0 0x250512");
@@ -51,4 +62,29 @@ TEST_CASE("semantic version compares extra suffix and without", "[version]") {
CHECK(v1010 <= v1011rc);
}
TEST_CASE("semantic version", "[version]") {
auto version = Version("10.1.1.rc 0x250512");
CHECK(version.hasSemanticVersioning());
CHECK(version.getDate() == "0x250512");
CHECK(version.toString() == "10.1.1.rc 0x250512");
auto semver = version.getSemanticVersion();
CHECK(semver.toString() == "10.1.1.rc");
CHECK(semver.major == 10);
CHECK(semver.minor == 1);
CHECK(semver.patch == 1);
CHECK(semver.prerelease == "rc");
version = Version("0.0.0 0x250512");
CHECK_FALSE(version.hasSemanticVersioning());
CHECK(version.getDate() == "0x250512");
CHECK(version.toString() == "0.0.0 0x250512");
REQUIRE_THROWS(version.getSemanticVersion());
version = Version("0x250512");
CHECK_FALSE(version.hasSemanticVersioning());
CHECK(version.getDate() == "0x250512");
CHECK(version.toString() == "0.0.0 0x250512");
REQUIRE_THROWS(version.getSemanticVersion());
}
} // namespace sls