From 50809970e0c1d39c57541cf50642b02be81a6373 Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Thu, 27 Mar 2025 18:19:55 -0400 Subject: [PATCH 01/10] Add Result and unit tests --- src/ystdlib/error_handling/CMakeLists.txt | 4 + src/ystdlib/error_handling/Result.hpp | 50 +++++++++++ .../error_handling/test/test_Result.cpp | 90 +++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 src/ystdlib/error_handling/Result.hpp create mode 100644 src/ystdlib/error_handling/test/test_Result.cpp diff --git a/src/ystdlib/error_handling/CMakeLists.txt b/src/ystdlib/error_handling/CMakeLists.txt index c5b7012..4af02d4 100644 --- a/src/ystdlib/error_handling/CMakeLists.txt +++ b/src/ystdlib/error_handling/CMakeLists.txt @@ -3,9 +3,13 @@ cpp_library( NAMESPACE ystdlib PUBLIC_HEADERS ErrorCode.hpp + Result.hpp + PUBLIC_LINK_LIBRARIES + outcome::hl TESTS_SOURCES test/constants.hpp test/test_ErrorCode.cpp + test/test_Result.cpp test/types.cpp test/types.hpp ) diff --git a/src/ystdlib/error_handling/Result.hpp b/src/ystdlib/error_handling/Result.hpp new file mode 100644 index 0000000..eb2ff7c --- /dev/null +++ b/src/ystdlib/error_handling/Result.hpp @@ -0,0 +1,50 @@ +#ifndef YSTDLIB_ERROR_HANDLING_RESULT_HPP +#define YSTDLIB_ERROR_HANDLING_RESULT_HPP + +#include + +#include +#include +#include + +namespace ystdlib::error_handling { +template +using Result = OUTCOME_V2_NAMESPACE::std_result; + +/** + * Default return value for ystdlib::error_handling::Result when function succeeds. + */ +[[nodiscard]] inline auto success() -> OUTCOME_V2_NAMESPACE::success_type { + return OUTCOME_V2_NAMESPACE::success(); +} + +// NOLINTBEGIN(bugprone-macro-parentheses, cppcoreguidelines-macro-usage) +/** + * This macro works the same way as Rust's `?` operator for error propagation. + */ +#define YSTDLIB_TRY(expr) \ + ({ \ + auto result{(expr)}; \ + if (result.has_error()) { \ + return result.error(); \ + } \ + using ReturnType = decltype(result.value()); \ + static_assert(std::is_move_constructible_v); \ + std::move(result.value()); \ + }) + +/** + * This macro works the same way as Rust's `?` operator for error propagation, without returning + * any value. + */ +#define YSTDLIB_ASSERT_NO_ERROR(expr) \ + ({ \ + if (auto const result{(expr)}; result.has_error()) { \ + return result.error(); \ + } \ + }) +// NOLINTEND(bugprone-macro-parentheses, cppcoreguidelines-macro-usage) +} // namespace ystdlib::error_handling + +#endif // YSTDLIB_ERROR_HANDLING_RESULT_HPP + diff --git a/src/ystdlib/error_handling/test/test_Result.cpp b/src/ystdlib/error_handling/test/test_Result.cpp new file mode 100644 index 0000000..c3025e2 --- /dev/null +++ b/src/ystdlib/error_handling/test/test_Result.cpp @@ -0,0 +1,90 @@ +#include +#include + +#include + +#include + +#include "types.hpp" + +using ystdlib::error_handling::Result; +using ystdlib::error_handling::success; +using ystdlib::error_handling::test::BinaryErrorCode; +using ystdlib::error_handling::test::BinaryErrorCodeEnum; + +namespace { +constexpr int cTestInt{123}; +constexpr auto cVoidFunc = [](bool is_error) -> Result { + if (is_error) { + return BinaryErrorCode{BinaryErrorCodeEnum::Failure}; + } + return success(); +}; +constexpr auto cIntFunc = [](bool is_error) -> Result { + if (is_error) { + return std::errc::bad_message; + } + return cTestInt; +}; +} // namespace + +namespace ystdlib::error_handling::test { +TEST_CASE("test_result_void", "[error_handling][Result]") { + auto const result_no_error{cVoidFunc(false)}; + REQUIRE_FALSE(result_no_error.has_error()); + REQUIRE(std::is_void_v); + + auto const result_has_error{cVoidFunc(true)}; + REQUIRE(result_has_error.has_error()); + REQUIRE(BinaryErrorCode{BinaryErrorCodeEnum::Failure} == result_has_error.error()); +} + +TEST_CASE("test_result_void_in_main", "[error_handling][Result]") { + auto main_func = [&](bool is_error) -> Result { + YSTDLIB_ASSERT_NO_ERROR(cVoidFunc(is_error)); + return success(); + }; + auto const main_no_error{main_func(false)}; + REQUIRE_FALSE(main_no_error.has_error()); + REQUIRE(std::is_void_v); + + auto const main_has_error{main_func(true)}; + REQUIRE(main_has_error.has_error()); + REQUIRE((BinaryErrorCode{BinaryErrorCodeEnum::Failure} == main_has_error.error())); +} + +TEST_CASE("test_result_int", "[error_handling][Result]") { + auto const result_no_error{cIntFunc(false)}; + REQUIRE_FALSE(result_no_error.has_error()); + REQUIRE((cTestInt == result_no_error.value())); + + auto const result_has_error{cIntFunc(true)}; + REQUIRE(result_has_error.has_error()); + REQUIRE(std::errc::bad_message == result_has_error.error()); +} + +TEST_CASE("test_result_int_in_main", "[error_handling][Result]") { + auto main_func = [&](bool is_error) -> Result { + YSTDLIB_ASSERT_NO_ERROR(cIntFunc(is_error)); + return success(); + }; + auto const main_no_error{main_func(false)}; + REQUIRE_FALSE(main_no_error.has_error()); + REQUIRE(std::is_void_v); + + auto const main_has_error{main_func(true)}; + REQUIRE(main_has_error.has_error()); + REQUIRE((std::errc::bad_message == main_has_error.error())); +} + +TEST_CASE("test_result_int_propagate", "[error_handling][Result]") { + auto main_func = [&](bool is_error) -> Result { return YSTDLIB_TRY(cIntFunc(is_error)); }; + auto const main_no_error{main_func(false)}; + REQUIRE_FALSE(main_no_error.has_error()); + REQUIRE((cTestInt == main_no_error.value())); + + auto const main_has_error{main_func(true)}; + REQUIRE(main_has_error.has_error()); + REQUIRE((std::errc::bad_message == main_has_error.error())); +} +} // namespace ystdlib::error_handling::test From db9fe2385649e1a8f25fab3d75a69756b81cb932 Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Wed, 2 Apr 2025 16:43:31 -0400 Subject: [PATCH 02/10] Rename macros and change underlying implementation to use OUTCOME_TRY* versions --- src/ystdlib/error_handling/Result.hpp | 27 ++++++------------- .../error_handling/test/test_Result.cpp | 6 ++--- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/ystdlib/error_handling/Result.hpp b/src/ystdlib/error_handling/Result.hpp index eb2ff7c..db427e8 100644 --- a/src/ystdlib/error_handling/Result.hpp +++ b/src/ystdlib/error_handling/Result.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace ystdlib::error_handling { template @@ -18,33 +19,21 @@ using Result = OUTCOME_V2_NAMESPACE::std_result; return OUTCOME_V2_NAMESPACE::success(); } -// NOLINTBEGIN(bugprone-macro-parentheses, cppcoreguidelines-macro-usage) /** * This macro works the same way as Rust's `?` operator for error propagation. */ -#define YSTDLIB_TRY(expr) \ - ({ \ - auto result{(expr)}; \ - if (result.has_error()) { \ - return result.error(); \ - } \ - using ReturnType = decltype(result.value()); \ - static_assert(std::is_move_constructible_v); \ - std::move(result.value()); \ - }) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define YSTDLIB_TRYX(expr) (OUTCOME_TRYX(expr)) /** * This macro works the same way as Rust's `?` operator for error propagation, without returning * any value. */ -#define YSTDLIB_ASSERT_NO_ERROR(expr) \ - ({ \ - if (auto const result{(expr)}; result.has_error()) { \ - return result.error(); \ - } \ - }) -// NOLINTEND(bugprone-macro-parentheses, cppcoreguidelines-macro-usage) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define YSTDLIB_TRYV(expr) \ + do { \ + OUTCOME_TRYV(expr); \ + } while (false) } // namespace ystdlib::error_handling #endif // YSTDLIB_ERROR_HANDLING_RESULT_HPP - diff --git a/src/ystdlib/error_handling/test/test_Result.cpp b/src/ystdlib/error_handling/test/test_Result.cpp index c3025e2..e3ce6fc 100644 --- a/src/ystdlib/error_handling/test/test_Result.cpp +++ b/src/ystdlib/error_handling/test/test_Result.cpp @@ -41,7 +41,7 @@ TEST_CASE("test_result_void", "[error_handling][Result]") { TEST_CASE("test_result_void_in_main", "[error_handling][Result]") { auto main_func = [&](bool is_error) -> Result { - YSTDLIB_ASSERT_NO_ERROR(cVoidFunc(is_error)); + YSTDLIB_TRYV(cVoidFunc(is_error)); return success(); }; auto const main_no_error{main_func(false)}; @@ -65,7 +65,7 @@ TEST_CASE("test_result_int", "[error_handling][Result]") { TEST_CASE("test_result_int_in_main", "[error_handling][Result]") { auto main_func = [&](bool is_error) -> Result { - YSTDLIB_ASSERT_NO_ERROR(cIntFunc(is_error)); + YSTDLIB_TRYV(cIntFunc(is_error)); return success(); }; auto const main_no_error{main_func(false)}; @@ -78,7 +78,7 @@ TEST_CASE("test_result_int_in_main", "[error_handling][Result]") { } TEST_CASE("test_result_int_propagate", "[error_handling][Result]") { - auto main_func = [&](bool is_error) -> Result { return YSTDLIB_TRY(cIntFunc(is_error)); }; + auto main_func = [&](bool is_error) -> Result { return YSTDLIB_TRYX(cIntFunc(is_error)); }; auto const main_no_error{main_func(false)}; REQUIRE_FALSE(main_no_error.has_error()); REQUIRE((cTestInt == main_no_error.value())); From 8f071529bd4c8371a4b865d19b58003873b066a3 Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Wed, 2 Apr 2025 17:21:10 -0400 Subject: [PATCH 03/10] Improve comments for result macros --- src/ystdlib/error_handling/Result.hpp | 33 +++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/ystdlib/error_handling/Result.hpp b/src/ystdlib/error_handling/Result.hpp index db427e8..da2d61f 100644 --- a/src/ystdlib/error_handling/Result.hpp +++ b/src/ystdlib/error_handling/Result.hpp @@ -9,27 +9,52 @@ #include namespace ystdlib::error_handling { +/** + * A convenience alias for Outcome's std_result. + * + * This alias standardizes error handling across the codebase by defaulting the error type to + * `std::error_code`, which interoperates with the ystdlib::error_handling::ErrorCode framework, + * making it easier to compose errors and propagate them across different modules and libraries. + * + * @tparam ReturnType The type returned upon success. + * @tparam ErrorType The type returned upon failure. + */ template using Result = OUTCOME_V2_NAMESPACE::std_result; /** * Default return value for ystdlib::error_handling::Result when function succeeds. + * + * Example: + * auto my_func() -> Result { + * // ... + * return success(); + * } */ [[nodiscard]] inline auto success() -> OUTCOME_V2_NAMESPACE::success_type { return OUTCOME_V2_NAMESPACE::success(); } /** - * This macro works the same way as Rust's `?` operator for error propagation. + * Propagates errors like Rust's `?` operator. + * + * Evaluates `expr`, and if it contains an error, returns the error from the calling function. + * Otherwise, extracts and returns the value. + * + * Only supported on AppleClang, Clang, and GCC due to reliance on Outcome's TRY macros. */ // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define YSTDLIB_TRYX(expr) (OUTCOME_TRYX(expr)) /** - * This macro works the same way as Rust's `?` operator for error propagation, without returning - * any value. + * Error propagation macro for expressions that return void on success. + * + * Evaluates `expr`, and if it contains an error, returns the error from the calling function. + * Intended for use with expressions that return `Result`. + * + * Only supported on AppleClang, Clang, and GCC due to reliance on Outcome's TRY macros. */ -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +// NOLINTNEXTLINE(cppcoreguidelines-avoid-do-while, cppcoreguidelines-macro-usage) #define YSTDLIB_TRYV(expr) \ do { \ OUTCOME_TRYV(expr); \ From 2ea95f2edb5e74278cf5e64bbb340ef49441ba83 Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Wed, 2 Apr 2025 17:22:15 -0400 Subject: [PATCH 04/10] Add ERROR_HANDLING to make macros more explicit --- src/ystdlib/error_handling/Result.hpp | 4 ++-- src/ystdlib/error_handling/test/test_Result.cpp | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ystdlib/error_handling/Result.hpp b/src/ystdlib/error_handling/Result.hpp index da2d61f..1483b01 100644 --- a/src/ystdlib/error_handling/Result.hpp +++ b/src/ystdlib/error_handling/Result.hpp @@ -44,7 +44,7 @@ using Result = OUTCOME_V2_NAMESPACE::std_result; * Only supported on AppleClang, Clang, and GCC due to reliance on Outcome's TRY macros. */ // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define YSTDLIB_TRYX(expr) (OUTCOME_TRYX(expr)) +#define YSTDLIB_ERROR_HANDLING_TRYX(expr) (OUTCOME_TRYX(expr)) /** * Error propagation macro for expressions that return void on success. @@ -55,7 +55,7 @@ using Result = OUTCOME_V2_NAMESPACE::std_result; * Only supported on AppleClang, Clang, and GCC due to reliance on Outcome's TRY macros. */ // NOLINTNEXTLINE(cppcoreguidelines-avoid-do-while, cppcoreguidelines-macro-usage) -#define YSTDLIB_TRYV(expr) \ +#define YSTDLIB_ERROR_HANDLING_TRYV(expr) \ do { \ OUTCOME_TRYV(expr); \ } while (false) diff --git a/src/ystdlib/error_handling/test/test_Result.cpp b/src/ystdlib/error_handling/test/test_Result.cpp index e3ce6fc..fbdfd2e 100644 --- a/src/ystdlib/error_handling/test/test_Result.cpp +++ b/src/ystdlib/error_handling/test/test_Result.cpp @@ -41,7 +41,7 @@ TEST_CASE("test_result_void", "[error_handling][Result]") { TEST_CASE("test_result_void_in_main", "[error_handling][Result]") { auto main_func = [&](bool is_error) -> Result { - YSTDLIB_TRYV(cVoidFunc(is_error)); + YSTDLIB_ERROR_HANDLING_TRYV(cVoidFunc(is_error)); return success(); }; auto const main_no_error{main_func(false)}; @@ -65,7 +65,7 @@ TEST_CASE("test_result_int", "[error_handling][Result]") { TEST_CASE("test_result_int_in_main", "[error_handling][Result]") { auto main_func = [&](bool is_error) -> Result { - YSTDLIB_TRYV(cIntFunc(is_error)); + YSTDLIB_ERROR_HANDLING_TRYV(cIntFunc(is_error)); return success(); }; auto const main_no_error{main_func(false)}; @@ -78,7 +78,9 @@ TEST_CASE("test_result_int_in_main", "[error_handling][Result]") { } TEST_CASE("test_result_int_propagate", "[error_handling][Result]") { - auto main_func = [&](bool is_error) -> Result { return YSTDLIB_TRYX(cIntFunc(is_error)); }; + auto main_func = [&](bool is_error) -> Result { + return YSTDLIB_ERROR_HANDLING_TRYX(cIntFunc(is_error)); + }; auto const main_no_error{main_func(false)}; REQUIRE_FALSE(main_no_error.has_error()); REQUIRE((cTestInt == main_no_error.value())); From 6361e257a92ad41b41b39fd230b16510a5d539dc Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Wed, 2 Apr 2025 17:27:48 -0400 Subject: [PATCH 05/10] Fix NOLINT comments --- src/ystdlib/error_handling/Result.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ystdlib/error_handling/Result.hpp b/src/ystdlib/error_handling/Result.hpp index 1483b01..a0f03b6 100644 --- a/src/ystdlib/error_handling/Result.hpp +++ b/src/ystdlib/error_handling/Result.hpp @@ -54,11 +54,12 @@ using Result = OUTCOME_V2_NAMESPACE::std_result; * * Only supported on AppleClang, Clang, and GCC due to reliance on Outcome's TRY macros. */ -// NOLINTNEXTLINE(cppcoreguidelines-avoid-do-while, cppcoreguidelines-macro-usage) +// NOLINTBEGIN(cppcoreguidelines-avoid-do-while, cppcoreguidelines-macro-usage) #define YSTDLIB_ERROR_HANDLING_TRYV(expr) \ do { \ OUTCOME_TRYV(expr); \ } while (false) +// NOLINTEND(cppcoreguidelines-avoid-do-while, cppcoreguidelines-macro-usage) } // namespace ystdlib::error_handling #endif // YSTDLIB_ERROR_HANDLING_RESULT_HPP From 8c210cac36bda035374a77d504a159fc548de977 Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Mon, 7 Apr 2025 19:19:16 -0400 Subject: [PATCH 06/10] Apply suggestions from code review Co-authored-by: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> --- src/ystdlib/error_handling/Result.hpp | 45 +++++++++++++++------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/ystdlib/error_handling/Result.hpp b/src/ystdlib/error_handling/Result.hpp index a0f03b6..d5a81e8 100644 --- a/src/ystdlib/error_handling/Result.hpp +++ b/src/ystdlib/error_handling/Result.hpp @@ -10,49 +10,54 @@ namespace ystdlib::error_handling { /** - * A convenience alias for Outcome's std_result. + * A Rust-style `Result` type for standardized, exception-free error handling. * * This alias standardizes error handling across the codebase by defaulting the error type to - * `std::error_code`, which interoperates with the ystdlib::error_handling::ErrorCode framework, - * making it easier to compose errors and propagate them across different modules and libraries. + * `std::error_code`, which interoperates with the `ystdlib::error_handling::ErrorCode`, making it + * easier to compose errors and propagate them across different modules and libraries. * - * @tparam ReturnType The type returned upon success. - * @tparam ErrorType The type returned upon failure. + * @tparam ReturnType The type returned on success. + * @tparam ErrorType The type used to represent errors. */ template using Result = OUTCOME_V2_NAMESPACE::std_result; /** - * Default return value for ystdlib::error_handling::Result when function succeeds. - * - * Example: - * auto my_func() -> Result { - * // ... - * return success(); - * } + * @return A value indicating successful completion of a function that returns a void result (i.e., + * `Result`). */ [[nodiscard]] inline auto success() -> OUTCOME_V2_NAMESPACE::success_type { return OUTCOME_V2_NAMESPACE::success(); } /** - * Propagates errors like Rust's `?` operator. + * A function-style macro that emulates Rust’s try (`?`) operator for error propagation. + * + * @param expr An expression that evaluates to a `Result` object. * - * Evaluates `expr`, and if it contains an error, returns the error from the calling function. - * Otherwise, extracts and returns the value. + * Behavior: + * - If `expr` represents an error (i.e., `expr.has_error()` returns true), the macro performs an + * early return from the enclosing function with the contained error. + * - Otherwise, it unwraps and yields the successful value as an rvalue reference (`expr.value()`). * - * Only supported on AppleClang, Clang, and GCC due to reliance on Outcome's TRY macros. + * NOTE: This macro is only supported on GCC and Clang due to reliance on compiler-specific + * extensions. */ +#ifdef OUTCOME_TRYX // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define YSTDLIB_ERROR_HANDLING_TRYX(expr) (OUTCOME_TRYX(expr)) +#endif /** - * Error propagation macro for expressions that return void on success. + * A function-style macro for propagating errors from expressions that evaluate to a void result + * (`Result`). * - * Evaluates `expr`, and if it contains an error, returns the error from the calling function. - * Intended for use with expressions that return `Result`. + * @param expr An expression that evaluates to a `Result` object. * - * Only supported on AppleClang, Clang, and GCC due to reliance on Outcome's TRY macros. + * Behavior: + * - If `expr` represents an error (i.e., `expr.has_error()` returns true), the macro performs an + * early return from the enclosing function with the contained error. + * - Otherwise, execution continues normally. */ // NOLINTBEGIN(cppcoreguidelines-avoid-do-while, cppcoreguidelines-macro-usage) #define YSTDLIB_ERROR_HANDLING_TRYV(expr) \ From cd779a9c03edc8cf8b0b3e2443cd58850242822d Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Mon, 7 Apr 2025 19:29:05 -0400 Subject: [PATCH 07/10] Simply macros --- src/ystdlib/error_handling/Result.hpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/ystdlib/error_handling/Result.hpp b/src/ystdlib/error_handling/Result.hpp index d5a81e8..4733d11 100644 --- a/src/ystdlib/error_handling/Result.hpp +++ b/src/ystdlib/error_handling/Result.hpp @@ -45,7 +45,7 @@ using Result = OUTCOME_V2_NAMESPACE::std_result; */ #ifdef OUTCOME_TRYX // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define YSTDLIB_ERROR_HANDLING_TRYX(expr) (OUTCOME_TRYX(expr)) +#define YSTDLIB_ERROR_HANDLING_TRYX(expr) OUTCOME_TRYX(expr) #endif /** @@ -59,12 +59,8 @@ using Result = OUTCOME_V2_NAMESPACE::std_result; * early return from the enclosing function with the contained error. * - Otherwise, execution continues normally. */ -// NOLINTBEGIN(cppcoreguidelines-avoid-do-while, cppcoreguidelines-macro-usage) -#define YSTDLIB_ERROR_HANDLING_TRYV(expr) \ - do { \ - OUTCOME_TRYV(expr); \ - } while (false) -// NOLINTEND(cppcoreguidelines-avoid-do-while, cppcoreguidelines-macro-usage) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define YSTDLIB_ERROR_HANDLING_TRYV(expr) OUTCOME_TRYV(expr) } // namespace ystdlib::error_handling #endif // YSTDLIB_ERROR_HANDLING_RESULT_HPP From 943154edf152c2d7c20d906fc9f6943ebdfb76ae Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Mon, 7 Apr 2025 20:36:50 -0400 Subject: [PATCH 08/10] lint fix --- src/ystdlib/error_handling/Result.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ystdlib/error_handling/Result.hpp b/src/ystdlib/error_handling/Result.hpp index 4733d11..7b0a48f 100644 --- a/src/ystdlib/error_handling/Result.hpp +++ b/src/ystdlib/error_handling/Result.hpp @@ -44,8 +44,8 @@ using Result = OUTCOME_V2_NAMESPACE::std_result; * extensions. */ #ifdef OUTCOME_TRYX -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define YSTDLIB_ERROR_HANDLING_TRYX(expr) OUTCOME_TRYX(expr) + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) + #define YSTDLIB_ERROR_HANDLING_TRYX(expr) OUTCOME_TRYX(expr) #endif /** From c1e11ddda356b980076d0358c5f6ba14e0492d13 Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Mon, 7 Apr 2025 20:48:31 -0400 Subject: [PATCH 09/10] Add unit test cases for unique ptr --- .../error_handling/test/test_Result.cpp | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/ystdlib/error_handling/test/test_Result.cpp b/src/ystdlib/error_handling/test/test_Result.cpp index fbdfd2e..65cd9d9 100644 --- a/src/ystdlib/error_handling/test/test_Result.cpp +++ b/src/ystdlib/error_handling/test/test_Result.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -9,6 +10,8 @@ using ystdlib::error_handling::Result; using ystdlib::error_handling::success; +using ystdlib::error_handling::test::AlwaysSuccessErrorCode; +using ystdlib::error_handling::test::AlwaysSuccessErrorCodeEnum; using ystdlib::error_handling::test::BinaryErrorCode; using ystdlib::error_handling::test::BinaryErrorCodeEnum; @@ -26,6 +29,12 @@ constexpr auto cIntFunc = [](bool is_error) -> Result { } return cTestInt; }; +constexpr auto cUniquePtrFunc = [](bool is_error) -> Result> { + if (is_error) { + return AlwaysSuccessErrorCode{AlwaysSuccessErrorCodeEnum::Success}; + } + return std::make_unique(cTestInt); +}; } // namespace namespace ystdlib::error_handling::test { @@ -89,4 +98,42 @@ TEST_CASE("test_result_int_propagate", "[error_handling][Result]") { REQUIRE(main_has_error.has_error()); REQUIRE((std::errc::bad_message == main_has_error.error())); } + +TEST_CASE("test_result_unique_ptr", "[error_handling][Result]") { + auto const result_no_error{cUniquePtrFunc(false)}; + REQUIRE_FALSE(result_no_error.has_error()); + REQUIRE((cTestInt == *(result_no_error.value()))); + + auto const result_has_error{cUniquePtrFunc(true)}; + REQUIRE(result_has_error.has_error()); + REQUIRE(AlwaysSuccessErrorCode{AlwaysSuccessErrorCodeEnum::Success} == result_has_error.error() + ); +} + +TEST_CASE("test_result_unique_ptr_in_main", "[error_handling][Result]") { + auto main_func = [&](bool is_error) -> Result { + YSTDLIB_ERROR_HANDLING_TRYV(cUniquePtrFunc(is_error)); + return success(); + }; + auto const main_no_error{main_func(false)}; + REQUIRE_FALSE(main_no_error.has_error()); + REQUIRE(std::is_void_v); + + auto const main_has_error{main_func(true)}; + REQUIRE(main_has_error.has_error()); + REQUIRE(AlwaysSuccessErrorCode{AlwaysSuccessErrorCodeEnum::Success} == main_has_error.error()); +} + +TEST_CASE("test_result_unique_ptr_propagate", "[error_handling][Result]") { + auto main_func = [&](bool is_error) -> Result> { + return YSTDLIB_ERROR_HANDLING_TRYX(cUniquePtrFunc(is_error)); + }; + auto const main_no_error{main_func(false)}; + REQUIRE_FALSE(main_no_error.has_error()); + REQUIRE((cTestInt == *(main_no_error.value()))); + + auto const main_has_error{main_func(true)}; + REQUIRE(main_has_error.has_error()); + REQUIRE(AlwaysSuccessErrorCode{AlwaysSuccessErrorCodeEnum::Success} == main_has_error.error()); +} } // namespace ystdlib::error_handling::test From b4aa46b9067a479d301c9afb01fff49685ea42cd Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Mon, 7 Apr 2025 21:34:36 -0400 Subject: [PATCH 10/10] Remove unnecessary parenthesis --- src/ystdlib/error_handling/test/test_Result.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ystdlib/error_handling/test/test_Result.cpp b/src/ystdlib/error_handling/test/test_Result.cpp index 65cd9d9..176b84b 100644 --- a/src/ystdlib/error_handling/test/test_Result.cpp +++ b/src/ystdlib/error_handling/test/test_Result.cpp @@ -59,13 +59,13 @@ TEST_CASE("test_result_void_in_main", "[error_handling][Result]") { auto const main_has_error{main_func(true)}; REQUIRE(main_has_error.has_error()); - REQUIRE((BinaryErrorCode{BinaryErrorCodeEnum::Failure} == main_has_error.error())); + REQUIRE(BinaryErrorCode{BinaryErrorCodeEnum::Failure} == main_has_error.error()); } TEST_CASE("test_result_int", "[error_handling][Result]") { auto const result_no_error{cIntFunc(false)}; REQUIRE_FALSE(result_no_error.has_error()); - REQUIRE((cTestInt == result_no_error.value())); + REQUIRE(cTestInt == result_no_error.value()); auto const result_has_error{cIntFunc(true)}; REQUIRE(result_has_error.has_error()); @@ -83,7 +83,7 @@ TEST_CASE("test_result_int_in_main", "[error_handling][Result]") { auto const main_has_error{main_func(true)}; REQUIRE(main_has_error.has_error()); - REQUIRE((std::errc::bad_message == main_has_error.error())); + REQUIRE(std::errc::bad_message == main_has_error.error()); } TEST_CASE("test_result_int_propagate", "[error_handling][Result]") { @@ -92,17 +92,17 @@ TEST_CASE("test_result_int_propagate", "[error_handling][Result]") { }; auto const main_no_error{main_func(false)}; REQUIRE_FALSE(main_no_error.has_error()); - REQUIRE((cTestInt == main_no_error.value())); + REQUIRE(cTestInt == main_no_error.value()); auto const main_has_error{main_func(true)}; REQUIRE(main_has_error.has_error()); - REQUIRE((std::errc::bad_message == main_has_error.error())); + REQUIRE(std::errc::bad_message == main_has_error.error()); } TEST_CASE("test_result_unique_ptr", "[error_handling][Result]") { auto const result_no_error{cUniquePtrFunc(false)}; REQUIRE_FALSE(result_no_error.has_error()); - REQUIRE((cTestInt == *(result_no_error.value()))); + REQUIRE(cTestInt == *(result_no_error.value())); auto const result_has_error{cUniquePtrFunc(true)}; REQUIRE(result_has_error.has_error()); @@ -130,7 +130,7 @@ TEST_CASE("test_result_unique_ptr_propagate", "[error_handling][Result]") { }; auto const main_no_error{main_func(false)}; REQUIRE_FALSE(main_no_error.has_error()); - REQUIRE((cTestInt == *(main_no_error.value()))); + REQUIRE(cTestInt == *(main_no_error.value())); auto const main_has_error{main_func(true)}; REQUIRE(main_has_error.has_error());