Skip to content
Snippets Groups Projects
Commit 0693f6a9 authored by Wuttke, Joachim's avatar Wuttke, Joachim
Browse files

PyPersistTest now compares dat and ref YAML tree entry by entry, allowing for...

PyPersistTest now compares dat and ref YAML tree entry by entry, allowing for a tolerance for floating-point numbers.
Still to do:
- allow for "VARIABILITY" anywhere in the tree
- generate YAML output from Fit tests.
parent b317cdfa
No related branches found
No related tags found
No related merge requests found
...@@ -21,12 +21,15 @@ ...@@ -21,12 +21,15 @@
#include "IntensityDataIOFactory.h" #include "IntensityDataIOFactory.h"
#include "PythonFormatting.h" #include "PythonFormatting.h"
#include "SimulationFactory.h" #include "SimulationFactory.h"
#include "Numeric.h"
#include "Utils.h" #include "Utils.h"
#include <yaml-cpp/yaml.h>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <map> #include <map>
#include <string>
PyPersistenceTest::PyPersistenceTest( PyPersistenceTest::PyPersistenceTest(
const std::string& directory, const std::string& name) const std::string& directory, const std::string& name)
...@@ -103,7 +106,8 @@ void PyPersistenceTest::runTest() ...@@ -103,7 +106,8 @@ void PyPersistenceTest::runTest()
} }
//! Returns true if test output and reference file agree. //! Returns true if test output and reference file agree.
bool PyPersistenceTest::compareFilePair(const std::string& dat_fpath, const std::string& ref_fpath) bool PyPersistenceTest::compareFilePair(
const std::string& dat_fpath, const std::string& ref_fpath) const
{ {
std::cout << "Comparing dat='" << dat_fpath << "' with ref='" << ref_fpath << "':\n"; std::cout << "Comparing dat='" << dat_fpath << "' with ref='" << ref_fpath << "':\n";
const std::string extension = Utils::String::split(FileSystem::filename(dat_fpath), ".")[2]; const std::string extension = Utils::String::split(FileSystem::filename(dat_fpath), ".")[2];
...@@ -117,7 +121,7 @@ bool PyPersistenceTest::compareFilePair(const std::string& dat_fpath, const std: ...@@ -117,7 +121,7 @@ bool PyPersistenceTest::compareFilePair(const std::string& dat_fpath, const std:
//! Returns true if intensity maps from test output and reference file agree reasonably. //! Returns true if intensity maps from test output and reference file agree reasonably.
bool PyPersistenceTest::compareIntensityPair( bool PyPersistenceTest::compareIntensityPair(
const std::string& dat_fpath, const std::string& ref_fpath) const std::string& dat_fpath, const std::string& ref_fpath) const
{ {
const OutputData<double>* dat = IntensityDataIOFactory::readOutputData( dat_fpath ); const OutputData<double>* dat = IntensityDataIOFactory::readOutputData( dat_fpath );
const OutputData<double>* ref = IntensityDataIOFactory::readOutputData( ref_fpath ); const OutputData<double>* ref = IntensityDataIOFactory::readOutputData( ref_fpath );
...@@ -125,34 +129,76 @@ bool PyPersistenceTest::compareIntensityPair( ...@@ -125,34 +129,76 @@ bool PyPersistenceTest::compareIntensityPair(
} }
//! Returns true if YAML files from test output and reference agree. //! Returns true if YAML files from test output and reference agree.
bool PyPersistenceTest::compareYamlPair(const std::string& dat_fpath, const std::string& ref_fpath) bool PyPersistenceTest::compareYamlPair(
const std::string& dat_fpath, const std::string& ref_fpath) const
{ {
std::fstream fdat(dat_fpath); std::fstream fdat(dat_fpath);
std::fstream fref(ref_fpath); std::fstream fref(ref_fpath);
const YAML::Node& dat = YAML::Load(fdat);
const YAML::Node& ref = YAML::Load(fref);
return compareYamlNode( YAML::Load(fdat), YAML::Load(fref) ); return compareYamlNode( YAML::Load(fdat), YAML::Load(fref) );
} }
for (size_t i = 1; ; ++i) { //! Returns true if all entries of the two YAML files agree.
std::string datline; //! Floating-point entries must agree within a certain tolerance.
std::string refline; //! The investigation is performed recursively, iterating over all lists and maps.
std::getline(fdat, datline); bool PyPersistenceTest::compareYamlNode(const YAML::Node& dat, const YAML::Node& ref) const
std::getline(fref, refline); {
if (datline!=refline) { // std::cout << "DEBUG: " << dat.as<std::string>() << " vs " << ref.as<std::string>() << "\n";
std::cerr << "Line " << i << " of " << dat_fpath << " and " << ref_fpath if (dat.Type() != ref.Type()) {
<< " differs:\n"; std::cerr << "YAML node type differs: " << dat.Type() << " vs " << ref.Type() << "\n";
std::cerr << "dat: '" << datline << "'\n"; return false;
std::cerr << "ref: '" << refline << "'\n"; }
return false; if (dat.Type()==YAML::NodeType::Undefined)
throw std::runtime_error("Invalid node type 'Undefined' in YAML tree");
else if (dat.Type()==YAML::NodeType::Null)
throw std::runtime_error("Invalid node type 'Null' in YAML tree");
else if (dat.Type()==YAML::NodeType::Sequence) {
auto it_dat=dat.begin();
auto it_ref=ref.begin();
for (size_t idx=0; ; ++it_dat, ++it_ref, ++idx) {
if (it_dat==dat.end() || it_ref==ref.end()) {
if (!(it_dat==dat.end() && it_ref==ref.end())) {
std::cerr << "lists have different length\n";
return false;
}
return true; // regular exit
}
// now recurse into the node
if (!compareYamlNode(*it_dat, *it_ref)) {
std::cerr << "at list position " << idx << "\n";
return false;
}
} }
if (fdat.eof() && fref.eof()) } else if (dat.Type()==YAML::NodeType::Map) {
break; auto it_dat=dat.begin();
if (fdat.eof() || fref.eof()) { auto it_ref=ref.begin();
std::cerr << "File length of " << dat_fpath << " and " << ref_fpath << " differs.\n"; for ( ; ; ++it_dat, ++it_ref) {
if (it_dat==dat.end() || it_ref==ref.end()) {
if (!(it_dat==dat.end() && it_ref==ref.end())) {
std::cerr << "maps have different length\n";
return false;
}
return true; // regular exit
}
// now recurse into the node
if (!compareYamlNode(it_dat->second, it_ref->second)) {
std::cerr << "at map entry [" << it_dat->first << "]\n";
return false;
}
}
} else if (dat.Type()==YAML::NodeType::Scalar) {
if (dat.as<std::string>() == ref.as<std::string>())
return true;
try {
if (!Numeric::areAlmostEqual( dat.as<double>(), ref.as<double>(), 1e-10 )) {
std::cerr << "numbers differ: " << dat << " vs " << ref << "\n";
return false;
}
return true;
} catch(...) {
std::cerr << "scalar entries differ: '" << dat << "' vs '" << ref << "'\n";
return false; return false;
} }
} } else
std::cout << "Files fully agree.\n"; throw std::runtime_error("Bug in PyPersistenceTest::compareYamlNode: unexpected node type");
return true; return true;
} }
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
#include "IReferencedTest.h" #include "IReferencedTest.h"
#include "OutputData.h" #include "OutputData.h"
namespace YAML {
class Node;
}
//! @class PyPersistenceTest //! @class PyPersistenceTest
//! @ingroup standard_samples //! @ingroup standard_samples
//! @brief A functional test that runs a Python script and compares its output with a reference. //! @brief A functional test that runs a Python script and compares its output with a reference.
...@@ -32,12 +36,17 @@ public: ...@@ -32,12 +36,17 @@ public:
void runTest() final; void runTest() final;
bool compareFilePair(const std::string& dat_fname, const std::string& ref_fname);
bool compareIntensityPair(const std::string& dat_fname, const std::string& ref_fname);
bool compareYamlPair(const std::string& dat_fname, const std::string& ref_fname);
private: private:
std::string m_directory; std::string m_directory;
bool compareFilePair(
const std::string& dat_fname, const std::string& ref_fname) const;
bool compareIntensityPair(
const std::string& dat_fname, const std::string& ref_fname) const;
bool compareYamlPair(
const std::string& dat_fname, const std::string& ref_fname) const;
bool compareYamlNode(
const YAML::Node& dat, const YAML::Node& ref) const;
}; };
#endif // PYPERSISTENCETEST_H #endif // PYPERSISTENCETEST_H
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <iostream> #include <iostream>
IFunctionalTest::ETestResult IReferencedTest::compareIntensityMaps( IFunctionalTest::ETestResult IReferencedTest::compareIntensityMaps(
const OutputData<double>& dat, const OutputData<double>& ref) const OutputData<double>& dat, const OutputData<double>& ref) const
{ {
if( dat.getVariability() != ref.getVariability() ) { if( dat.getVariability() != ref.getVariability() ) {
std::cerr << "Failed: reproducibility threshold has changed from " std::cerr << "Failed: reproducibility threshold has changed from "
......
...@@ -37,7 +37,8 @@ public: ...@@ -37,7 +37,8 @@ public:
protected: protected:
double m_threshold; double m_threshold;
ETestResult compareIntensityMaps(const OutputData<double>& dat, const OutputData<double>& ref); ETestResult compareIntensityMaps(
const OutputData<double>& dat, const OutputData<double>& ref) const;
}; };
#endif // IREFERENCEDTEST_H #endif // IREFERENCEDTEST_H
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment