From e9a2a580af6c00c6499af0867fe14d014d35e709 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (l)" <j.wuttke@fz-juelich.de>
Date: Fri, 5 Aug 2016 10:10:06 +0200
Subject: [PATCH] Start PyPersistenceTest, to resolve #1440

---
 Tests/Functional/CMakeLists.txt               |   5 +-
 Tests/Functional/Core/CoreTest.h              |   6 +-
 Tests/Functional/Fit/FitTest.cpp              |   2 +-
 .../PyCore/{suite => export}/CMakeLists.txt   |   0
 .../PyExportStandardTest.cpp                  |   2 +-
 .../PyCore/{suite => export}/PyExportTest.cpp |   0
 .../PyCore/{suite => export}/PyExportTest.h   |   0
 .../PyCore/{scripts => legacy}/CMakeLists.txt |   0
 .../PyCore/{scripts => legacy}/README         |   0
 .../{scripts => legacy}/customformfactor.py   |   0
 .../cylinders_ba_dwba_size.py                 |   0
 .../detector_resolution.py                    |   0
 .../{scripts => legacy}/intensitydata.py      |   0
 .../{scripts => legacy}/intensitydata_io.py   |   0
 .../intensitydata_io_tiff.py                  |   0
 .../{scripts => legacy}/layerwithroughness.py |   0
 .../{scripts => legacy}/mesocrystal1.py       |   0
 .../montecarlo_integration.py                 |   0
 .../{scripts => legacy}/polmagcylinders1.py   |   0
 .../{scripts => legacy}/polmagcylinders2.py   |   0
 .../PyCore/{scripts => legacy}/ripple1.py     |   0
 .../{scripts => legacy}/ripple2_asym.py       |   0
 .../PyCore/{scripts => legacy}/ripple2_sym.py |   0
 .../transform_BoxComposition.py               |   0
 .../transform_CoreShellBox.py                 |   0
 .../{scripts => legacy}/transform_box.py      |   0
 .../{scripts => legacy}/transform_cube.py     |   0
 .../PyCore/{scripts => legacy}/utils.py       |   0
 .../PyCore/persistence/CMakeLists.txt         |  29 +++++
 .../PyCore/persistence/PyPersistenceTest.cpp  | 108 ++++++++++++++++++
 .../PyCore/persistence/PyPersistenceTest.h    |  53 +++++++++
 .../persistence/RunPyPersistenceTest.cpp      |  31 +++++
 32 files changed, 229 insertions(+), 7 deletions(-)
 rename Tests/Functional/PyCore/{suite => export}/CMakeLists.txt (100%)
 rename Tests/Functional/PyCore/{suite => export}/PyExportStandardTest.cpp (95%)
 rename Tests/Functional/PyCore/{suite => export}/PyExportTest.cpp (100%)
 rename Tests/Functional/PyCore/{suite => export}/PyExportTest.h (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/CMakeLists.txt (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/README (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/customformfactor.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/cylinders_ba_dwba_size.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/detector_resolution.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/intensitydata.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/intensitydata_io.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/intensitydata_io_tiff.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/layerwithroughness.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/mesocrystal1.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/montecarlo_integration.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/polmagcylinders1.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/polmagcylinders2.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/ripple1.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/ripple2_asym.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/ripple2_sym.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/transform_BoxComposition.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/transform_CoreShellBox.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/transform_box.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/transform_cube.py (100%)
 rename Tests/Functional/PyCore/{scripts => legacy}/utils.py (100%)
 create mode 100644 Tests/Functional/PyCore/persistence/CMakeLists.txt
 create mode 100644 Tests/Functional/PyCore/persistence/PyPersistenceTest.cpp
 create mode 100644 Tests/Functional/PyCore/persistence/PyPersistenceTest.h
 create mode 100644 Tests/Functional/PyCore/persistence/RunPyPersistenceTest.cpp

diff --git a/Tests/Functional/CMakeLists.txt b/Tests/Functional/CMakeLists.txt
index 29bb06feecc..c1e4b81de32 100644
--- a/Tests/Functional/CMakeLists.txt
+++ b/Tests/Functional/CMakeLists.txt
@@ -7,8 +7,9 @@ add_subdirectory(Core)
 add_subdirectory(Fit)
 
 if(BORNAGAIN_PYTHON)
-    add_subdirectory(PyCore/scripts)
-    add_subdirectory(PyCore/suite)
+    add_subdirectory(PyCore/legacy)
+    add_subdirectory(PyCore/export)
+    add_subdirectory(PyCore/persistence)
     add_subdirectory(PyFit)
 endif()
 
diff --git a/Tests/Functional/Core/CoreTest.h b/Tests/Functional/Core/CoreTest.h
index 78e2d67b705..7c73328db97 100644
--- a/Tests/Functional/Core/CoreTest.h
+++ b/Tests/Functional/Core/CoreTest.h
@@ -33,10 +33,10 @@ public:
     CoreTest(
         const std::string& name, const std::string& description, GISASSimulation* simulation,
         double threshold);
-    virtual ~CoreTest();
+    ~CoreTest() final;
 
-    virtual void runTest();
-    virtual void printResults(std::ostream& ostr) const;
+    void runTest() final;
+    void printResults(std::ostream& ostr) const final;
 
 private:
     std::string getSimulationResultsFileNameAndPath() const;
diff --git a/Tests/Functional/Fit/FitTest.cpp b/Tests/Functional/Fit/FitTest.cpp
index a66a0385170..51568db3407 100644
--- a/Tests/Functional/Fit/FitTest.cpp
+++ b/Tests/Functional/Fit/FitTest.cpp
@@ -13,7 +13,7 @@
 //
 // ************************************************************************** //
 
-#include "IMinimizerTest.h"
+#include "IFunctionalTest.h"
 #include "StandardFitsFactory.h"
 #include <memory>
 #include <iostream>
diff --git a/Tests/Functional/PyCore/suite/CMakeLists.txt b/Tests/Functional/PyCore/export/CMakeLists.txt
similarity index 100%
rename from Tests/Functional/PyCore/suite/CMakeLists.txt
rename to Tests/Functional/PyCore/export/CMakeLists.txt
diff --git a/Tests/Functional/PyCore/suite/PyExportStandardTest.cpp b/Tests/Functional/PyCore/export/PyExportStandardTest.cpp
similarity index 95%
rename from Tests/Functional/PyCore/suite/PyExportStandardTest.cpp
rename to Tests/Functional/PyCore/export/PyExportStandardTest.cpp
index 867de4df912..73b44d9ace8 100644
--- a/Tests/Functional/PyCore/suite/PyExportStandardTest.cpp
+++ b/Tests/Functional/PyCore/export/PyExportStandardTest.cpp
@@ -20,7 +20,7 @@
 class PyExportStandardTest : public IStandardTest
 {
 public:
-    PyExportStandardTest() : IStandardTest("PySuite") {}
+    PyExportStandardTest() : IStandardTest("PyExport") {}
     IFunctionalTest* getTest() const { return new PyExportTest(
             getTestName(), getTestDescription(), getSimulation(), getTestThreshold()); }
 };
diff --git a/Tests/Functional/PyCore/suite/PyExportTest.cpp b/Tests/Functional/PyCore/export/PyExportTest.cpp
similarity index 100%
rename from Tests/Functional/PyCore/suite/PyExportTest.cpp
rename to Tests/Functional/PyCore/export/PyExportTest.cpp
diff --git a/Tests/Functional/PyCore/suite/PyExportTest.h b/Tests/Functional/PyCore/export/PyExportTest.h
similarity index 100%
rename from Tests/Functional/PyCore/suite/PyExportTest.h
rename to Tests/Functional/PyCore/export/PyExportTest.h
diff --git a/Tests/Functional/PyCore/scripts/CMakeLists.txt b/Tests/Functional/PyCore/legacy/CMakeLists.txt
similarity index 100%
rename from Tests/Functional/PyCore/scripts/CMakeLists.txt
rename to Tests/Functional/PyCore/legacy/CMakeLists.txt
diff --git a/Tests/Functional/PyCore/scripts/README b/Tests/Functional/PyCore/legacy/README
similarity index 100%
rename from Tests/Functional/PyCore/scripts/README
rename to Tests/Functional/PyCore/legacy/README
diff --git a/Tests/Functional/PyCore/scripts/customformfactor.py b/Tests/Functional/PyCore/legacy/customformfactor.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/customformfactor.py
rename to Tests/Functional/PyCore/legacy/customformfactor.py
diff --git a/Tests/Functional/PyCore/scripts/cylinders_ba_dwba_size.py b/Tests/Functional/PyCore/legacy/cylinders_ba_dwba_size.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/cylinders_ba_dwba_size.py
rename to Tests/Functional/PyCore/legacy/cylinders_ba_dwba_size.py
diff --git a/Tests/Functional/PyCore/scripts/detector_resolution.py b/Tests/Functional/PyCore/legacy/detector_resolution.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/detector_resolution.py
rename to Tests/Functional/PyCore/legacy/detector_resolution.py
diff --git a/Tests/Functional/PyCore/scripts/intensitydata.py b/Tests/Functional/PyCore/legacy/intensitydata.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/intensitydata.py
rename to Tests/Functional/PyCore/legacy/intensitydata.py
diff --git a/Tests/Functional/PyCore/scripts/intensitydata_io.py b/Tests/Functional/PyCore/legacy/intensitydata_io.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/intensitydata_io.py
rename to Tests/Functional/PyCore/legacy/intensitydata_io.py
diff --git a/Tests/Functional/PyCore/scripts/intensitydata_io_tiff.py b/Tests/Functional/PyCore/legacy/intensitydata_io_tiff.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/intensitydata_io_tiff.py
rename to Tests/Functional/PyCore/legacy/intensitydata_io_tiff.py
diff --git a/Tests/Functional/PyCore/scripts/layerwithroughness.py b/Tests/Functional/PyCore/legacy/layerwithroughness.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/layerwithroughness.py
rename to Tests/Functional/PyCore/legacy/layerwithroughness.py
diff --git a/Tests/Functional/PyCore/scripts/mesocrystal1.py b/Tests/Functional/PyCore/legacy/mesocrystal1.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/mesocrystal1.py
rename to Tests/Functional/PyCore/legacy/mesocrystal1.py
diff --git a/Tests/Functional/PyCore/scripts/montecarlo_integration.py b/Tests/Functional/PyCore/legacy/montecarlo_integration.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/montecarlo_integration.py
rename to Tests/Functional/PyCore/legacy/montecarlo_integration.py
diff --git a/Tests/Functional/PyCore/scripts/polmagcylinders1.py b/Tests/Functional/PyCore/legacy/polmagcylinders1.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/polmagcylinders1.py
rename to Tests/Functional/PyCore/legacy/polmagcylinders1.py
diff --git a/Tests/Functional/PyCore/scripts/polmagcylinders2.py b/Tests/Functional/PyCore/legacy/polmagcylinders2.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/polmagcylinders2.py
rename to Tests/Functional/PyCore/legacy/polmagcylinders2.py
diff --git a/Tests/Functional/PyCore/scripts/ripple1.py b/Tests/Functional/PyCore/legacy/ripple1.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/ripple1.py
rename to Tests/Functional/PyCore/legacy/ripple1.py
diff --git a/Tests/Functional/PyCore/scripts/ripple2_asym.py b/Tests/Functional/PyCore/legacy/ripple2_asym.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/ripple2_asym.py
rename to Tests/Functional/PyCore/legacy/ripple2_asym.py
diff --git a/Tests/Functional/PyCore/scripts/ripple2_sym.py b/Tests/Functional/PyCore/legacy/ripple2_sym.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/ripple2_sym.py
rename to Tests/Functional/PyCore/legacy/ripple2_sym.py
diff --git a/Tests/Functional/PyCore/scripts/transform_BoxComposition.py b/Tests/Functional/PyCore/legacy/transform_BoxComposition.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/transform_BoxComposition.py
rename to Tests/Functional/PyCore/legacy/transform_BoxComposition.py
diff --git a/Tests/Functional/PyCore/scripts/transform_CoreShellBox.py b/Tests/Functional/PyCore/legacy/transform_CoreShellBox.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/transform_CoreShellBox.py
rename to Tests/Functional/PyCore/legacy/transform_CoreShellBox.py
diff --git a/Tests/Functional/PyCore/scripts/transform_box.py b/Tests/Functional/PyCore/legacy/transform_box.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/transform_box.py
rename to Tests/Functional/PyCore/legacy/transform_box.py
diff --git a/Tests/Functional/PyCore/scripts/transform_cube.py b/Tests/Functional/PyCore/legacy/transform_cube.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/transform_cube.py
rename to Tests/Functional/PyCore/legacy/transform_cube.py
diff --git a/Tests/Functional/PyCore/scripts/utils.py b/Tests/Functional/PyCore/legacy/utils.py
similarity index 100%
rename from Tests/Functional/PyCore/scripts/utils.py
rename to Tests/Functional/PyCore/legacy/utils.py
diff --git a/Tests/Functional/PyCore/persistence/CMakeLists.txt b/Tests/Functional/PyCore/persistence/CMakeLists.txt
new file mode 100644
index 00000000000..dceb4ae996c
--- /dev/null
+++ b/Tests/Functional/PyCore/persistence/CMakeLists.txt
@@ -0,0 +1,29 @@
+############################################################################
+# Tests/Functional/PyCore/suite/CMakeLists.txt
+############################################################################
+
+set(test_cases
+    ApproximationDA
+    ApproximationLMA
+    ToBeReplacedByGlob
+)
+
+# for some reason these flags doesn't propagated here by SetUpWindows.cmake
+if(MSVC)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc ")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /EHsc ")
+endif()
+
+include_directories(
+    ${BornAgainCore_INCLUDE_DIRS}
+    ${EIGEN3_INCLUDE_DIR}
+    ${CMAKE_SOURCE_DIR}/Core/Simulation
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../TestMachinery
+)
+
+add_executable(PyPersistenceTest RunPyPersistenceTest.cpp PyPersistenceTest.h PyPersistenceTest.cpp)
+target_link_libraries(PyPersistenceTest BornAgainCore BornAgainTestMachinery)
+foreach(test_case ${test_cases})
+    add_test(PyPersistenceTest/${test_case}
+        ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PyPersistenceTest ${test_case})
+endforeach()
diff --git a/Tests/Functional/PyCore/persistence/PyPersistenceTest.cpp b/Tests/Functional/PyCore/persistence/PyPersistenceTest.cpp
new file mode 100644
index 00000000000..80aead66d91
--- /dev/null
+++ b/Tests/Functional/PyCore/persistence/PyPersistenceTest.cpp
@@ -0,0 +1,108 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Tests/Functional/PyCore/suite/PyPersistenceTest.cpp
+//! @brief     Implements class PyPersistenceTest
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2015
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
+//
+// ************************************************************************** //
+
+#include "PyPersistenceTest.h"
+#include "BAPython.h"
+#include "FileSystem.h"
+#include "GISASSimulation.h"
+#include "IntensityDataFunctions.h"
+#include "IntensityDataIOFactory.h"
+#include "PythonFormatting.h"
+#include "SimulationFactory.h"
+#include "TestConfig.h"
+#include "Utils.h"
+#include <cstdio>
+#include <cstdlib>
+#include <fstream>
+
+PyPersistenceTest::PyPersistenceTest(const std::string& name)
+    : IFunctionalTest(name, "persistence test on script "+name)
+    , m_reference_simulation(nullptr)
+    , m_domain_simulation(0)
+    , m_threshold(2e-10)
+    , m_difference(0)
+    , m_pyscript_filename( BUILD_TMP_DIR + "/pysuite_" + name + ".py" )
+    , m_output_filename( BUILD_TMP_DIR + "/pysuite_" + name + ".int" )
+{
+}
+
+PyPersistenceTest::~PyPersistenceTest()
+{
+    delete m_reference_simulation;
+    delete m_domain_simulation;
+}
+
+void PyPersistenceTest::runTest()
+{
+    // Generate Python script
+    std::ostringstream ostr;
+    ostr << "# Functional test settings, generated by PyPersistenceTest::runTest():\n"
+         << "import sys, os\n"
+         << "sys.path.append('" << BUILD_LIB_DIR << "')\n\n"
+         << "# Simulation script, generated by PythonFormatting::simulationToPython(..):\n"
+         << PythonFormatting::simulationToPython(m_reference_simulation);
+    std::ofstream pythonFile(m_pyscript_filename);
+    pythonFile << ostr.str();
+    pythonFile.close();
+    std::cout << "Generated Python script " << m_pyscript_filename <<"." << std::endl/*sic*/;
+        // Here we are using std::endl instead of "\n" in order to flush because otherwise
+        // the system calls 'remove' and 'system' may break the order of output lines.
+
+    // Run Python script
+    std::remove( m_output_filename.c_str() );
+    std::cout << "Removed old data set " << m_output_filename << "." << std::endl/*sic*/;
+    std::string command = std::string(BORNAGAIN_PYTHON_EXE) + " " + m_pyscript_filename +
+        " " + m_output_filename;
+    std::cout << "Now running command '" << command << "'." << std::endl/*sic*/;
+    int ret = std::system(command.c_str()); // run python script
+    if (ret!=0) {
+        std::cerr << "Command returned non-zero value " << ret << ".\n";
+        m_result = FAILED;
+        return;
+    }
+
+    // Run direct simulation
+    std::cout <<
+        "Now going to directly run the simulation, and to compare with result from Py script.\n";
+    assert(m_reference_simulation);
+    m_reference_simulation->runSimulation();
+    const std::unique_ptr<OutputData<double> > P_reference_data(
+        m_reference_simulation->getDetectorIntensity());
+
+    // Compare results
+    const std::unique_ptr<OutputData<double> > P_domain_data(
+        IntensityDataIOFactory::readOutputData(m_output_filename));
+    m_difference = IntensityDataFunctions::getRelativeDifference(*P_domain_data, *P_reference_data);
+    m_result = m_difference > m_threshold ? FAILED_DIFF : SUCCESS;
+    if (m_result != SUCCESS) {
+        // Move failed Python script to failed tests directory
+        Utils::FileSystem::CreateDirectory(FAILED_TESTS_DIR);
+        std::rename( m_pyscript_filename.c_str(), getPySuiteFileNameAndPath().c_str());
+    }
+}
+
+void PyPersistenceTest::printResults(std::ostream& ostr) const
+{
+    ostr << getFormattedInfoString();
+    ostr << Utils::String::getScientificDoubleString(m_difference);
+    if (m_result != SUCCESS)
+        ostr << "--> " << getPySuiteFileNameAndPath();
+}
+
+std::string PyPersistenceTest::getPySuiteFileNameAndPath() const
+{
+    std::string result = Utils::FileSystem::GetJoinPath(FAILED_TESTS_DIR, m_pyscript_filename);
+    return result;
+}
diff --git a/Tests/Functional/PyCore/persistence/PyPersistenceTest.h b/Tests/Functional/PyCore/persistence/PyPersistenceTest.h
new file mode 100644
index 00000000000..5fb12070b8f
--- /dev/null
+++ b/Tests/Functional/PyCore/persistence/PyPersistenceTest.h
@@ -0,0 +1,53 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Tests/Functional/PyCore/suite/PyPersistenceTest.h
+//! @brief     Declares class PyPersistenceTest
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2015
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
+//
+// ************************************************************************** //
+
+#ifndef PYSUITETEST_H
+#define PYSUITETEST_H
+
+#include "IFunctionalTest.h" // inheriting from
+#include "OutputData.h"
+
+//! @class PyPersistenceTest
+//! @ingroup standard_samples
+//! @brief A functional test of PyCore (the Python wrapper of BornAgain/Core).
+//!   Performs a given standard simulation, both directly and from a Python dump.
+//!   Invoked from PyPersistenceStandardTest.
+
+class PyPersistenceTest : public IFunctionalTest
+{
+public:
+    PyPersistenceTest(const std::string& name);
+    ~PyPersistenceTest() final;
+
+    void runTest() final;
+
+    const OutputData<double>* getOutputData() const;
+
+    double getDifference() const { return m_difference; }
+
+    void printResults(std::ostream& ostr) const final;
+
+private:
+    std::string getPySuiteFileNameAndPath() const;
+
+    class GISASSimulation* m_reference_simulation;
+    class GISASSimulation* m_domain_simulation;
+    double m_threshold;
+    double m_difference;
+    std::string m_pyscript_filename;
+    std::string m_output_filename;
+};
+
+#endif // PYSUITETEST_H
diff --git a/Tests/Functional/PyCore/persistence/RunPyPersistenceTest.cpp b/Tests/Functional/PyCore/persistence/RunPyPersistenceTest.cpp
new file mode 100644
index 00000000000..4fb9d9aef33
--- /dev/null
+++ b/Tests/Functional/PyCore/persistence/RunPyPersistenceTest.cpp
@@ -0,0 +1,31 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Tests/Functional/PyCore/suite/PyPersistenceStandardTest.cpp
+//! @brief     Implements program PyPersistenceStandardTest, to run functional tests
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2015
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
+//
+// ************************************************************************** //
+
+#include "PyPersistenceTest.h"
+#include <cstdlib>
+#include <iostream>
+
+//! Runs PyPersistenceTest on a standard simulation indicated by argv[1].
+int main(int argc, char** argv)
+{
+    if(argc<3){
+        std::cout << "Usage: " << argv[0] << " <scriptname [without extension .py]>\n";
+        std::exit(1);
+    }
+    PyPersistenceTest test(argv[1]);
+    test.runTest();
+    std::cout << test << "\n";
+    return test.getTestResult();
+}
-- 
GitLab