Merge pull request #1969 from wito/keyword-handler-try-catch

Exception Catch and Release
This commit is contained in:
Joakim Hove
2020-09-29 09:54:41 +02:00
committed by GitHub
6 changed files with 155 additions and 37 deletions
+1
View File
@@ -301,6 +301,7 @@ list (APPEND TEST_SOURCE_FILES
tests/test_cubic.cpp
tests/test_messagelimiter.cpp
tests/test_nonuniformtablelinear.cpp
tests/test_OpmInputError_format.cpp
tests/test_OpmLog.cpp
tests/test_param.cpp
tests/test_RootFinders.cpp
+44 -18
View File
@@ -21,6 +21,7 @@
#include <stdexcept>
#include <string>
#include <utility>
#include <fmt/format.h>
@@ -53,29 +54,44 @@ public:
The message string will be used as format string in the fmt::format()
function as, and optional {} markers can be used to inject keyword,
filename and linenumber into the final what() message. The placeholders
can use named arguments
must use named arguments
{keyword} -> loc.keyword
{file} -> loc.filename
{line} -> loc.lineno
or numbered arguments
{0} -> loc.keyword
{1} -> loc.filename
{2} -> loc.lineno
If just plain {} placeholders are used the order of the arguments is
keyword, filename, linenumber.
additionally, the message can contain any number of positional
arguments to add further context to the message.
KeywordLocation loc("KW", "file.inc", 100);
OpmInputError("Error at line {line} in file{file} - keyword: {keyword} ignored", location)
OpmInputError("Error at line {line} in file {file} - keyword: {keyword} ignored", location);
OpmInputError("Error at line {line} in file {file} - keyword: {keyword} has invalid argument {}", invalid_argument);
*/
template<class ... Args>
OpmInputError(const std::string& msg_fmt, const KeywordLocation& loc, const Args ... additionalArguments) :
m_what { OpmInputError::format(msg_fmt, loc, std::forward<const Args>(additionalArguments)...) },
location { loc }
{}
OpmInputError(const std::string& msg_fmt, const KeywordLocation& loc) :
m_what(OpmInputError::format(msg_fmt, loc)),
location(loc)
/*
Allows for the initialisation of an OpmInputError from another exception.
Usage:
try {
.
.
.
} catch (const Opm::OpmInputError&) {
throw;
} catch (const std::exception& e) {
std::throw_with_nested(Opm::OpmInputError(location, e));
}
*/
OpmInputError(const KeywordLocation& loc, const std::exception& e, const std::string& reason = "Internal error message") :
m_what { OpmInputError::formatException(loc, e, reason) },
location { loc }
{}
const char * what() const throw()
@@ -83,12 +99,22 @@ public:
return this->m_what.c_str();
}
template<class ... Args>
static std::string format(const std::string& msg_format, const KeywordLocation& loc, const Args ... additionalArguments) {
return fmt::format(msg_format,
std::forward<const Args>(additionalArguments)...,
fmt::arg("keyword", loc.keyword),
fmt::arg("file", loc.filename),
fmt::arg("line", loc.lineno)
);
}
static std::string format(const std::string& msg_fmt, const KeywordLocation& loc) {
return fmt::format(msg_fmt,
fmt::arg("keyword", loc.keyword),
fmt::arg("file", loc.filename),
fmt::arg("line", loc.lineno));
static std::string formatException(const KeywordLocation& loc, const std::exception& e, const std::string& reason = "Internal error message") {
const std::string defaultMessage { R"(Problem parsing keyword {keyword}
In {file} line {line}.
{}: {})" } ;
return format(defaultMessage, loc, reason, e.what());
}
@@ -27,6 +27,7 @@
#include <vector>
#include <opm/common/OpmLog/LogUtil.hpp>
#include <opm/common/utility/OpmInputError.hpp>
#include <opm/common/utility/numeric/cmp.hpp>
#include <opm/common/utility/String.hpp>
@@ -1752,7 +1753,15 @@ namespace {
if (function_iterator != handler_functions.end()) {
const auto& handler = function_iterator->second;
handler(this, handlerContext, parseContext, errors);
try {
handler(this, handlerContext, parseContext, errors);
} catch (const OpmInputError&) {
throw;
} catch (const std::exception& e) {
OpmLog::error(OpmInputError::formatException(handlerContext.keyword.location(), e));
throw;
}
return true;
} else {
+4 -7
View File
@@ -923,8 +923,7 @@ bool parseState( ParserState& parserState, const Parser& parser ) {
parserState.deck.getDefaultUnitSystem()));
} catch (const OpmInputError& opm_error) {
throw;
}
catch (const std::exception& std_error) {
} catch (const std::exception& e) {
/*
This catch-all of parsing errors is to be able to write a good
error message; the parser is quite confused at this state and
@@ -935,11 +934,9 @@ bool parseState( ParserState& parserState, const Parser& parser ) {
same exception without updating the what() message of the
exception.
*/
const auto& location = rawKeyword->location();
std::string msg_fmt = fmt::format("Problem parsing keyword {{keyword}}\n"
"In {{file}} line {{line}}.\n"
"Internal error message: {}" , std_error.what());
OpmLog::error( OpmInputError::format(msg_fmt, location) );
OpmLog::error(OpmInputError::formatException(rawKeyword->location(), e));
throw;
}
} else {
+2 -11
View File
@@ -840,21 +840,12 @@ Deck parse(bool throw_opm, bool& opm_caught, bool& std_caught) {
BOOST_AUTO_TEST_CASE(OPM_ERROR) {
KeywordLocation location("kw", "file", 100);
OpmInputError error1("Error", location);
OpmInputError error2("{2}:{1}:{0}", location);
OpmInputError error3("{}:{}:{}", location);
OpmInputError error4("{keyword}:{line}:{keyword}", location);
/*
Use of named placeholders like {keyword} and {file} is probabably the
best, but also numbered placeholders like {0} and {1} and also pure
positional {} works.
*/
OpmInputError error5("{keyword}:{line}:{file}: {}", location, "error");
BOOST_CHECK_EQUAL(error1.what(), "Error");
BOOST_CHECK_EQUAL(error2.what(), "100:file:kw");
BOOST_CHECK_EQUAL(error3.what(), "kw:file:100");
BOOST_CHECK_EQUAL(error4.what(), "kw:100:kw");
BOOST_CHECK_EQUAL(error5.what(), "kw:100:file: error");
/*
This test is meant to emulate the typical parsing process, the blocks here
+94
View File
@@ -0,0 +1,94 @@
/*
Copyright 2020 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#define BOOST_TEST_MODULE OpmInputError_format
#include <boost/test/unit_test.hpp>
#include <exception>
#include <opm/common/utility/OpmInputError.hpp>
const Opm::KeywordLocation location { "MXUNSUPP", "FILENAME.DAT", 42 } ;
const std::string error_string { "Error encountered" } ;
BOOST_AUTO_TEST_CASE(simple) {
const std::string expected { "MXUNSUPP@FILENAME.DAT:42" } ;
const std::string format_string { "{keyword}@{file}:{line}" } ;
const std::string formatted { Opm::OpmInputError::format(format_string, location) } ;
BOOST_CHECK_EQUAL(formatted, expected);
}
BOOST_AUTO_TEST_CASE(positional) {
const std::string expected { "MXUNSUPP@FILENAME.DAT:42: Error encountered" } ;
const std::string format_string { "{keyword}@{file}:{line}: {}" } ;
const std::string formatted { Opm::OpmInputError::format(format_string, location, error_string) } ;
BOOST_CHECK_EQUAL(formatted, expected);
}
BOOST_AUTO_TEST_CASE(exception) {
const std::string expected { R"(Problem parsing keyword MXUNSUPP
In FILENAME.DAT line 42.
Internal error message: Runtime Error)" };
const std::string formatted { Opm::OpmInputError::formatException(location, std::runtime_error("Runtime Error")) } ;
BOOST_CHECK_EQUAL(formatted, expected);
}
BOOST_AUTO_TEST_CASE(exception_reason) {
const std::string expected { R"(Problem parsing keyword MXUNSUPP
In FILENAME.DAT line 42.
Reason: Runtime Error)" };
const std::string formatted { Opm::OpmInputError::formatException(location, std::runtime_error("Runtime Error"), "Reason") } ;
BOOST_CHECK_EQUAL(formatted, expected);
}
BOOST_AUTO_TEST_CASE(exception_init) {
const std::string expected { R"(Problem parsing keyword MXUNSUPP
In FILENAME.DAT line 42.
Reason: Runtime Error)" };
const std::string formatted { Opm::OpmInputError(location, std::runtime_error("Runtime Error"), "Reason").what() } ;
BOOST_CHECK_EQUAL(formatted, expected);
}
BOOST_AUTO_TEST_CASE(exception_nest) {
const std::string expected { R"(Problem parsing keyword MXUNSUPP
In FILENAME.DAT line 42.
Internal error message: Runtime Error)" };
try {
try {
throw std::runtime_error("Runtime Error");
} catch (const std::exception& e) {
std::throw_with_nested(Opm::OpmInputError(location, e));
}
} catch (const Opm::OpmInputError& opm_error) {
BOOST_CHECK_EQUAL(opm_error.what(), expected);
}
}