Merge pull request #1969 from wito/keyword-handler-try-catch
Exception Catch and Release
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user