Continued unit testing work

This commit is contained in:
GPayne
2020-05-05 20:57:54 -06:00
parent 1fbb9e8acf
commit 02fb61d95d
12 changed files with 334 additions and 85 deletions

View File

@@ -27,6 +27,7 @@
#include <openspace/scene/profilefile.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scene/scenelicense.h>
#include <ghoul/misc/easing.h>
@@ -47,20 +48,26 @@ namespace scripting { struct LuaLibrary; }
class Profile {
public:
enum class AssetEventType {
add,
require,
request,
remove
remove,
ignore
};
const std::map<AssetEventType, std::string> AssetEventTypeString {
{AssetEventType::add, "add"},
{AssetEventType::require, "required"},
{AssetEventType::request, "requested"},
{AssetEventType::remove, "removed"},
{AssetEventType::ignore, "ignored"},
};
struct AssetEvent {
std::string name;
AssetEventType eventType;
};
virtual ~Profile() {};
/**
* Saves all current settings, starting from the profile that was loaded at startup,
* and all of the property & asset changes that were made since startup.
@@ -68,6 +75,12 @@ public:
*/
void saveCurrentSettingsToProfile(std::string filename);
/**
* Saves all current settings, similar to saveCurrentSettingsToProfile() except the
* output is a string without writing to a file.
*/
std::string saveCurrentSettingsToProfile_string();
/**
* Reads in a .profile file, converts it to scene/asset equivalent syntax, and
* writes the result to the specified output path.
@@ -99,6 +112,9 @@ private:
std::vector<AssetEvent> changed;
};
virtual bool usingProfile();
virtual std::string initialProfile();
ProfileFile collateBaseWithChanges();
std::string convertToScene_assets(ProfileFile& pf);
std::string convertToScene_modules(ProfileFile& pf);
std::string convertToScene_properties(ProfileFile& pf);
@@ -109,13 +125,16 @@ private:
std::vector<AssetEvent> modifyAssetsToReflectChanges(ProfileFile& pf);
void parseAssetFileLines(std::vector<AssetEvent>& results, ProfileFile& pf);
void handleChangedRequire(std::vector<AssetEvent>& base, std::string asset);
void handleChangedRequest(std::vector<AssetEvent>& base, std::string asset);
void handleChangedRemove(std::vector<AssetEvent>& base, std::string asset);
void handleChangedAdd(std::vector<AssetEvent>& base, unsigned int changedIdx,
std::vector<AssetEvent>& changed, std::string asset);
void handleChangedRemove(std::vector<AssetEvent>& base, unsigned int changedIdx,
std::vector<AssetEvent>& changed, std::string asset);
void addAssetsToProfileFile(std::vector<AssetEvent>& allAssets, ProfileFile& pf);
void modifyPropertiesToReflectChanges(ProfileFile& pf);
std::vector<openspace::properties::Property*> getNodesThatHaveChangedProperties(
ProfileFile& pf);
virtual std::vector<openspace::properties::Property*> getChangedProperties();
virtual std::vector<std::string> getChangedPropertiesFormatted();
virtual std::string getCurrentTimeUTC();
virtual interaction::NavigationHandler::NavigationState getCurrentCameraState();
void addCurrentTimeToProfileFile(ProfileFile& pf);
void addCurrentCameraToProfileFile(ProfileFile& pf);
};

View File

@@ -94,25 +94,47 @@ class ProfileFile {
public:
using Lines = std::vector<std::string>;
/**
* Constructs object by reading the contents of a profile file and populates vector
* containers for all sections. This only pulls individual line entries into their
* proper sections; it does not parse the tab-delimited fields of each line.
* \param filename The profile file to read
*/
ProfileFile(std::string filename);
/**
* Constructor with alternative method of populating the object by reading the lines
* from a profile file. This is mainly intended for testing purposes, but it can be
* used to provide the profile file contents from another source (the function
* readFromFile() provides its own ifstream source).
* \param reader A std::function object that accepts a string reference which will
* be populated with a single line of content. This function returns
* true if a single line was read successfully, or false if not to
* indicate that the end of the content has been reached.
*/
ProfileFile(std::function<bool(std::string&)> reader);
/**
* Reads the contents of a profile file and populates vector containers for all
* sections. This only pulls individual line entries into their proper sections;
* it does not parse the tab-delimited fields of each line.
* This will reset contents of the object.
* \param filename The profile file to read
*/
void readFromFile(std::string filename);
void readIn(std::string filename);
/**
* Alternative function for reading the lines from a profile file. This is mainly
* intended for testing purposes, but it can be used to provide the profile file
* contents from another source (the function readFromFile() provides its own
* ifstream source).
* This will reset contents of the object.
* \param reader A std::function object that accepts a string reference which will
* be populated with a single line of content. This function returns
* true if a single line was read successfully, or false if not to
* indicate that the end of the content has been reached.
*/
void readLines(std::function<bool(std::string&)> reader);
void readIn(std::function<bool(std::string&)> reader);
/**
* Returns the string contents of this object converted to scene/asset

View File

@@ -444,7 +444,6 @@ std::shared_ptr<Asset> AssetLoader::require(const std::string& identifier) {
std::shared_ptr<Asset> asset = getAsset(identifier);
std::shared_ptr<Asset> dependant = _currentAsset;
dependant->require(asset);
addToProfileTracking(asset->assetFilePath(), Profile::AssetEventType::require);
return asset;
}
@@ -453,7 +452,6 @@ std::shared_ptr<Asset> AssetLoader::request(const std::string& identifier) {
std::shared_ptr<Asset> parent = _currentAsset;
parent->request(asset);
assetRequested(parent, asset);
addToProfileTracking(asset->assetFilePath(), Profile::AssetEventType::request);
return asset;
}
@@ -480,7 +478,7 @@ ghoul::filesystem::Directory AssetLoader::currentDirectory() const {
std::shared_ptr<Asset> AssetLoader::add(const std::string& identifier) {
setCurrentAsset(_rootAsset);
addToProfileTracking(identifier, Profile::AssetEventType::add);
return request(identifier);
}

View File

@@ -59,19 +59,37 @@ namespace {
namespace openspace {
void Profile::saveCurrentSettingsToProfile(std::string filename) {
if (! global::configuration.usingProfile) {
ProfileFile pf = collateBaseWithChanges();
pf.writeToFile(filename);
}
std::string Profile::saveCurrentSettingsToProfile_string() {
ProfileFile pf = collateBaseWithChanges();
return pf.writeToString();
}
bool Profile::usingProfile() {
return global::configuration.usingProfile;
}
std::string Profile::initialProfile() {
return global::configuration.profile;
}
ProfileFile Profile::collateBaseWithChanges() {
if (! usingProfile()) {
std::string errorMessage = "Program was not started using a profile, "
"so cannot use this save-current-settings feature.";
LERROR(errorMessage);
}
std::string initProfile = global::configuration.profile;
ProfileFile pf;
pf.readFromFile(initProfile);
std::string initProfile = initialProfile();
ProfileFile pf(initProfile);
std::vector<AssetEvent> ass = modifyAssetsToReflectChanges(pf);
addAssetsToProfileFile(ass, pf);
modifyPropertiesToReflectChanges(pf);
addCurrentTimeToProfileFile(pf);
addCurrentCameraToProfileFile(pf);
return pf;
}
std::vector<Profile::AssetEvent> Profile::modifyAssetsToReflectChanges(ProfileFile& pf) {
@@ -82,35 +100,41 @@ std::vector<Profile::AssetEvent> Profile::modifyAssetsToReflectChanges(ProfileFi
assetDetails.base = a;
assetDetails.changed = global::openSpaceEngine.listOfAllAssetEvents();
for (AssetEvent event : assetDetails.changed) {
if (event.eventType == AssetEventType::require) {
handleChangedRequire(assetDetails.base, event.name);
}
else if (event.eventType == AssetEventType::request) {
handleChangedRequest(assetDetails.base, event.name);
for (unsigned int i = 0; i < assetDetails.changed.size(); i++) {
AssetEvent event = assetDetails.changed[i];
if (event.eventType == AssetEventType::add) {
handleChangedAdd(assetDetails.base, i, assetDetails.changed, event.name);
}
else if (event.eventType == AssetEventType::remove) {
handleChangedRemove(assetDetails.base, event.name);
handleChangedRemove(assetDetails.base, i, assetDetails.changed, event.name);
}
}
return assetDetails.base;
}
void Profile::handleChangedRequire(std::vector<AssetEvent>& base, std::string asset) {
void Profile::handleChangedAdd(std::vector<AssetEvent>& base, unsigned int changedIdx,
std::vector<AssetEvent>& changed, std::string asset)
{
bool addThisAsset = true;
//Check base profile to see if has already been added there
for (auto b : base) {
if (b.name == asset && b.eventType == AssetEventType::request) {
base.push_back({asset, AssetEventType::require});
if (b.name == asset ) {
if ( b.eventType == AssetEventType::require
|| b.eventType == AssetEventType::request)
{
addThisAsset = false;
break;
}
}
}
}
void Profile::handleChangedRequest(std::vector<AssetEvent>& base, std::string asset) {
bool addThisAsset = true;
std::vector<AssetEvent>::iterator f;
f = find_if(base.begin(), base.end(), [asset](AssetEvent ae)
{ return (ae.name == asset); } );
if (f != base.end()) {
addThisAsset = false;
//Check changed asset commands only prior to this one to see if already added
for (unsigned int i = 0; i < changedIdx; i++) {
if (changed[i].name == asset) {
addThisAsset = false;
break;
}
}
if (addThisAsset) {
@@ -119,10 +143,24 @@ void Profile::handleChangedRequest(std::vector<AssetEvent>& base, std::string as
}
}
void Profile::handleChangedRemove(std::vector<AssetEvent>& base, std::string asset) {
std::vector<AssetEvent>::iterator f;
f = remove_if(base.begin(), base.end(), [asset](AssetEvent ae)
{ return (ae.name == asset); } );
void Profile::handleChangedRemove(std::vector<AssetEvent>& base, unsigned int changedIdx,
std::vector<AssetEvent>& changed, std::string asset)
{
//Blank-out any base profile entries where this asset was required/requested
for (unsigned int i = 0; i < base.size(); i++) {
if (base[i].name == asset) {
base[i].name = "";
base[i].eventType = AssetEventType::ignore;
}
}
//Blank-out any changes profile entries where this asset was required/requested
for (unsigned int i = 0; i < changedIdx; i++) {
if (changed[i].name == asset) {
changed[i].name = "";
changed[i].eventType = AssetEventType::ignore;
}
}
}
void Profile::addAssetsToProfileFile(std::vector<AssetEvent>& allAssets, ProfileFile& pf)
@@ -152,7 +190,7 @@ void Profile::parseAssetFileLines(std::vector<AssetEvent>& results, ProfileFile&
if (elements[1] == AssetEventTypeString.at(AssetEventType::require)) {
a.eventType = AssetEventType::require;
}
else if (elements[1] == AssetEventTypeString.at(AssetEventType::require)) {
else if (elements[1] == AssetEventTypeString.at(AssetEventType::request)) {
a.eventType = AssetEventType::request;
}
else if (elements[1] == "") {
@@ -168,48 +206,66 @@ void Profile::parseAssetFileLines(std::vector<AssetEvent>& results, ProfileFile&
}
void Profile::modifyPropertiesToReflectChanges(ProfileFile& pf) {
std::vector<openspace::properties::Property*> changedProps
= getNodesThatHaveChangedProperties(pf);
std::string newLine;
std::vector<std::string> formatted = getChangedPropertiesFormatted();
for (auto prop : changedProps) {
newLine = "setPropertyValueSingle\t";
newLine += prop->identifier() + "\t";
newLine += prop->getStringValue() + "\n";
pf.addPropertyLine(newLine);
for (std::string line: formatted) {
pf.addPropertyLine(line);
}
}
std::vector<openspace::properties::Property*> Profile::getNodesThatHaveChangedProperties(
ProfileFile& pf)
std::vector<std::string> Profile::getChangedPropertiesFormatted() {
std::vector<openspace::properties::Property*> changedProps
= getChangedProperties();
std::vector<std::string> formattedLines;
for (auto prop : changedProps) {
std::string newLine = "setPropertyValueSingle\t";
newLine += prop->identifier() + "\t";
newLine += prop->getStringValue() + "\n";
formattedLines.push_back(newLine);
}
return formattedLines;
}
std::vector<openspace::properties::Property*> Profile::getChangedProperties()
{
ZoneScoped
std::vector<SceneGraphNode*> nodes =
global::renderEngine.scene()->allSceneGraphNodes();
std::vector<SceneGraphNode*> nodes
= global::renderEngine.scene()->allSceneGraphNodes();
std::vector<openspace::properties::Property*> changedProps;
for (auto n : nodes) {
std::vector<openspace::properties::Property*> props = n->properties();
for (auto p : props) {
if (p->hasChanged()) {
changedProps.push_back(p);
}
}
if (n != nullptr) {
std::vector<openspace::properties::Property*> props = n->properties();
for (auto p : props) {
if (p->hasChanged()) {
changedProps.push_back(p);
}
}
}
}
return changedProps;
}
std::string Profile::getCurrentTimeUTC() {
return global::timeManager.time().UTC();
}
void Profile::addCurrentTimeToProfileFile(ProfileFile& pf) {
std::string t = global::timeManager.time().UTC();
std::string t = getCurrentTimeUTC();
std::string update = "absolute\t" + t + "\n";
pf.updateTime(update);
}
interaction::NavigationHandler::NavigationState Profile::getCurrentCameraState() {
return global::navigationHandler.navigationState();
}
void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) {
std::string update = "setNavigationState\t";
interaction::NavigationHandler::NavigationState nav;
nav = global::navigationHandler.navigationState();
nav = getCurrentCameraState();
update += nav.anchor + "\t";
update += nav.aim + "\t";
update += nav.referenceFrame + "\t";
@@ -233,9 +289,9 @@ void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) {
void Profile::convertToSceneFile(const std::string inProfilePath,
const std::string outFilePath)
{
ProfileFile pf;
ZoneScoped
pf.readFromFile(inProfilePath);
ProfileFile pf(inProfilePath);
std::ofstream outFile;
try {
@@ -261,6 +317,8 @@ void Profile::convertToSceneFile(const std::string inProfilePath,
}
std::string Profile::convertToScene(ProfileFile& pf) {
ZoneScoped
std::string result;
result += convertToScene_modules(pf) + "\n";

View File

@@ -43,7 +43,15 @@ namespace {
namespace openspace {
void ProfileFile::readFromFile(std::string filename) {
ProfileFile::ProfileFile(std::string filename) {
readIn(filename);
}
ProfileFile::ProfileFile(std::function<bool(std::string&)> reader) {
readIn(reader);
}
void ProfileFile::readIn(std::string filename) {
clearAllFields();
std::ifstream inFile;
@@ -56,7 +64,7 @@ void ProfileFile::readFromFile(std::string filename) {
}
try {
readLines([&inFile] (std::string& line) {
readIn([&inFile] (std::string& line) {
if (getline(inFile, line))
return true;
else
@@ -77,7 +85,8 @@ void ProfileFile::readFromFile(std::string filename) {
}
}
void ProfileFile::readLines(std::function<bool(std::string&)> reader) {
void ProfileFile::readIn(std::function<bool(std::string&)> reader) {
clearAllFields();
std::string line;
bool insideSection = false;
_lineNum = 1;
@@ -295,7 +304,6 @@ void ProfileFile::parseModule(std::string line) {
void ProfileFile::parseAsset(std::string line) {
std::vector<std::string> fields;
if (splitByTab(line, fields) != assetFieldsExpected) {
throw ghoul::RuntimeError(errorString(std::to_string(assetFieldsExpected) +
" fields required in an Asset entry"), "profileFile");

View File

@@ -0,0 +1,21 @@
#Version
1.0
#Asset
scene/solarsystem/planets/earth/earth required
scene/solarsystem/planets/earth/satellites/satellites required
#Property
setPropertyValue {earth_satellites}.Renderable.Enabled false
#Time
relative -1d
#Camera
goToGeo "Earth" 58.5877 16.1924 20000000
#MarkNodes
Earth
Mars
Moon
Sun

View File

@@ -0,0 +1,3 @@
asset.onInitialize(function ()
passTest()
end)

View File

@@ -0,0 +1 @@
assert (true)

View File

@@ -0,0 +1,21 @@
#Version
1.0
#Asset
scene/solarsystem/planets/earth/earth required
scene/solarsystem/planets/earth/satellites/satellites required
#Property
setPropertyValue {earth_satellites}.Renderable.Enabled false
#Time
relative -1d
#Camera
goToGeo "Earth" 58.5877 16.1924 20000000
#MarkNodes
Earth
Mars
Moon
Sun

View File

@@ -102,8 +102,7 @@ std::string stringFromTestProfileFormat(testProfileFormat& tpf) {
ProfileFile makeProfileFromString(std::string s) {
std::istringstream iss(s);
ProfileFile pf;
pf.readLines([&iss](std::string& line) {
ProfileFile pf([&iss](std::string& line) {
if (getline(iss, line))
return true;
else

View File

@@ -24,27 +24,93 @@
#include "catch2/catch.hpp"
#include "test_common.h"
#include <openspace/engine/configuration.h>
#include <openspace/engine/globals.h>
#include <openspace/scene/assetloader.h>
#include <openspace/scene/asset.h>
#include "openspace/scene/profile.h"
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scene/sceneinitializer.h>
#include <openspace/scripting/scriptengine.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/exception.h>
#include <ghoul/lua/lua_helper.h>
#include <iostream>
#include <iomanip>
#include <memory>
using namespace openspace;
namespace {
}
int passTest(lua_State* state) {
bool* test = reinterpret_cast<bool*>(lua_touserdata(state, lua_upvalueindex(1)));
*test = true;
return 0;
}
} // namespace
class Profile2 : public Profile {
public:
std::string getCurrentTimeUTC() {
return "2020-02-29T01:23:45.00";
}
interaction::NavigationHandler::NavigationState getCurrentCameraState() {
interaction::NavigationHandler::NavigationState n;
n.anchor = "Earth";
n.aim = "Sun";
n.referenceFrame = "root";
n.position = {-1.0, -2.0, -3.0};
n.up = {0.0, 0.0, 1.0};
n.pitch = 0.0;
n.yaw = 0.0;
return n;
}
void addPropertiesMarkedAsChanged(std::string formattedLine) {
_scenegraphProps.push_back(formattedLine);
}
std::vector<std::string> getChangedPropertiesFormatted() {
std::vector<std::string> formattedLines;
for (std::string s : _scenegraphProps) {
formattedLines.push_back(s);
}
return formattedLines;
}
bool usingProfile() {
return true;
}
std::string initialProfile() {
return _initProfile;
}
void setInitialProfile(std::string file) {
_initProfile = file;
}
private:
std::vector<std::string> _scenegraphProps;
std::string _initProfile;
};
static void addLineHeaderForFailureMessage(std::string& s, size_t lineNumber) {
s = "@line " + std::to_string(lineNumber) + ": '" + s + "'";
}
TEST_CASE("profile: Convert profileFile to asset", "[profile]") {
testProfileFormat test = buildTestProfile1();
std::string testFull_string = stringFromTestProfileFormat(test);
ProfileFile pf = makeProfileFromString(testFull_string);
std::istringstream iss(testFull_string);
ProfileFile pf("default.profile");
pf.readIn([&iss](std::string& line) {
if (getline(iss, line))
return true;
else
return false;
}
);
Profile p;
REQUIRE_NOTHROW(
@@ -53,7 +119,15 @@ TEST_CASE("profile: Convert profileFile to asset", "[profile]") {
}
TEST_CASE("profile: Verify conversion to scene", "[profile]") {
ProfileFile pf = makeProfileFromString(newHorizonsProfileInput);
std::istringstream iss(newHorizonsProfileInput);
ProfileFile pf("default.profile");
pf.readIn([&iss](std::string& line) {
if (getline(iss, line))
return true;
else
return false;
}
);
Profile p;
std::string result;
@@ -77,3 +151,30 @@ TEST_CASE("profile: Verify conversion to scene", "[profile]") {
REQUIRE(sr_standard.getNextLine(comparing) == false);
}
TEST_CASE("profile: Detect new required asset", "[profile]") {
openspace::Scene scene(std::make_unique<openspace::SingleThreadedSceneInitializer>());
ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState();
openspace::SynchronizationWatcher syncWatcher;
AssetLoader assetLoader(
state,
&syncWatcher,
FileSys.absolutePath("${TESTDIR}/profile/")
);
bool passed;
lua_pushlightuserdata(*state, &passed);
lua_pushcclosure(*state, &passTest, 1);
lua_setglobal(*state, "passTest");
std::shared_ptr<openspace::Asset> asset = assetLoader.add("initialization");
asset->initialize();
assetLoader.add("test1");
Profile2 p;
p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile"));
p.addPropertiesMarkedAsChanged("initialized 1st\t123");
p.addPropertiesMarkedAsChanged("initialized 2nd\t3.14159");
p.addPropertiesMarkedAsChanged("initialized 3rd\ttested.");
std::string output = p.saveCurrentSettingsToProfile_string();
std::cout << output << std::endl;
}

View File

@@ -41,8 +41,7 @@ TEST_CASE("profileFile: Simple read and verify", "[profileFile]") {
std::string testFull_string = stringFromTestProfileFormat(test);
std::istringstream iss(testFull_string);
ProfileFile pf;
pf.readLines([&iss](std::string& line) {
ProfileFile pf([&iss](std::string& line) {
if (getline(iss, line))
return true;
else
@@ -85,9 +84,9 @@ TEST_CASE("profileFile: Unrecognized header", "[profileFile]") {
std::string testFull_string = stringFromTestProfileFormat(test);
std::istringstream iss(testFull_string);
ProfileFile pf;
ProfileFile pf("default.profile");
REQUIRE_THROWS_WITH(
pf.readLines([&iss](std::string& line) {
pf.readIn([&iss](std::string& line) {
if (getline(iss, line))
return true;
else
@@ -106,9 +105,9 @@ TEST_CASE("profileFile: Bad number of fields", "[profileFile]") {
testFull_string = stringFromTestProfileFormat(test);
{
std::istringstream iss(testFull_string);
ProfileFile pf;
ProfileFile pf("default.profile");
REQUIRE_THROWS_WITH(
pf.readLines([&iss](std::string& line) {
pf.readIn([&iss](std::string& line) {
if (getline(iss, line))
return true;
else
@@ -124,9 +123,9 @@ TEST_CASE("profileFile: Bad number of fields", "[profileFile]") {
testFull_string = stringFromTestProfileFormat(test);
{
std::istringstream iss(testFull_string);
ProfileFile pf;
ProfileFile pf("default.profile");
REQUIRE_THROWS_WITH(
pf.readLines([&iss](std::string& line) {
pf.readIn([&iss](std::string& line) {
if (getline(iss, line))
return true;
else
@@ -145,9 +144,9 @@ TEST_CASE("profileFile: Too many lines in time entry", "[profileFile]") {
testFull_string = stringFromTestProfileFormat(test);
{
std::istringstream iss(testFull_string);
ProfileFile pf;
ProfileFile pf("default.profile");
REQUIRE_THROWS_WITH(
pf.readLines([&iss](std::string& line) {
pf.readIn([&iss](std::string& line) {
if (getline(iss, line))
return true;
else
@@ -167,9 +166,9 @@ TEST_CASE("profileFile: Required field missing", "[profileFile]") {
testFull_string = stringFromTestProfileFormat(test);
{
std::istringstream iss(testFull_string);
ProfileFile pf;
ProfileFile pf("default.profile");
REQUIRE_THROWS_WITH(
pf.readLines([&iss](std::string& line) {
pf.readIn([&iss](std::string& line) {
if (getline(iss, line))
return true;
else
@@ -185,9 +184,9 @@ TEST_CASE("profileFile: Required field missing", "[profileFile]") {
testFull_string = stringFromTestProfileFormat(test);
{
std::istringstream iss(testFull_string);
ProfileFile pf;
ProfileFile pf("default.profile");
REQUIRE_THROWS_WITH(
pf.readLines([&iss](std::string& line) {
pf.readIn([&iss](std::string& line) {
if (getline(iss, line))
return true;
else
@@ -203,8 +202,7 @@ TEST_CASE("profileFile: Write test", "[profileFile]") {
testProfileFormat test = buildTestProfile1();
std::string testFull_string = stringFromTestProfileFormat(test);
std::istringstream iss(testFull_string);
ProfileFile pf;
pf.readLines([&iss](std::string& line) {
ProfileFile pf([&iss](std::string& line) {
if (getline(iss, line))
return true;
else