From 487bec7fd86778af9d8207cb68075247a6a483d6 Mon Sep 17 00:00:00 2001 From: Sangwan Kwon Date: Wed, 6 Nov 2019 14:36:43 +0900 Subject: [PATCH] Add enum based exception handling Standard c++ throw can not provide information like function, file, line number. It makes hard to tracking where the exception occured. So, add macro(THROW) which can track informations. Syntax: - THROW(ErrCode::LogicError) << "Additional information about exception"; Signed-off-by: Sangwan Kwon --- src/vist/CMakeLists.txt | 1 + src/vist/common/CMakeLists.txt | 16 +++++++ src/vist/common/exception.h | 94 +++++++++++++++++++++++++++++++++++++ src/vist/common/tests/exception.cpp | 67 ++++++++++++++++++++++++++ 4 files changed, 178 insertions(+) create mode 100644 src/vist/common/CMakeLists.txt create mode 100644 src/vist/common/exception.h create mode 100644 src/vist/common/tests/exception.cpp diff --git a/src/vist/CMakeLists.txt b/src/vist/CMakeLists.txt index 8f71945..73f9be1 100644 --- a/src/vist/CMakeLists.txt +++ b/src/vist/CMakeLists.txt @@ -29,6 +29,7 @@ ADD_DEFINITIONS(-DDB_PATH="${DB_INSTALL_DIR}/.vist.db" -DSCRIPT_INSTALL_DIR="${SCRIPT_INSTALL_DIR}") ADD_SUBDIRECTORY(client) +ADD_SUBDIRECTORY(common) ADD_SUBDIRECTORY(notification) ADD_SUBDIRECTORY(policy) ADD_SUBDIRECTORY(service) diff --git a/src/vist/common/CMakeLists.txt b/src/vist/common/CMakeLists.txt new file mode 100644 index 0000000..04eeb46 --- /dev/null +++ b/src/vist/common/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License + +FILE(GLOB COMMON_TESTS "tests/*.cpp") +ADD_VIST_TEST(${COMMON_TESTS}) diff --git a/src/vist/common/exception.h b/src/vist/common/exception.h new file mode 100644 index 0000000..8236026 --- /dev/null +++ b/src/vist/common/exception.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file exception.h + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @brief Enum based exception handling + * @usage + * enum class ErrCode { + * LogicError = 1, + * RuntimeError + * }; + * + * try { + * THROW(ErrCode::LogicError) << "Additional information about exception"; + * } catch (const vist::Exception& e) { + * ErrCode ec = e.get(); + * std::string message = e.what(); + * } + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#ifndef __FILENAME__ +#define __FILENAME__ \ + ::strrchr(__FILE__, '/') ? ::strrchr(__FILE__, '/') + 1 : __FILE__ +#endif + +#define THROW(ec) \ + throw vist::Exception(ec,__FILENAME__,__FUNCTION__,__LINE__) + +namespace vist { + +template +class Exception final : public std::exception { +public: + static_assert(std::is_enum::value, "Error code must be enum type."); + + using Self = Exception; + + Exception(ErrCode ec, const char *file, + const char *function, unsigned int line) noexcept : ec(ec) + { + std::stringstream ss; + ss << "[" << file << ":" << line << " " << function << "()]" + << "[" << boost::core::demangle(typeid(ec).name()) + << "(" << static_cast>(ec) << ")]"; + message = ss.str(); + } + + virtual const char* what() const noexcept override + { + return message.c_str(); + } + + inline ErrCode get() const noexcept + { + return ec; + } + + template + Self& operator<<(const T& arg) noexcept + { + message += (static_cast(std::stringstream() << arg)).str(); + return *this; + } + +private: + ErrCode ec; + std::string message; +}; + +} // namespace vist diff --git a/src/vist/common/tests/exception.cpp b/src/vist/common/tests/exception.cpp new file mode 100644 index 0000000..9dd4f5e --- /dev/null +++ b/src/vist/common/tests/exception.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +#include + +#include "../exception.h" + +enum class ErrCode { + InvalidArgument = 1, + DominError, + LogicError, + RuntimeError, + None +}; + +class ExceptionTests : public testing::Test {}; + +TEST_F(ExceptionTests, exception) +{ + bool raised = false; + ErrCode ec = ErrCode::None; + std::string msg; + + try { + THROW(ErrCode::InvalidArgument); + } catch (const vist::Exception& e) { + raised = true; + ec = e.get(); + msg = e.what(); + } + + EXPECT_TRUE(raised); + EXPECT_EQ(ec, ErrCode::InvalidArgument); + EXPECT_NE(std::string::npos, msg.find("ErrCode")); +} + +TEST_F(ExceptionTests, exception_msg) +{ + bool raised = false; + ErrCode ec = ErrCode::None; + std::string msg; + + try { + THROW(ErrCode::RuntimeError) << "Additional error message"; + } catch (const vist::Exception& e) { + raised = true; + ec = e.get(); + msg = e.what(); + } + + EXPECT_TRUE(!raised) << msg; + EXPECT_EQ(ec, ErrCode::RuntimeError); + EXPECT_NE(std::string::npos, msg.find("Additional")); +} -- 2.7.4