diff --git a/CMakeLists.txt b/CMakeLists.txt index 7965947..b6f5414 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ include_directories(include) ament_export_include_directories(include) add_library(${PROJECT_NAME} + src/asserts.cpp src/find_library.cpp) target_include_directories(${PROJECT_NAME} PUBLIC @@ -46,6 +47,16 @@ if(BUILD_TESTING) ament_lint_auto_find_test_dependencies() + ament_add_gtest(test_asserts_ndebug test/test_asserts.cpp) + target_link_libraries(test_asserts_ndebug ${PROJECT_NAME}) + + if(TARGET test_asserts_ndebug) + target_compile_definitions(test_asserts_ndebug PUBLIC NDEBUG) + endif() + + ament_add_gtest(test_asserts_debug test/test_asserts.cpp) + target_link_libraries(test_asserts_debug ${PROJECT_NAME}) + ament_add_gtest(test_thread_safety_annotations test/test_thread_safety_annotations.cpp) ament_add_gtest(test_join test/test_join.cpp) diff --git a/include/rcpputils/asserts.hpp b/include/rcpputils/asserts.hpp new file mode 100644 index 0000000..d56f0ca --- /dev/null +++ b/include/rcpputils/asserts.hpp @@ -0,0 +1,106 @@ +// Copyright 2020 Amazon.com, Inc. or its affiliates. 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. + +#ifndef RCPPUTILS__ASSERTS_HPP_ +#define RCPPUTILS__ASSERTS_HPP_ + +#include +#include +#include + +#include "rcpputils/visibility_control.hpp" + +// Needed to disable compiler warning for exporting a class that extends a +// non-DLL-interface class. +// This should be fine since its extending an STL class. +#ifdef _WIN32 +# pragma warning(push) +# pragma warning(disable:4251) +# pragma warning(disable:4275) +#endif + +namespace rcpputils +{ + +class RCPPUTILS_PUBLIC AssertionException : public std::exception +{ + std::string msg_; + +public: + explicit AssertionException(const char * msg); + + virtual const char * what() const throw(); +}; + +class RCPPUTILS_PUBLIC IllegalStateException : public std::exception +{ + std::string msg_; + +public: + explicit IllegalStateException(const char * msg); + + virtual const char * what() const throw(); +}; + +/** + * Checks that an argument condition passes. + * + * \param condition + * \throw std::invalid_argument if the condition is not met. + */ +inline void require_true(bool condition) +{ + if (!condition) { + throw std::invalid_argument{"Invalid argument passed!"}; + } +} + +/** + * Checks that a state condition passes. + * + * \param condition + * \throw rcpputils::IllegalStateException if the condition is not met. + */ +inline void check_true(bool condition) +{ + if (!condition) { + throw rcpputils::IllegalStateException{"Check reported invalid state!"}; + } +} + +/** + * Asserts that a condition passes. + * + * This function behaves similar to assert, except that it throws instead of invoking abort(). + * \param condition + * \throw rcpputils::AssertionException if the macro NDEBUG is not set and the condition is not met. + */ +inline void assert_true(bool condition) +{ +// Same macro definition used by cassert +#ifndef NDEBUG + if (!condition) { + throw rcpputils::AssertionException{"Assertion failed!"}; + } +#else + (void) condition; +#endif +} +} // namespace rcpputils + +#ifdef _WIN32 +# pragma warning(pop) +#endif + +#endif // RCPPUTILS__ASSERTS_HPP_ diff --git a/src/asserts.cpp b/src/asserts.cpp new file mode 100644 index 0000000..c072ba1 --- /dev/null +++ b/src/asserts.cpp @@ -0,0 +1,38 @@ +// Copyright 2020 Amazon.com, Inc. or its affiliates. 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 "rcpputils/asserts.hpp" + +namespace rcpputils +{ +AssertionException::AssertionException(const char * msg) +{ + msg_ = msg; +} + +const char * AssertionException::what() const throw() +{ + return msg_.c_str(); +} + +IllegalStateException::IllegalStateException(const char * msg) +{ + msg_ = msg; +} + +const char * IllegalStateException::what() const throw() +{ + return msg_.c_str(); +} +} // namespace rcpputils diff --git a/test/test_asserts.cpp b/test/test_asserts.cpp new file mode 100644 index 0000000..2fc58d1 --- /dev/null +++ b/test/test_asserts.cpp @@ -0,0 +1,52 @@ +// Copyright 2020 Amazon.com, Inc. or its affiliates. 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 "gtest/gtest.h" + +#include "rcpputils/asserts.hpp" + +TEST(test_asserts, require_throws_if_condition_is_false) { + EXPECT_THROW(rcpputils::require_true(false), std::invalid_argument); +} + +TEST(test_asserts, require_does_not_throw_if_condition_is_true) { + EXPECT_NO_THROW(rcpputils::require_true(true)); +} + +TEST(test_asserts, check_throws_if_condition_is_false) { + EXPECT_THROW(rcpputils::check_true(false), rcpputils::IllegalStateException); +} + +TEST(test_asserts, check_does_not_throw_if_condition_is_true) { + EXPECT_NO_THROW(rcpputils::check_true(true)); +} + +#ifndef NDEBUG +TEST(test_asserts, ros_assert_throws_if_condition_is_false_and_ndebug_not_set) { + EXPECT_THROW(rcpputils::assert_true(false), rcpputils::AssertionException); +} + +TEST(test_asserts, ros_assert_does_not_throw_if_condition_is_true_and_ndebug_not_set) +{ + EXPECT_NO_THROW(rcpputils::assert_true(true)); +} + +#else +TEST(test_asserts, ros_assert_does_not_throw_if_ndebug_set) { + EXPECT_NO_THROW(rcpputils::assert_true(false)); + EXPECT_NO_THROW(rcpputils::assert_true(true)); +} +#endif