Skip to content

Commit

Permalink
feat: (##1076) enable backward compatibility (#1740)
Browse files Browse the repository at this point in the history
  • Loading branch information
rprospero committed Apr 9, 2024
1 parent 8cfdae1 commit ee153a5
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
add_library(
main
comms.cpp
compatibility.cpp
cli.cpp
dissolve.cpp
io.cpp
Expand All @@ -14,6 +15,7 @@ add_library(
simulation.cpp
version.cpp
cli.h
compatibility.h
dissolve.h
keywords.h
version.h
Expand Down
47 changes: 47 additions & 0 deletions src/main/compatibility.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2023 Team Dissolve and contributors

#include "main/compatibility.h"
#include <functional>
#include <iostream>

namespace dissolve
{

// Upgrade from version zero, which never supported TOML in the first
// place. This exists purely to allow testing the backward
// compatibility code before there is any pass worth checking.
SerialisedValue unrealUpgrade(SerialisedValue contents)
{
if (contents["pairPotentials"].contains("coulombTruncation"))
contents["pairPotentials"]["coulombTruncation"] =
toml::find<std::string>(contents["pairPotentials"], "coulombTruncation") + "ed";

return contents;
}

// Upgrade a file to the current version.
SerialisedValue backwardsUpgrade(SerialisedValue contents)
{
using Version::DissolveVersion;

// A map of version numbers and the corresponding function to
// upgrade the file.
std::map<std::string, std::function<SerialisedValue(SerialisedValue)>> breakingChanges = {{"1.2.0", unrealUpgrade}};

DissolveVersion current(toml::find<std::string>(contents, "version"));

for (auto &[key, value] : breakingChanges)
{
DissolveVersion next(key);
if (current < next)
{
contents = value(contents);
current = next;
}
}

return contents;
}

} // namespace dissolve
14 changes: 14 additions & 0 deletions src/main/compatibility.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2023 Team Dissolve and contributors

#pragma once

#include "base/serialiser.h"
#include "main/version.h"

namespace dissolve
{

SerialisedValue backwardsUpgrade(SerialisedValue contents);

}
14 changes: 13 additions & 1 deletion src/main/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@
// Copyright (c) 2023 Team Dissolve and contributors

#include "base/lineParser.h"
#include "base/messenger.h"
#include "base/serialiser.h"
#include "base/sysFunc.h"
#include "classes/atomType.h"
#include "classes/species.h"
#include "data/isotopes.h"
#include "main/compatibility.h"
#include "main/dissolve.h"
#include "main/keywords.h"
#include "main/version.h"
#include <cstring>
#include <functional>
#include <map>

// Load input file through supplied parser
bool Dissolve::loadInput(LineParser &parser)
Expand Down Expand Up @@ -144,6 +149,8 @@ SerialisedValue Dissolve::serialise() const
{
SerialisedValue root;

root["version"] = Version::semantic();

if (!coreData_.masterBonds().empty() || !coreData_.masterAngles().empty() || !coreData_.masterTorsions().empty() ||
!coreData_.masterImpropers().empty())
root["master"] = coreData_.serialiseMaster();
Expand Down Expand Up @@ -179,8 +186,13 @@ void Dissolve::deserialisePairPotentials(const SerialisedValue &node)
}

// Read values from a serialisable value
void Dissolve::deserialise(const SerialisedValue &node)
void Dissolve::deserialise(const SerialisedValue &originalNode)
{
// Default to current version if no version info is given.
auto hasVersion = originalNode.contains("version");
if (!hasVersion)
Messenger::warn("File does not contain version information. Assuming the current version: {}", Version::semantic());
const SerialisedValue node = hasVersion ? dissolve::backwardsUpgrade(originalNode) : originalNode;

Serialisable::optionalOn(node, "pairPotentials", [this](const auto node) { deserialisePairPotentials(node); });
Serialisable::optionalOn(node, "master", [this](const auto node) { coreData_.deserialiseMaster(node); });
Expand Down
30 changes: 30 additions & 0 deletions src/main/version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "main/version.h"
#include <fmt/format.h>
#include <iostream>

#define DISSOLVEVERSION "1.4.0"
#define DISSOLVESHORTHASH ""
Expand Down Expand Up @@ -50,4 +51,33 @@ std::string_view appType()
#endif
}

DissolveVersion::DissolveVersion(std::string_view version)
{
auto dot = version.find(".");
major_ = std::stoi(std::string(version.substr(0, dot)));
auto rest = version.substr(dot + 1);
dot = rest.find(".");
minor_ = std::stoi(std::string(rest.substr(0, dot)));
patch_ = std::stoi(std::string(rest.substr(dot + 1)));
}

bool DissolveVersion::operator<(const DissolveVersion &other) const
{
if (major_ != other.major_)
return major_ < other.major_;
if (minor_ != other.minor_)
return minor_ < other.minor_;
return patch_ < other.patch_;
}

bool DissolveVersion::operator==(const DissolveVersion &other) const
{
return major_ == other.major_ && minor_ == other.minor_ && patch_ == other.patch_;
}

std::ostream &operator<<(std::ostream &os, const DissolveVersion &version)
{
os << fmt::format("{}.{}.{}", version.major_, version.minor_, version.patch_);
return os;
}
}; // namespace Version
17 changes: 17 additions & 0 deletions src/main/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,21 @@ std::string_view info();
std::string_view repoUrl();
// Return app type
std::string_view appType();

// This class handles the version numbers of the app in a structured
// manner.
class DissolveVersion
{
private:
int major_;
int minor_;
int patch_;

public:
DissolveVersion(std::string_view version);
bool operator<(const DissolveVersion &other) const;
bool operator==(const DissolveVersion &other) const;
friend std::ostream &operator<<(std::ostream &os, const DissolveVersion &version);
};

}; // namespace Version
1 change: 1 addition & 0 deletions tests/io/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dissolve_add_test(SRC cif.cpp)
dissolve_add_test(SRC intraParameterParse.cpp)
dissolve_add_test(SRC version.cpp)
57 changes: 57 additions & 0 deletions tests/io/version.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2023 Team Dissolve and contributors

#include "main/version.h"
#include "base/serialiser.h"
#include "main/dissolve.h"
#include <gtest/gtest.h>

namespace UnitTest
{

TEST(VersionTest, VersionClass)
{
using Version::DissolveVersion;
DissolveVersion first{"1.10.3"}, second{"2.1.12"}, minor{"2.2.1"}, patch{"2.2.2"}, third{"3.0.0"};

// Main sequence
EXPECT_LT(first, second);
EXPECT_LT(second, minor);
EXPECT_LT(minor, patch);
EXPECT_LT(patch, third);

// Full combinatorial
EXPECT_LT(first, minor);
EXPECT_LT(first, patch);
EXPECT_LT(first, third);
EXPECT_LT(second, minor);
EXPECT_LT(second, patch);
EXPECT_LT(second, third);
EXPECT_LT(minor, third);
}

TEST(VersionTest, VersionInfo)
{
CoreData coreData;
Dissolve dissolve(coreData);
dissolve.loadInput("dissolve/input/rdfMethod.txt");
auto serialised = dissolve.serialise();

Version::DissolveVersion fileVersion(serialised["version"].as_string().str), actual(Version::semantic());

EXPECT_EQ(fileVersion, actual);
}

TEST(VersionTest, VersionUpgrade)
{
CoreData coreData;
Dissolve dissolve(coreData);

SerialisedValue old;
old["version"] = "0.0.0";
old["pairPotentials"] = {{"coulombTruncation", "Shift"}};

dissolve.deserialise(old);
}

} // namespace UnitTest

0 comments on commit ee153a5

Please sign in to comment.