224 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			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()));
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |