diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e6867ca..670ab992 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -603,6 +603,7 @@ if(WITH_TESTS) compat_test dwarfs_test entry_test + error_test file_access_test fragment_category_test incompressible_categorizer_test @@ -1020,6 +1021,7 @@ foreach(tgt dwarfs dwarfs_compression dwarfs_categorizer target_link_options(${tgt} PRIVATE -fprofile-instr-generate -fcoverage-mapping) endif() + target_compile_definitions(${tgt} PRIVATE DWARFS_COVERAGE_ENABLED=1) endif() endforeach() diff --git a/src/dwarfs/error.cpp b/src/dwarfs/error.cpp index b32df62d..26f0fe40 100644 --- a/src/dwarfs/error.cpp +++ b/src/dwarfs/error.cpp @@ -35,6 +35,18 @@ namespace dwarfs { +namespace { + +[[noreturn]] void do_terminate() { +#ifdef DWARFS_COVERAGE_ENABLED + std::exit(99); +#else + std::terminate(); +#endif +} + +} // namespace + system_error::system_error(char const* file, int line) noexcept : system_error(errno, file, line) {} @@ -68,14 +80,14 @@ void handle_nothrow(char const* expr, char const* file, int line) { std::cerr << "Expression `" << expr << "` threw `" << folly::exceptionStr(std::current_exception()) << "` in " << file << "(" << line << ")\n"; - ::abort(); + do_terminate(); } void assertion_failed(char const* expr, std::string const& msg, char const* file, int line) { std::cerr << "Assertion `" << expr << "` failed in " << file << "(" << line << "): " << msg << "\n"; - ::abort(); + do_terminate(); } } // namespace dwarfs diff --git a/test/error_test.cpp b/test/error_test.cpp new file mode 100644 index 00000000..b202a95c --- /dev/null +++ b/test/error_test.cpp @@ -0,0 +1,98 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/** + * \author Marcus Holland-Moritz (github@mhxnet.de) + * \copyright Copyright (c) Marcus Holland-Moritz + * + * This file is part of dwarfs. + * + * dwarfs 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. + * + * dwarfs 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 dwarfs. If not, see . + */ + +#include +#include + +#include +#include + +#include + +#include "dwarfs/error.h" + +using namespace dwarfs; + +namespace { + +int test_throw_runtime_error(bool throw_it) { + if (throw_it) { + DWARFS_THROW(runtime_error, "my test error"); + } + return __LINE__ - 2; +} + +int test_throw_system_error(bool throw_it) { + if (throw_it) { + errno = EPERM; + DWARFS_THROW(system_error, "my test system error"); + } + return __LINE__ - 2; +} + +} // namespace + +TEST(error_test, runtime_error) { + int expected_line = test_throw_runtime_error(false); + + try { + test_throw_runtime_error(true); + FAIL() << "expected runtime_error to be thrown"; + } catch (const runtime_error& e) { + EXPECT_EQ("my test error", std::string(e.what())); + EXPECT_EQ("error_test.cpp", + std::filesystem::path(e.file()).filename().string()); + EXPECT_EQ(expected_line, e.line()); + } catch (...) { + FAIL() << "expected runtime_error, got " + << folly::exceptionStr(std::current_exception()); + } +} + +TEST(error_test, system_error) { + int expected_line = test_throw_system_error(false); + + try { + test_throw_system_error(true); + FAIL() << "expected system_error to be thrown"; + } catch (const system_error& e) { + EXPECT_THAT(std::string(e.what()), + ::testing::MatchesRegex("my test system error: .*")); + EXPECT_EQ("error_test.cpp", + std::filesystem::path(e.file()).filename().string()); + EXPECT_EQ(EPERM, e.get_errno()); + EXPECT_EQ(expected_line, e.line()); + } catch (...) { + FAIL() << "expected system_error, got " + << folly::exceptionStr(std::current_exception()); + } +} + +TEST(error_test, dwarfs_check) { + DWARFS_CHECK(true, "my test error"); + EXPECT_DEATH(DWARFS_CHECK(false, "my test error"), "my test error"); +} + +TEST(error_test, dwarfs_nothrow) { + std::vector v{1, 2, 3}; + EXPECT_EQ(3, DWARFS_NOTHROW(v.at(2))); + EXPECT_DEATH(DWARFS_NOTHROW(v.at(3)), "Expression `v.at\\(3\\)` threw .*"); +}