Commit 854e4884 authored by Dave Moxey's avatar Dave Moxey

Add test for error streams, add verbose output to Tester and fix a few compiler warnings

parent 1123c73a
......@@ -4,6 +4,8 @@ ADD_NEKTAR_EXECUTABLE(NodalDemo
COMPONENT demos DEPENDS LibUtilities SOURCES NodalDemo.cpp)
ADD_NEKTAR_EXECUTABLE(TimeIntegrationDemo
COMPONENT demos DEPENDS LibUtilities SOURCES TimeIntegrationDemo.cpp)
ADD_NEKTAR_EXECUTABLE(ErrorStream
COMPONENT demos DEPENDS LibUtilities SOURCES ErrorStream.cpp)
IF(NEKTAR_USE_MPI)
ADD_NEKTAR_EXECUTABLE(FieldIOBenchmarker
......
////////////////////////////////////////////////////////////////////////////////
//
// File: ErrorStream.cpp
//
// For more information, please see: http://www.nektar.info/
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and laimitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Ensure that error stream tester and exception handling works.
//
////////////////////////////////////////////////////////////////////////////////
#include <LibUtilities/BasicUtils/ErrorUtil.hpp>
#include <LibUtilities/BasicUtils/SessionReader.h>
#include <sstream>
#include <vector>
using namespace Nektar;
int main(int argc, char *argv[])
{
// Set up a stringstream to catch any error output.
std::stringstream ss;
ErrorUtil::SetErrorStream(ss);
// Set up output that will be overwritten with exception error (any
// non-empty string).
std::string output = "some error";
// Run a piece of code designed to generate an error: create a SessionReader
// with missing file.
try
{
std::vector<std::string> arguments = {"ErrorStream", "missing.xml"};
std::vector<char*> argv;
for (const auto& arg : arguments)
{
argv.push_back((char*)arg.data());
}
argv.push_back(nullptr);
LibUtilities::SessionReaderSharedPtr session =
LibUtilities::SessionReader::CreateInstance(2, &argv[0]);
session->InitSession();
}
catch (const ErrorUtil::NekError &e)
{
// Format exception error to the appropriate message that should be
// output by the ErrorUtil class.
std::stringstream outf;
outf << "Fatal : " << e.what() << std::endl;
output = outf.str();
}
// Check to see whether we get the correct output.
if (output == ss.str())
{
std::cout << "Caught exception error message matches stringstream"
<< std::endl;
return 0;
}
std::cout << "Difference between exception message and stringstream."
<< std::endl << "Stringstream contains:" << std::endl
<< ss.str() << std::endl << std::endl
<< "Exception contains:" << std::endl
<< output << std::endl;
return 1;
}
<?xml version="1.0" encoding="utf-8" ?>
<test>
<description>Test error streams</description>
<executable>ErrorStream</executable>
<parameters></parameters>
<metrics>
</metrics>
</test>
......@@ -34,6 +34,7 @@
////////////////////////////////////////////////////////////////////////////////
#include <NekMeshUtils/CADSystem/OCE/CADSurfOCE.h>
#include <boost/lexical_cast.hpp>
using namespace std;
......
......@@ -43,6 +43,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
using namespace std;
......
......@@ -50,7 +50,7 @@ namespace Nektar
* @brief Constructor.
*/
Metric::Metric(TiXmlElement *metric, bool generate) :
m_metric(metric), m_generate(generate)
m_generate(generate), m_metric(metric)
{
if (!metric->Attribute("id"))
{
......
......@@ -40,8 +40,15 @@
#include <string>
#include <map>
#include <boost/filesystem.hpp>
#include <exception>
#define ASSERTL0(condition,msg)
struct TesterException : public std::runtime_error
{
TesterException(const std::string &msg) : std::runtime_error(msg) {}
};
#define ASSERTL0(condition, msg) \
if (!(condition)) { throw TesterException(msg); }
namespace fs = boost::filesystem;
......@@ -49,6 +56,19 @@ std::string PortablePath(const boost::filesystem::path& path);
namespace Nektar
{
/**
* @brief Check to see whether the given string @p s is empty (or null).
*/
inline bool EmptyString(const char *s)
{
if (!s)
{
return true;
}
return std::string(s) == "";
}
class Metric
{
public:
......@@ -58,14 +78,25 @@ namespace Nektar
bool Test (std::istream& pStdout, std::istream& pStderr);
/// Perform the test, given the standard output and error streams
void Generate (std::istream& pStdout, std::istream& pStderr);
/// Return metric type
std::string GetType()
{
return m_type;
}
/// Return metric ID
int GetID()
{
return m_id;
}
protected:
/// Stores the ID of this metric.
int m_id;
/// Stores the type of this metric (uppercase).
std::string m_type;
///
/// Determines whether to generate this metric or not.
bool m_generate;
/// Pointer to XML structure containing metric definition.
TiXmlElement *m_metric;
virtual bool v_Test (std::istream& pStdout,
......
......@@ -68,7 +68,7 @@ namespace Nektar
{
ASSERTL0(value->Attribute("tolerance"),
"Missing tolerance in eigenvalue metric");
ASSERTL0(value->GetText() || value->GetText() == "",
ASSERTL0(!EmptyString(value->GetText()),
"Missing value in preconditioner metric.");
MetricRegexFieldValue mag, angle;
......
......@@ -187,7 +187,6 @@ namespace Nektar
void MetricFile::v_Generate(std::istream& pStdout, std::istream& pStderr)
{
std::map<std::string, std::string>::iterator it;
bool success = true;
// Update SHA1 hashes.
for (it = m_filehash.begin(); it != m_filehash.end(); ++it)
......
......@@ -62,7 +62,7 @@ namespace Nektar
// the L2 error.
ASSERTL0(value->Attribute("tolerance"),
"Missing tolerance in L2 metric");
ASSERTL0(value->GetText() || value->GetText() == "",
ASSERTL0(!EmptyString(value->GetText()),
"Missing value in L2 metric.");
MetricRegexFieldValue var;
......
......@@ -63,7 +63,7 @@ namespace Nektar
// the L2 error.
ASSERTL0(value->Attribute("tolerance"),
"Missing tolerance in L2 metric");
ASSERTL0(value->GetText() || value->GetText() == "",
ASSERTL0(!EmptyString(value->GetText()),
"Missing value in L2 metric.");
MetricRegexFieldValue var;
......
......@@ -62,7 +62,7 @@ namespace Nektar
// the precon iteration count.
ASSERTL0(value->Attribute("tolerance"),
"Missing tolerance in preconditioner metric");
ASSERTL0(value->GetText() || value->GetText() == "",
ASSERTL0(!EmptyString(value->GetText()),
"Missing value in preconditioner metric.");
MetricRegexFieldValue val;
......
......@@ -109,6 +109,8 @@ int main(int argc, char *argv[])
return 1;
}
bool verbose = vm.count("verbose");
// Set up set containing metrics to be generated.
vector<int> metricGenVec;
if (vm.count("generate-metric"))
......@@ -139,9 +141,19 @@ int main(int argc, char *argv[])
try
{
if (verbose)
{
cerr << "Reading test file definition: " << specFile << endl;
}
// Parse the test file
TestData file(specFile, vm);
if (verbose && file.GetNumMetrics() > 0)
{
cerr << "Creating metrics:" << endl;
}
// Generate the metric objects
vector<MetricSharedPtr> metrics;
for (unsigned int i = 0; i < file.GetNumMetrics(); ++i)
......@@ -156,6 +168,12 @@ int main(int argc, char *argv[])
genMetric
));
if (verbose)
{
cerr << " - ID " << metrics.back()->GetID() << ": "
<< metrics.back()->GetType() << endl;
}
if (it != metricGen.end())
{
metricGen.erase(it);
......@@ -181,12 +199,22 @@ int main(int argc, char *argv[])
fs::remove_all(tmpDir);
}
if (verbose)
{
cerr << "Creating working directory: " << tmpDir << endl;
}
// Create temporary directory
fs::create_directory(tmpDir);
// Change working directory to the temporary directory
fs::current_path(tmpDir);
if (verbose && file.GetNumDependentFiles())
{
cerr << "Copying required files: " << endl;
}
// Copy required files for this test from the test definition directory
// to the temporary directory.
for (unsigned int i = 0; i < file.GetNumDependentFiles(); ++i)
......@@ -196,6 +224,10 @@ int main(int argc, char *argv[])
fs::path source = specPath / source_file;
fs::path dest = tmpDir / source_file.filename();
fs::copy_file(source, dest);
if (verbose)
{
cerr << " - " << source << " -> " << dest << endl;
}
}
// Construct test command to run. If in debug mode, append "-g"
......@@ -237,6 +269,11 @@ int main(int argc, char *argv[])
status = 0;
string line;
if (verbose)
{
cerr << "Running command: " << command << endl;
}
// Run executable to perform test.
if (system(command.c_str()))
{
......@@ -264,21 +301,50 @@ int main(int argc, char *argv[])
// Test against all metrics
if (status == 0)
{
if (verbose && metrics.size())
{
cerr << "Checking metrics:" << endl;
}
for (int i = 0; i < metrics.size(); ++i)
{
bool gen = metricGen.find(metrics[i]->GetID()) != metricGen.end() ||
(vm.count("generate-all-metrics") > 0);
vStdout.clear();
vStderr.clear();
vStdout.seekg(0, ios::beg);
vStderr.seekg(0, ios::beg);
if (verbose)
{
cerr << " - " << (gen ? "generating" : "checking")
<< " metric " << metrics[i]->GetID()
<< " (" << metrics[i]->GetType() << ")... ";
}
if (!metrics[i]->Test(vStdout, vStderr))
{
status = 1;
if (verbose)
{
cerr << "failed!" << endl;
}
}
else if (verbose)
{
cerr << "passed" << endl;
}
}
}
if (verbose)
{
cerr << endl << endl;
}
// Dump output files to terminal for debugging purposes on fail.
if (status == 1)
if (status == 1 || verbose)
{
vStdout.clear();
vStderr.clear();
......@@ -306,6 +372,11 @@ int main(int argc, char *argv[])
// Change back to the original path and delete temporary directory.
fs::current_path(startDir);
if (verbose)
{
cerr << "Removing working directory" << endl;
}
// Repeatedly try deleting directory with sleep for filesystems which
// work asynchronously. This allows time for the filesystem to register
// the output files are closed so they can be deleted and not cause a
......@@ -354,8 +425,21 @@ int main(int argc, char *argv[])
cerr << " " << e.what() << endl;
cerr << " Files left in " << tmpDir.string() << endl;
}
catch (const TesterException &e)
{
cerr << "Error occurred during test:" << endl;
cerr << " " << e.what() << endl;
cerr << " Files left in " << tmpDir.string() << endl;
}
catch (const std::exception &e)
{
cerr << "Unhandled exception during test:" << endl;
cerr << " " << e.what() << endl;
cerr << " Files left in " << tmpDir.string() << endl;
}
catch (...)
{
cerr << "Unknown error during test" << endl;
cerr << " Files left in " << tmpDir.string() << endl;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment