diff --git a/src/error.cpp b/src/error.cpp index 0cbfa4c4a1..a67a9e5865 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -213,6 +213,30 @@ void Error::one(const std::string &file, int line, const std::string &str) #endif } +/* ---------------------------------------------------------------------- + forward vararg version to single string version +------------------------------------------------------------------------- */ + +void Error::_all(const std::string &file, int line, fmt::string_view format, + fmt::format_args args) +{ + try { + all(file,line,fmt::vformat(format, args)); + } catch (fmt::format_error &e) { + all(file,line,e.what()); + } +} + +void Error::_one(const std::string &file, int line, fmt::string_view format, + fmt::format_args args) +{ + try { + one(file,line,fmt::vformat(format, args)); + } catch (fmt::format_error &e) { + one(file,line,e.what()); + } +} + /* ---------------------------------------------------------------------- called by one proc in world only write to screen if non-nullptr on this proc since could be file diff --git a/src/error.h b/src/error.h index dedebc4148..8b71974df5 100644 --- a/src/error.h +++ b/src/error.h @@ -32,6 +32,17 @@ class Error : protected Pointers { [[ noreturn ]] void all(const std::string &, int, const std::string &); [[ noreturn ]] void one(const std::string &, int, const std::string &); + template + [[ noreturn ]] void all(const std::string &file, int line, const S &format, + Args&&... args) { + _all(file, line, format, fmt::make_args_checked(format, args...)); + } + template + [[ noreturn ]] void one(const std::string &file, int line, const S &format, + Args&&... args) { + _one(file, line, format, fmt::make_args_checked(format, args...)); + } + void warning(const std::string &, int, const std::string &, int = 1); void message(const std::string &, int, const std::string &, int = 1); [[ noreturn ]] void done(int = 0); // 1 would be fully backwards compatible @@ -44,6 +55,12 @@ class Error : protected Pointers { private: std::string last_error_message; ErrorType last_error_type; + + // internal versions that accept explicit fmtlib arguments + [[ noreturn ]] void _all(const std::string &, int, fmt::string_view, + fmt::format_args args); + [[ noreturn ]] void _one(const std::string &, int, fmt::string_view, + fmt::format_args args); #endif }; diff --git a/unittest/formats/test_file_operations.cpp b/unittest/formats/test_file_operations.cpp index 392ca04656..414c2dba21 100644 --- a/unittest/formats/test_file_operations.cpp +++ b/unittest/formats/test_file_operations.cpp @@ -11,13 +11,14 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "../testing/core.h" +#include "error.h" #include "info.h" #include "input.h" #include "lammps.h" #include "utils.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "../testing/core.h" #include #include @@ -134,9 +135,9 @@ TEST_F(FileOperationsTest, logmesg) utils::logmesg(lmp, "one\n"); command("log test_logmesg.log"); utils::logmesg(lmp, "two\n"); - utils::logmesg(lmp, "three={}\n",3); + utils::logmesg(lmp, "three={}\n", 3); utils::logmesg(lmp, "four {}\n"); - utils::logmesg(lmp, "five\n",5); + utils::logmesg(lmp, "five\n", 5); command("log none"); std::string out = END_CAPTURE_OUTPUT(); memset(buf, 0, 64); @@ -148,6 +149,50 @@ TEST_F(FileOperationsTest, logmesg) remove("test_logmesg.log"); } +TEST_F(FileOperationsTest, error_message_warn) +{ + char buf[64]; + BEGIN_HIDE_OUTPUT(); + command("echo none"); + command("log test_error_warn.log"); + END_HIDE_OUTPUT(); + BEGIN_CAPTURE_OUTPUT(); + lmp->error->message("testme.cpp", 10, "message me"); + lmp->error->warning("testme.cpp", 100, "warn me"); + command("log none"); + std::string out = END_CAPTURE_OUTPUT(); + memset(buf, 0, 64); + FILE *fp = fopen("test_error_warn.log", "r"); + fread(buf, 1, 64, fp); + fclose(fp); + auto msg = StrEq("message me (testme.cpp:10)\n" + "WARNING: warn me (testme.cpp:100)\n"); + ASSERT_THAT(out, msg); + ASSERT_THAT(buf, msg); + remove("test_error_warn.log"); +} + +TEST_F(FileOperationsTest, error_all_one) +{ + char buf[64]; + BEGIN_HIDE_OUTPUT(); + command("echo none"); + command("log none"); + END_HIDE_OUTPUT(); + TEST_FAILURE(".*ERROR: exit \\(testme.cpp:10\\).*", + lmp->error->all("testme.cpp", 10, "exit");); + TEST_FAILURE(".*ERROR: exit too \\(testme.cpp:10\\).*", + lmp->error->all("testme.cpp", 10, "exit {}", "too");); + TEST_FAILURE(".*ERROR: argument not found \\(testme.cpp:10\\).*", + lmp->error->all("testme.cpp", 10, "exit {} {}", "too");); + TEST_FAILURE(".*ERROR on proc 0: exit \\(testme.cpp:10\\).*", + lmp->error->one("testme.cpp", 10, "exit");); + TEST_FAILURE(".*ERROR on proc 0: exit too \\(testme.cpp:10\\).*", + lmp->error->one("testme.cpp", 10, "exit {}", "too");); + TEST_FAILURE(".*ERROR on proc 0: argument not found \\(testme.cpp:10\\).*", + lmp->error->one("testme.cpp", 10, "exit {} {}", "too");); +} + int main(int argc, char **argv) { MPI_Init(&argc, &argv);