
commit
e50ed656d7
7 changed files with 694 additions and 0 deletions
@ -0,0 +1,29 @@ |
|||
LDLIBS=-lstdc++ -lpEpAdapter |
|||
LDFLAGS=-L../../src/ |
|||
CXXFLAGS=-std=c++11 -g |
|||
CXXFLAGS+=-I./src |
|||
TEST_EXTRA_OBJS=../framework/utils.o |
|||
|
|||
# Src
|
|||
SRC=$(wildcard src/*.cc) |
|||
OBJ=$(subst .cc,.o,$(SRC)) |
|||
|
|||
# Tests
|
|||
TEST_SRC=$(wildcard test/*.cc) |
|||
TEST_OBJ=$(subst .cc,,$(TEST_SRC)) |
|||
|
|||
|
|||
.PHONY: all clean rmtestdata |
|||
.DEFAULT_GOAL := all |
|||
|
|||
all: $(TEST_OBJ) |
|||
|
|||
$(TEST_OBJ): $(OBJ) $(TEST_EXTRA_OBJS) |
|||
|
|||
|
|||
clean: |
|||
rm -f $(OBJ) |
|||
rm -f $(TEST_OBJ) |
|||
rm -rf src/*.dSYM |
|||
rm -rf test/*.dSYM |
|||
|
@ -0,0 +1,16 @@ |
|||
#include "PityModel.hh" |
|||
#include "iostream" |
|||
|
|||
using namespace std; |
|||
namespace pEp { |
|||
namespace PityTest11 { |
|||
bool PityModel::log_enabled = true; |
|||
|
|||
PityModel::PityModel(const string& name) : name(name) {} |
|||
|
|||
const std::string& PityModel::getName() const |
|||
{ |
|||
return name; |
|||
} |
|||
} // namespace Test
|
|||
} // namespace pEp
|
@ -0,0 +1,26 @@ |
|||
// This file is under GNU General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef PITYTEST_PITYMODEL_HH |
|||
#define PITYTEST_PITYMODEL_HH |
|||
|
|||
#include "../../../src/pEpLog.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PityTest11 { |
|||
class PityModel { |
|||
public: |
|||
PityModel() = delete; |
|||
PityModel(const std::string& name); |
|||
virtual const std::string& getName() const; |
|||
|
|||
private: |
|||
const std::string name; |
|||
static bool log_enabled; |
|||
Adapter::pEpLog::pEpLogger logger{ "PityModel", log_enabled }; |
|||
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
|||
}; |
|||
}; // namespace Test
|
|||
}; // namespace pEp
|
|||
|
|||
#endif // PITYTEST_PITYMODEL_HH
|
@ -0,0 +1,113 @@ |
|||
// This file is under GNU General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef PITYTEST_PITYUNIT_HH |
|||
#define PITYTEST_PITYUNIT_HH |
|||
|
|||
#include <string> |
|||
#include <functional> |
|||
#include <map> |
|||
#include "../../../src/pEpLog.hh" |
|||
|
|||
// Yes, the mem mgmt is purely static on purpose (so far)
|
|||
|
|||
namespace pEp { |
|||
namespace PityTest11 { |
|||
template<class T = void> |
|||
class PityUnit { |
|||
public: |
|||
using NodeFunc = std::function<void(const PityUnit&)>; |
|||
|
|||
enum class ExecutionMode |
|||
{ |
|||
FUNCTION, |
|||
PROCESS_SEQUENTIAL, |
|||
PROCESS_PARALLEL, |
|||
THREAD_SEQUENTIAL, // unimplemented
|
|||
THREAD_PARALLEL, // unimplemented
|
|||
INHERIT |
|||
}; |
|||
|
|||
// Constructors are private
|
|||
PityUnit() = delete; |
|||
explicit PityUnit( |
|||
PityUnit* parent, |
|||
const std::string& name, |
|||
const NodeFunc test_func = nullptr, |
|||
T* model = nullptr, |
|||
ExecutionMode exec_mode = ExecutionMode::FUNCTION); |
|||
|
|||
// Read-Only
|
|||
std::string getNodeName() const; |
|||
std::string getNodePath() const; |
|||
std::string getNodePathShort() const; |
|||
T* getModel() const; |
|||
std::string rootNodeDir() const; |
|||
std::string processDir() const; // own process dir
|
|||
|
|||
// Read-Write
|
|||
void setExecutionMode(ExecutionMode mode); |
|||
static void setGlobalRootDir(const std::string& dir); |
|||
static std::string getGlobalRootDir(); |
|||
|
|||
|
|||
// Main funcs
|
|||
void run() const; |
|||
std::string to_string(bool recursive = true, int indent = 0) const; |
|||
static std::string to_string(const ExecutionMode& emode); |
|||
|
|||
// logging service
|
|||
void log(const std::string& msg) const; |
|||
|
|||
// internal logging
|
|||
static bool debug_log_enabled; |
|||
Adapter::pEpLog::pEpLogger logger_debug{ "PityUnit", debug_log_enabled }; |
|||
|
|||
private: |
|||
// CONSTRUCTORS
|
|||
|
|||
// METHODS
|
|||
// Execution
|
|||
void _runRootNode() const; |
|||
void _run() const; |
|||
void _runSelf() const; |
|||
void _runChildren() const; |
|||
void _executeInFork(std::function<void(void)> func, bool wait_child) const; |
|||
void _waitChildProcesses() const; |
|||
|
|||
// Modify
|
|||
void _addChildNode(PityUnit& node); |
|||
|
|||
// Query
|
|||
bool _isProcessNode() const; |
|||
bool _isRootNode() const; |
|||
const PityUnit& _rootNode() const; |
|||
const PityUnit& _parentingProcessNode() const; |
|||
|
|||
// Util
|
|||
std::string _normalizeName(std::string name) const; |
|||
|
|||
// TODO
|
|||
void _data_dir_delete(); |
|||
void _data_dir_create(); |
|||
void _data_dir_recreate(); |
|||
|
|||
// Fields
|
|||
const std::string _name; |
|||
const PityUnit* _parent; //nullptr if RootUnit
|
|||
T* _model; //nullptr if inherited
|
|||
const NodeFunc _test_func; |
|||
ExecutionMode _exec_mode; |
|||
static std::string _global_root_dir; |
|||
|
|||
std::map<const std::string, PityUnit&> _children; // map to guarantee uniqueness of sibling-names
|
|||
|
|||
// internal logging
|
|||
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug; |
|||
}; |
|||
}; // namespace Test
|
|||
}; // namespace pEp
|
|||
|
|||
#include "PityUnit.hxx" |
|||
|
|||
#endif // PITYTEST_PITYUNIT_HH
|
@ -0,0 +1,390 @@ |
|||
// This file is under GNU General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef PITYTEST_PITYUNIT_HXX |
|||
#define PITYTEST_PITYUNIT_HXX |
|||
|
|||
#include "../../../src/std_utils.hh" |
|||
#include "../../framework/utils.hh" |
|||
#include <iostream> |
|||
#include <unistd.h> |
|||
#include <cstdlib> |
|||
#include <sys/stat.h> |
|||
#include <functional> |
|||
#include <algorithm> |
|||
#include <sstream> |
|||
|
|||
|
|||
using namespace pEp::Adapter::pEpLog; |
|||
|
|||
namespace pEp { |
|||
namespace PityTest11 { |
|||
template<class T> |
|||
std::string PityUnit<T>::_global_root_dir = "./pitytest"; |
|||
template<class T> |
|||
bool PityUnit<T>::debug_log_enabled = false; |
|||
|
|||
// PUBLIC CONCSTRUCTORS / FACTORY -----------------------------------------------------------
|
|||
template<class T> |
|||
PityUnit<T>::PityUnit( |
|||
PityUnit* const parent, |
|||
const std::string& name, |
|||
const NodeFunc test_func, |
|||
T* model, |
|||
ExecutionMode exec_mode) : |
|||
_parent(parent), |
|||
_model(model), _name(_normalizeName(name)), _test_func(test_func), _exec_mode(exec_mode) |
|||
{ |
|||
logger_debug.set_instancename(getNodePath()); |
|||
if (!_isRootNode()) { |
|||
parent->_addChildNode(*this); |
|||
} |
|||
} |
|||
|
|||
template<class T> |
|||
std::string PityUnit<T>::getNodeName() const |
|||
{ |
|||
return _name; |
|||
} |
|||
|
|||
template<class T> |
|||
std::string PityUnit<T>::getNodePath() const |
|||
{ |
|||
std::string ret; |
|||
|
|||
if (!_isRootNode()) { |
|||
ret = _parent->getNodePath() + "/" + getNodeName(); |
|||
} else { |
|||
ret = getNodeName(); |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
// For:
|
|||
// RootNode - "<name>"
|
|||
// ProcessNode - ".../<proc>"
|
|||
// When Process as dir. parent - ".../<proc>/name"
|
|||
// When no process as dir. parent - ".../<proc>/.../name"
|
|||
template<class T> |
|||
std::string PityUnit<T>::getNodePathShort() const |
|||
{ |
|||
std::string ret; |
|||
if (_isRootNode()) { |
|||
ret = getNodeName(); |
|||
} else { |
|||
if (_isProcessNode()) { |
|||
ret += ".../" + getNodeName(); |
|||
} else { |
|||
if (&(_parentingProcessNode()) == (_parent)) { |
|||
ret = _parentingProcessNode().getNodePathShort() + "/" + getNodeName(); |
|||
} else { |
|||
ret = _parentingProcessNode().getNodePathShort() + "/.../" + getNodeName(); |
|||
} |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
// Inherited (if null see parent recursively)
|
|||
template<class T> |
|||
T* PityUnit<T>::getModel() const |
|||
{ |
|||
pEpLogClass("called"); |
|||
T* ret = nullptr; |
|||
|
|||
if (_model != nullptr) { |
|||
ret = _model; |
|||
} else { |
|||
if (!_isRootNode()) { |
|||
ret = _parent->getModel(); |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
// Every RootNode has its own dir
|
|||
template<class T> |
|||
std::string PityUnit<T>::rootNodeDir() const |
|||
{ |
|||
return getGlobalRootDir() + _rootNode().getNodeName() + "/"; |
|||
} |
|||
|
|||
// Every process has its own dir inside its rootNodeDir
|
|||
// All other nodes inherit processDir from their Root/ProcessNode
|
|||
template<class T> |
|||
std::string PityUnit<T>::processDir() const |
|||
{ |
|||
if (_isRootNode()) { |
|||
return rootNodeDir(); |
|||
} else { |
|||
if (_isProcessNode()) { |
|||
return rootNodeDir() + getNodeName() + "/"; |
|||
} else{ |
|||
return _parent->processDir(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
template<class T> |
|||
void PityUnit<T>::setExecutionMode(ExecutionMode mode) |
|||
{ |
|||
_exec_mode = mode; |
|||
} |
|||
|
|||
// static
|
|||
template<> |
|||
void PityUnit<void>::setGlobalRootDir(const std::string& dir) |
|||
{ |
|||
PityUnit::_global_root_dir = dir; |
|||
} |
|||
|
|||
// static
|
|||
template<class T> |
|||
std::string PityUnit<T>::getGlobalRootDir() |
|||
{ |
|||
return PityUnit::_global_root_dir; |
|||
} |
|||
|
|||
template<class T> |
|||
void PityUnit<T>::run() const |
|||
{ |
|||
pEpLogClass("called"); |
|||
// caller is never nullptr if called by another PityUnit
|
|||
if (_isRootNode()) { |
|||
logH1("Starting PityUnit from node: " + getNodePathShort()); |
|||
log(to_string()); |
|||
} |
|||
|
|||
// Execute in fork and wait here until process ends
|
|||
if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL) { // fork
|
|||
logH2("[ " + to_string(_exec_mode) + " / " + getNodePathShort() + " ]"); |
|||
_executeInFork(std::bind(&PityUnit::_run, this), true); |
|||
// Execute in fork and go on, wait for process execution in the end
|
|||
} else if (_exec_mode == ExecutionMode::PROCESS_PARALLEL) { |
|||
logH2("[ " + to_string(_exec_mode) + " / " + getNodePathShort() + " ]"); |
|||
_executeInFork(std::bind(&PityUnit::_run, this), false); |
|||
// Execute as normal funciton
|
|||
} else if (_exec_mode == ExecutionMode::FUNCTION) { |
|||
logH3("[ " + to_string(_exec_mode) + " / " + getNodePathShort() + " ]"); |
|||
_run(); |
|||
} else if (_exec_mode == ExecutionMode::THREAD_PARALLEL) { |
|||
throw std::invalid_argument(to_string(_exec_mode) + " - not implemented"); |
|||
} else if (_exec_mode == ExecutionMode::THREAD_SEQUENTIAL) { |
|||
throw std::invalid_argument(to_string(_exec_mode) + " - not implemented"); |
|||
} |
|||
|
|||
if(_isRootNode()) { |
|||
_waitChildProcesses(); |
|||
} |
|||
} |
|||
|
|||
template<class T> |
|||
std::string PityUnit<T>::to_string(bool recursive, int indent) const |
|||
{ |
|||
std::string ret; |
|||
std::stringstream builder; |
|||
builder << std::string(indent * 4, ' '); |
|||
|
|||
builder << getNodeName(); |
|||
builder << " [ "; |
|||
builder << to_string(_exec_mode) << " - "; |
|||
builder << "\"" << processDir() << "\""; |
|||
builder << " ]"; |
|||
builder << std::endl; |
|||
ret = builder.str(); |
|||
|
|||
if (recursive) { |
|||
indent++; |
|||
for (const std::pair<std::string, const PityUnit&> child : _children) { |
|||
ret += child.second.to_string(true, indent); |
|||
} |
|||
indent--; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
template<class T> |
|||
std::string PityUnit<T>::to_string(const ExecutionMode& emode) |
|||
{ |
|||
switch (emode) { |
|||
case ExecutionMode::FUNCTION: |
|||
return "FUNCTION"; |
|||
case ExecutionMode::PROCESS_SEQUENTIAL: |
|||
return "PROC_SEQ"; |
|||
case ExecutionMode::PROCESS_PARALLEL: |
|||
return "PROC_PAR"; |
|||
case ExecutionMode::THREAD_SEQUENTIAL: |
|||
return "THREAD_S"; |
|||
case ExecutionMode::THREAD_PARALLEL: |
|||
return "THREAD_P"; |
|||
case ExecutionMode::INHERIT: |
|||
return "INHERIT"; |
|||
default: |
|||
return "UNDEFINED EXECUTION MODE"; |
|||
} |
|||
} |
|||
|
|||
//Well, ok, lets just add some little convenience logging service in here, too
|
|||
template<class T> |
|||
void PityUnit<T>::log(const std::string& msg) const |
|||
{ |
|||
std::stringstream builder; |
|||
builder << "["; |
|||
builder << std::to_string(getpid()); |
|||
builder << " - "; |
|||
builder << getNodePathShort(); |
|||
builder << "] - "; |
|||
builder << msg; |
|||
builder << std::endl; |
|||
std::cout << builder.str(); |
|||
} |
|||
|
|||
// PRIVATE ---------------------------------------------------------------------------------
|
|||
|
|||
template<class T> |
|||
void PityUnit<T>::_run() const |
|||
{ |
|||
_runSelf(); |
|||
_runChildren(); |
|||
} |
|||
|
|||
template<class T> |
|||
void PityUnit<T>::_runSelf() const |
|||
{ |
|||
if (_test_func != nullptr) { |
|||
_test_func(*this); |
|||
} else { |
|||
log("No function to execute"); |
|||
} |
|||
} |
|||
|
|||
template<class T> |
|||
void PityUnit<T>::_runChildren() const |
|||
{ |
|||
if (!_children.empty()) { |
|||
for (const std::pair<std::string, PityUnit&> child : _children) { |
|||
child.second.run(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
template<class T> |
|||
void PityUnit<T>::_executeInFork(std::function<void(void)> func, bool wait_child) const |
|||
{ |
|||
pid_t pid; |
|||
pid = fork(); |
|||
if (pid == pid_t(0)) { |
|||
func(); |
|||
exit(0); |
|||
} else if (pid < pid_t(0)) { |
|||
throw std::runtime_error("Error forking"); |
|||
} |
|||
if (wait_child) { |
|||
_waitChildProcesses(); |
|||
} |
|||
} |
|||
|
|||
template<class T> |
|||
void PityUnit<T>::_waitChildProcesses() const |
|||
{ |
|||
int status; |
|||
pid_t pid; |
|||
while ((pid = wait(&status)) > 0) { |
|||
log( |
|||
"process[" + std::to_string((int)pid) + |
|||
"] terminated with status: " + std::to_string(status)); |
|||
} |
|||
} |
|||
|
|||
template<class T> |
|||
void PityUnit<T>::_addChildNode(PityUnit& node) |
|||
{ |
|||
_children.insert(std::pair<std::string, PityUnit&>(node.getNodeName(), node)); |
|||
} |
|||
|
|||
template<class T> |
|||
bool PityUnit<T>::_isProcessNode() const |
|||
{ |
|||
bool ret = false; |
|||
if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL || |
|||
_exec_mode == ExecutionMode::PROCESS_PARALLEL) { |
|||
ret = true; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
template<class T> |
|||
bool PityUnit<T>::_isRootNode() const |
|||
{ |
|||
if (_parent == nullptr) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
template<class T> |
|||
const PityUnit<T>& PityUnit<T>::_rootNode() const |
|||
{ |
|||
const PityUnit* ret = nullptr; |
|||
if (!_isRootNode()) { |
|||
ret = &(_parent->_rootNode()); |
|||
} else { |
|||
ret = this; |
|||
} |
|||
assert(ret != nullptr); |
|||
// cant be null because for createChildNode() you need to provide a TestNode& and
|
|||
// the only other way is using createRootNode() which has parent == nullptr
|
|||
return *ret; |
|||
} |
|||
|
|||
template<class T> |
|||
const PityUnit<T>& PityUnit<T>::_parentingProcessNode() const |
|||
{ |
|||
if (_isRootNode() || _isProcessNode()) { |
|||
return *this; |
|||
} else { |
|||
return _parent->_parentingProcessNode(); |
|||
} |
|||
} |
|||
|
|||
// name is alphanumeric only (everything else will be replaced by an underscore)
|
|||
template<class T> |
|||
std::string PityUnit<T>::_normalizeName(std::string name) const |
|||
{ |
|||
replace_if( |
|||
name.begin(), |
|||
name.end(), |
|||
[](char c) -> bool { return !isalnum(c); }, |
|||
'_'); |
|||
|
|||
return name; |
|||
} |
|||
|
|||
template<class T> |
|||
void PityUnit<T>::_data_dir_create() |
|||
{ |
|||
// Utils::dir_create(dataDir());
|
|||
log("creating dir:" + getGlobalRootDir()); |
|||
} |
|||
|
|||
template<class T> |
|||
void PityUnit<T>::_data_dir_delete() |
|||
{ |
|||
try { |
|||
Utils::path_delete_all(getGlobalRootDir()); |
|||
} catch (const std::exception& e) { |
|||
log("DistTest: - could not delete data dir: " + getGlobalRootDir()); |
|||
} |
|||
} |
|||
|
|||
template<class T> |
|||
void PityUnit<T>::_data_dir_recreate() |
|||
{ |
|||
_data_dir_delete(); |
|||
_data_dir_create(); |
|||
}; |
|||
} // namespace Test
|
|||
} // namespace pEp
|
|||
|
|||
#endif // PITYTEST_PITYUNIT_HXX
|
@ -0,0 +1,65 @@ |
|||
#include "../src/PityUnit.hh" |
|||
#include <iostream> |
|||
|
|||
using namespace std; |
|||
using namespace pEp::PityTest11; |
|||
|
|||
void printHomeDir(const PityUnit<>& myself, int sleepmilis, int rep_count) |
|||
{ |
|||
int i = 0; |
|||
while (i < rep_count) { |
|||
myself.log(myself.getNodeName() + " - " + to_string(i)); |
|||
sleep_millis(sleepmilis); |
|||
i++; |
|||
} |
|||
} |
|||
|
|||
int main(int argc, char* argv[]) |
|||
{ |
|||
{ |
|||
// DEBUG Logging of PityTestUnit itself
|
|||
PityUnit<>::debug_log_enabled = false; |
|||
|
|||
// Configure DataRoot for all TestNodes
|
|||
PityUnit<>::setGlobalRootDir("./basic_data_root"); |
|||
|
|||
// The RootNode is the
|
|||
PityUnit<> root = PityUnit<>{ nullptr, "Test Execution Model" }; |
|||
|
|||
// Subprocess 1
|
|||
PityUnit<> test1 = PityUnit<>{ &root, |
|||
"node1", |
|||
[](const PityUnit<>& mynode) { |
|||
printHomeDir(mynode, 200, 10); |
|||
}, |
|||
nullptr, |
|||
pEp::PityTest11::PityUnit<>::ExecutionMode::PROCESS_PARALLEL }; |
|||
|
|||
PityUnit<> test1_1 = PityUnit<>{ &test1, "test1.1", [](const PityUnit<>& mynode) { |
|||
printHomeDir(mynode, 200, 10); |
|||
} }; |
|||
|
|||
PityUnit<> test1_2 = PityUnit<>{ &test1, "test1.2", [](const PityUnit<>& mynode) { |
|||
printHomeDir(mynode, 200, 10); |
|||
} }; |
|||
|
|||
// Subprocess 2
|
|||
PityUnit<> test2 = PityUnit<>{ &root, |
|||
"node2", |
|||
[](const PityUnit<>& mynode) { |
|||
printHomeDir(mynode, 200, 10); |
|||
}, |
|||
nullptr, |
|||
pEp::PityTest11::PityUnit<>::ExecutionMode::PROCESS_PARALLEL }; |
|||
|
|||
PityUnit<> test2_1 = PityUnit<>{ &test2, "test2.1", [](const PityUnit<>& mynode) { |
|||
printHomeDir(mynode, 200, 10); |
|||
} }; |
|||
|
|||
PityUnit<> test2_2 = PityUnit<>{ &test2, "test2.2", [](const PityUnit<>& mynode) { |
|||
printHomeDir(mynode, 200, 10); |
|||
} }; |
|||
|
|||
test1.run(); |
|||
} |
|||
} |
@ -0,0 +1,55 @@ |
|||
#include "../src/PityUnit.hh" |
|||
#include "../../framework/utils.hh" |
|||
#include <iostream> |
|||
#include <algorithm> |
|||
|
|||
using namespace std; |
|||
using namespace pEp::PityTest11; |
|||
|
|||
void printHomeDir(const PityUnit<>& myself) |
|||
{ |
|||
// TESTLOG(string(myself.getFQName() + " - PID: " + to_string(getpid())));
|
|||
// cout << "[" << to_string(getpid()) << "/" << myself.getFQName() << "] - " << endl;
|
|||
setenv("HOME", myself.processDir().c_str(), 1); |
|||
myself.log("HOME=" + string(getenv("HOME"))); |
|||
} |
|||
|
|||
void ptAssert(bool condition) { |
|||
if(!condition) { |
|||
|
|||
} |
|||
} |
|||
|
|||
int main(int argc, char* argv[]) |
|||
{ |
|||
PityUnit<>::debug_log_enabled = false; |
|||
PityUnit<>::setGlobalRootDir("./"); |
|||
PityUnit<> root = PityUnit<>{ nullptr, "rootnode" }; |
|||
|
|||
PityUnit<> test1 = PityUnit<>{ &root, "node 1", [](const PityUnit<>& mynode) { |
|||
assert(mynode.processDir() == "./rootnode/"); |
|||
} }; |
|||
|
|||
PityUnit<> test1_1 = PityUnit<>{ &test1, "node 1.1", [](const PityUnit<>& mynode) { |
|||
assert(mynode.processDir() == "./rootnode/"); |
|||
} }; |
|||
|
|||
PityUnit<> test2 = PityUnit<>{ &root, "node 2", [](const PityUnit<>& mynode) { |
|||
assert(mynode.processDir() == "./rootnode/"); |
|||
} }; |
|||
|
|||
PityUnit<> test2_1 = PityUnit<>{ &test2, |
|||
"node 2.1", |
|||
[](const PityUnit<>& mynode) { |
|||
assert(mynode.processDir() == "./rootnode/"); |
|||
}, |
|||
nullptr, |
|||
pEp::PityTest11::PityUnit<>::ExecutionMode::PROCESS_PARALLEL }; |
|||
|
|||
|
|||
PityUnit<> test2_1_1 = PityUnit<>{ &test2_1, "node 2.1.1", [](PityUnit<> mynode) { |
|||
assert(mynode.processDir() == "./rootnode/"); |
|||
} }; |
|||
|
|||
root.run(); |
|||
} |
Loading…
Reference in new issue