fbstring what() const {
if (item_) {
- return exceptionStr(*item_.get());
+ return exceptionStr(*item_);
} else if (eptr_) {
return estr_;
} else {
}
}
+ fbstring class_name() const {
+ if (item_) {
+ return demangle(typeid(*item_));
+ } else if (eptr_) {
+ return ename_;
+ } else {
+ return fbstring();
+ }
+ }
+
template <class Ex>
bool is_compatible_with() const {
if (item_) {
- return dynamic_cast<const Ex*>(getCopied());
+ return dynamic_cast<const Ex*>(item_.get());
} else if (eptr_) {
try {
std::rethrow_exception(eptr_);
std::shared_ptr<std::exception> item_;
void (*throwfn_)(std::exception*);
// Fallback case: store the library wrapper, which is less efficient
- // but gets the job done. Also store the the what() string, so we
- // can at least get it back out without having to rethrow.
+ // but gets the job done. Also store exceptionPtr() the name of the
+ // exception type, so we can at least get those back out without
+ // having to rethrow.
std::exception_ptr eptr_;
std::string estr_;
+ std::string ename_;
template <class T, class... Args>
friend exception_wrapper make_exception_wrapper(Args&&... args);
template <class Ex, class F, class T>
static bool with_exception1(F f, T* that) {
if (that->item_) {
- if (auto ex = dynamic_cast<Ex*>(that->getCopied())) {
+ if (auto ex = dynamic_cast<Ex*>(that->item_.get())) {
f(*ex);
return true;
}
try_and_catch() : Base() {}
template <typename Ex>
- typename std::enable_if<std::is_base_of<std::exception, Ex>::value>::type
- assign_eptr(Ex& e) {
- this->eptr_ = std::current_exception();
- this->estr_ = exceptionStr(e).toStdString();
- }
-
- template <typename Ex>
- typename std::enable_if<!std::is_base_of<std::exception, Ex>::value>::type
- assign_eptr(Ex& e) {
+ void assign_eptr(Ex& e) {
this->eptr_ = std::current_exception();
this->estr_ = exceptionStr(e).toStdString();
+ this->ename_ = demangle(typeid(e)).toStdString();
}
template <typename Ex>
}
}
-TEST(ExceptionWrapper, boolean) {
+TEST(ExceptionWrapper, members) {
auto ew = exception_wrapper();
EXPECT_FALSE(bool(ew));
+ EXPECT_EQ(ew.what(), "");
+ EXPECT_EQ(ew.class_name(), "");
ew = make_exception_wrapper<std::runtime_error>("payload");
EXPECT_TRUE(bool(ew));
+ EXPECT_EQ(ew.what(), "std::runtime_error: payload");
+ EXPECT_EQ(ew.class_name(), "std::runtime_error");
}
TEST(ExceptionWrapper, equals) {
EXPECT_TRUE(bool(ew));
EXPECT_TRUE(ew.getCopied());
EXPECT_EQ(ew.what(), "std::runtime_error: payload");
+ EXPECT_EQ(ew.class_name(), "std::runtime_error");
auto rep = ew.is_compatible_with<std::runtime_error>();
EXPECT_TRUE(rep);
throw std::exception();
});
EXPECT_TRUE(bool(ew3));
- EXPECT_NE(ew3.what(), expected);
+ EXPECT_EQ(ew3.what(), "std::exception: std::exception");
+ EXPECT_EQ(ew3.class_name(), "std::exception");
rep = ew3.is_compatible_with<std::runtime_error>();
EXPECT_FALSE(rep);
});
EXPECT_TRUE(bool(ew));
EXPECT_EQ(ew.what(), "IntException: int == 23");
+ EXPECT_EQ(ew.class_name(), "IntException");
ew.with_exception<IntException>([&](const IntException& ie) {
EXPECT_EQ(ie.getInt(), expected);
});
});
EXPECT_TRUE(bool(ew2));
EXPECT_EQ(ew2.what(), "IntException: int == 23");
+ EXPECT_EQ(ew2.class_name(), "IntException");
ew2.with_exception<AbstractIntException>([&](AbstractIntException& ie) {
EXPECT_EQ(ie.getInt(), expected);
EXPECT_EQ(typeid(ie), typeid(IntException));
EXPECT_TRUE(bool(ew));
EXPECT_FALSE(ew.is_compatible_with<std::exception>());
EXPECT_EQ(ew.what(), "int");
+ EXPECT_EQ(ew.class_name(), "int");
// non-std::exception types are supported, but the only way to
// access their value is to explicity rethrow and catch it.
try {