mpd/test/util/TestException.cxx
Max Kellermann 7b938b4d14 util/Exception: sanitize message strings
This should prevent leaking unsanitized strings from libraries.
2024-06-25 20:29:07 +02:00

224 lines
3.9 KiB
C++

// SPDX-License-Identifier: BSD-2-Clause
// Copyright CM4all GmbH
// author: Max Kellermann <mk@cm4all.com>
#include "util/Exception.hxx"
#include <gtest/gtest.h>
using std::string_view_literals::operator""sv;
TEST(ExceptionTest, RuntimeError)
{
ASSERT_EQ(GetFullMessage(std::make_exception_ptr(std::runtime_error("Foo"))), "Foo");
}
TEST(ExceptionTest, DerivedError)
{
class DerivedError : public std::runtime_error {
public:
explicit DerivedError(const char *_msg)
:std::runtime_error(_msg) {}
};
ASSERT_EQ(GetFullMessage(std::make_exception_ptr(DerivedError("Foo"))), "Foo");
}
TEST(ExceptionTest, GetFullMessageSanitize)
{
try {
try {
throw " ABC \n DEF ";
} catch (...) {
std::throw_with_nested(std::runtime_error{"foo\r\n\tbar"});
}
FAIL();
} catch (...) {
ASSERT_EQ(GetFullMessage(std::current_exception()),
"foo bar; ABC DEF"sv);
}
}
TEST(ExceptionTest, FindNestedDirect)
{
struct Foo {};
struct Bar {};
struct Derived : Foo {};
try {
throw Foo{};
} catch (...) {
EXPECT_NE(FindNested<Foo>(std::current_exception()),
nullptr);
}
try {
throw Bar{};
} catch (...) {
EXPECT_EQ(FindNested<Foo>(std::current_exception()),
nullptr);
}
try {
throw Derived{};
} catch (...) {
EXPECT_NE(FindNested<Foo>(std::current_exception()),
nullptr);
}
}
TEST(ExceptionTest, FindNestedIndirect)
{
struct Foo {};
struct Bar {};
struct Derived : Foo {};
struct Outer {};
try {
throw Foo{};
} catch (...) {
try {
std::throw_with_nested(Outer{});
} catch (...) {
EXPECT_NE(FindNested<Foo>(std::current_exception()),
nullptr);
}
}
try {
throw Bar{};
} catch (...) {
try {
std::throw_with_nested(Outer{});
} catch (...) {
EXPECT_EQ(FindNested<Foo>(std::current_exception()),
nullptr);
}
}
try {
throw Derived{};
} catch (...) {
try {
std::throw_with_nested(Outer{});
} catch (...) {
EXPECT_NE(FindNested<Foo>(std::current_exception()),
nullptr);
}
}
}
template<typename T>
static bool
CheckFindRetrowNested(std::exception_ptr e) noexcept
{
try {
FindRetrowNested<T>(e);
} catch (const T &) {
return true;
}
return false;
}
TEST(ExceptionTest, FindRetrowNestedDirect)
{
struct Foo {};
struct Bar {};
struct Derived : Foo {};
try {
throw Foo{};
} catch (...) {
EXPECT_TRUE(CheckFindRetrowNested<Foo>(std::current_exception()));
}
try {
throw Bar{};
} catch (...) {
EXPECT_FALSE(CheckFindRetrowNested<Foo>(std::current_exception()));
}
try {
throw Derived{};
} catch (...) {
EXPECT_TRUE(CheckFindRetrowNested<Foo>(std::current_exception()));
}
}
TEST(ExceptionTest, FindRetrowNestedIndirect)
{
struct Foo {};
struct Bar {};
struct Derived : Foo {};
struct Outer {};
try {
throw Foo{};
} catch (...) {
try {
std::throw_with_nested(Outer{});
} catch (...) {
EXPECT_TRUE(CheckFindRetrowNested<Foo>(std::current_exception()));
}
}
try {
throw Bar{};
} catch (...) {
try {
std::throw_with_nested(Outer{});
} catch (...) {
EXPECT_FALSE(CheckFindRetrowNested<Foo>(std::current_exception()));
}
}
try {
throw Derived{};
} catch (...) {
try {
std::throw_with_nested(Outer{});
} catch (...) {
EXPECT_TRUE(CheckFindRetrowNested<Foo>(std::current_exception()));
}
}
}
TEST(ExceptionTest, FindRetrowNestedIndirectRuntimeError)
{
struct Foo {};
struct Bar {};
struct Derived : Foo {};
try {
throw Foo{};
} catch (...) {
try {
std::throw_with_nested(std::runtime_error("X"));
} catch (...) {
EXPECT_TRUE(CheckFindRetrowNested<Foo>(std::current_exception()));
}
}
try {
throw Bar{};
} catch (...) {
try {
std::throw_with_nested(std::runtime_error("X"));
} catch (...) {
EXPECT_FALSE(CheckFindRetrowNested<Foo>(std::current_exception()));
}
}
try {
throw Derived{};
} catch (...) {
try {
std::throw_with_nested(std::runtime_error("X"));
} catch (...) {
EXPECT_TRUE(CheckFindRetrowNested<Foo>(std::current_exception()));
}
}
}