| // Copyright 2026 The Abseil Authors | |
| // | |
| // 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 | |
| // | |
| // https://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 "absl/status/status_macros.h" | |
| #include <cstddef> | |
| #include <memory> | |
| #include <string> | |
| #include <tuple> | |
| #include <type_traits> | |
| #include <utility> | |
| #include <vector> | |
| #include "gmock/gmock.h" | |
| #include "gtest/gtest.h" | |
| #include "absl/status/status.h" | |
| #include "absl/status/status_builder.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/string_view.h" | |
| #include "absl/types/source_location.h" | |
| namespace { | |
| using ::testing::AllOf; | |
| using ::testing::Eq; | |
| using ::testing::HasSubstr; | |
| using absl::status_macro_internal::ReturnIfErrorAdaptor; | |
| using absl::status_macro_internal::StatusAdaptorForMacros; | |
| static_assert(!std::is_default_constructible_v<ReturnIfErrorAdaptor>); | |
| static_assert(!std::is_default_constructible_v<StatusAdaptorForMacros>); | |
| static_assert(!std::is_copy_constructible_v<ReturnIfErrorAdaptor>); | |
| static_assert(!std::is_copy_constructible_v<StatusAdaptorForMacros>); | |
| static_assert(!std::is_copy_assignable_v<ReturnIfErrorAdaptor>); | |
| static_assert(!std::is_copy_assignable_v<StatusAdaptorForMacros>); | |
| absl::Status ReturnOk() { return absl::OkStatus(); } | |
| absl::StatusBuilder ReturnOkBuilder() { | |
| return absl::StatusBuilder(absl::OkStatus()); | |
| } | |
| absl::Status ReturnError(absl::string_view msg) { | |
| return absl::Status(absl::StatusCode::kUnknown, msg); | |
| } | |
| absl::StatusBuilder ReturnErrorBuilder(absl::string_view msg) { | |
| return absl::StatusBuilder(absl::Status(absl::StatusCode::kUnknown, msg)); | |
| } | |
| absl::StatusOr<int> ReturnStatusOrValue(int v) { return v; } | |
| absl::StatusOr<int> ReturnStatusOrError(absl::string_view msg) { | |
| return absl::Status(absl::StatusCode::kUnknown, msg); | |
| } | |
| template <class... Args> | |
| absl::StatusOr<std::tuple<Args...>> ReturnStatusOrTupleValue(Args&&... v) { | |
| return std::tuple<Args...>(std::forward<Args>(v)...); | |
| } | |
| template <class... Args> | |
| absl::StatusOr<std::tuple<Args...>> ReturnStatusOrTupleError( | |
| absl::string_view msg) { | |
| return absl::Status(absl::StatusCode::kUnknown, msg); | |
| } | |
| absl::StatusOr<int&> ReturnStatusOrRef(int& v) { return v; } | |
| absl::StatusOr<std::unique_ptr<int>> ReturnStatusOrPtrValue(int v) { | |
| return std::make_unique<int>(v); | |
| } | |
| void CheckSourceLocation( | |
| const absl::Status& status, std::vector<int> lines = {}, | |
| absl::SourceLocation loc = absl::SourceLocation::current()) { | |
| ASSERT_EQ(status.GetSourceLocations().size(), lines.size()) | |
| << "Size check failed at " << loc.line(); | |
| for (size_t i = 0; i < lines.size(); ++i) { | |
| EXPECT_EQ(absl::string_view(status.GetSourceLocations()[i].file_name()), | |
| absl::string_view(loc.file_name())) | |
| << "File name check failed at " << loc.line(); | |
| EXPECT_EQ(status.GetSourceLocations()[i].line(), lines[i]) | |
| << "Line check failed at " << loc.line(); | |
| } | |
| } | |
| TEST(AssignOrReturn, Works) { | |
| auto func = []() -> absl::Status { | |
| ABSL_ASSIGN_OR_RETURN(int value1, ReturnStatusOrValue(1)); | |
| EXPECT_EQ(1, value1); | |
| ABSL_ASSIGN_OR_RETURN(const int value2, ReturnStatusOrValue(2)); | |
| EXPECT_EQ(2, value2); | |
| ABSL_ASSIGN_OR_RETURN(const int& value3, ReturnStatusOrValue(3)); | |
| EXPECT_EQ(3, value3); | |
| ABSL_ASSIGN_OR_RETURN(int value4 [[maybe_unused]], | |
| ReturnStatusOrError("EXPECTED")); | |
| return ReturnError("ERROR"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| } | |
| TEST(AssignOrReturn, WorksWithReferences) { | |
| int value = 17; | |
| auto func = [&]() -> absl::Status { | |
| ABSL_ASSIGN_OR_RETURN(int& value1, ReturnStatusOrRef(value)); | |
| EXPECT_EQ(&value1, &value); | |
| ABSL_ASSIGN_OR_RETURN(const int& value2, ReturnStatusOrRef(value)); | |
| EXPECT_EQ(&value2, &value); | |
| ABSL_ASSIGN_OR_RETURN(int value3, ReturnStatusOrRef(value)); | |
| EXPECT_EQ(value3, value); | |
| value = 11; | |
| EXPECT_NE(value3, value); | |
| ABSL_ASSIGN_OR_RETURN(int value4 [[maybe_unused]], | |
| ReturnStatusOrError("EXPECTED")); | |
| return ReturnError("ERROR"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| } | |
| TEST(AssignOrReturn, WorksWithCommasInType) { | |
| auto func = []() -> absl::Status { | |
| ABSL_ASSIGN_OR_RETURN((std::tuple<int, int> t1), | |
| ReturnStatusOrTupleValue(1, 1)); | |
| EXPECT_EQ((std::tuple{1, 1}), t1); | |
| ABSL_ASSIGN_OR_RETURN((const std::tuple<int, std::tuple<int, int>, int> t2), | |
| ReturnStatusOrTupleValue(1, std::tuple{1, 1}, 1)); | |
| EXPECT_EQ((std::tuple{1, std::tuple{1, 1}, 1}), t2); | |
| ABSL_ASSIGN_OR_RETURN( | |
| (std::tuple<int, std::tuple<int, int>, int> t3), | |
| (ReturnStatusOrTupleError<int, std::tuple<int, int>, int>("EXPECTED"))); | |
| t3 = {}; // fix unused error | |
| return ReturnError("ERROR"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| } | |
| TEST(AssignOrReturn, WorksWithStructureBindings) { | |
| auto func = []() -> absl::Status { | |
| ABSL_ASSIGN_OR_RETURN( | |
| (const auto& [t1, t2, t3, t4, t5]), | |
| ReturnStatusOrTupleValue(std::tuple{1, 1}, 1, 2, 3, 4)); | |
| EXPECT_EQ((std::tuple{1, 1}), t1); | |
| EXPECT_EQ(1, t2); | |
| EXPECT_EQ(2, t3); | |
| EXPECT_EQ(3, t4); | |
| EXPECT_EQ(4, t5); | |
| ABSL_ASSIGN_OR_RETURN(int t6 [[maybe_unused]], | |
| ReturnStatusOrError("EXPECTED")); | |
| return ReturnError("ERROR"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| } | |
| TEST(AssignOrReturn, WorksWithParenthesesAndDereference) { | |
| auto func = []() -> absl::Status { | |
| int integer; | |
| int* pointer_to_integer = &integer; | |
| ABSL_ASSIGN_OR_RETURN((*pointer_to_integer), ReturnStatusOrValue(1)); | |
| EXPECT_EQ(1, integer); | |
| ABSL_ASSIGN_OR_RETURN(*pointer_to_integer, ReturnStatusOrValue(2)); | |
| EXPECT_EQ(2, integer); | |
| // Make the test where the order of dereference matters and treat the | |
| // parentheses. | |
| pointer_to_integer--; | |
| int** pointer_to_pointer_to_integer = &pointer_to_integer; | |
| ABSL_ASSIGN_OR_RETURN((*pointer_to_pointer_to_integer)[1], | |
| ReturnStatusOrValue(3)); | |
| EXPECT_EQ(3, integer); | |
| ABSL_ASSIGN_OR_RETURN(int t1 [[maybe_unused]], | |
| ReturnStatusOrError("EXPECTED")); | |
| return ReturnError("ERROR"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| } | |
| TEST(AssignOrReturn, WorksWithAppend) { | |
| auto fail_test_if_called = []() -> std::string { | |
| ADD_FAILURE(); | |
| return "FAILURE"; | |
| }; | |
| auto func = [&]() -> absl::Status { | |
| int value [[maybe_unused]]; | |
| ABSL_ASSIGN_OR_RETURN(value, ReturnStatusOrValue(1), | |
| _ << fail_test_if_called()); | |
| ABSL_ASSIGN_OR_RETURN(value, ReturnStatusOrError("EXPECTED A"), | |
| _ << "EXPECTED B"); | |
| return ReturnOk(); | |
| }; | |
| EXPECT_THAT(func().message(), | |
| AllOf(HasSubstr("EXPECTED A"), HasSubstr("EXPECTED B"))); | |
| } | |
| TEST(AssignOrReturn, WorksWithAdaptorFunc) { | |
| auto fail_test_if_called = [](absl::StatusBuilder builder) { | |
| ADD_FAILURE(); | |
| return builder; | |
| }; | |
| auto adaptor = [](absl::StatusBuilder builder) { | |
| return builder << "EXPECTED B"; | |
| }; | |
| auto func = [&]() -> absl::Status { | |
| int value [[maybe_unused]]; | |
| ABSL_ASSIGN_OR_RETURN(value, ReturnStatusOrValue(1), | |
| fail_test_if_called(_)); | |
| ABSL_ASSIGN_OR_RETURN(value, ReturnStatusOrError("EXPECTED A"), adaptor(_)); | |
| return ReturnOk(); | |
| }; | |
| EXPECT_THAT(func().message(), | |
| AllOf(HasSubstr("EXPECTED A"), HasSubstr("EXPECTED B"))); | |
| } | |
| TEST(AssignOrReturn, WorksWithThirdArgumentAndCommas) { | |
| auto fail_test_if_called = [](absl::StatusBuilder builder) { | |
| ADD_FAILURE(); | |
| return builder; | |
| }; | |
| auto adaptor = [](absl::StatusBuilder builder) { | |
| return builder << "EXPECTED B"; | |
| }; | |
| auto func = [&]() -> absl::Status { | |
| ABSL_ASSIGN_OR_RETURN((const auto& [t1, t2, t3]), | |
| ReturnStatusOrTupleValue(1, 2, 3), | |
| fail_test_if_called(_)); | |
| EXPECT_EQ(t1, 1); | |
| EXPECT_EQ(t2, 2); | |
| EXPECT_EQ(t3, 3); | |
| ABSL_ASSIGN_OR_RETURN( | |
| (const auto& [t4, t5, t6]), | |
| (ReturnStatusOrTupleError<int, int, int>("EXPECTED A")), adaptor(_)); | |
| // Silence errors about the unused values. | |
| static_cast<void>(t4); | |
| static_cast<void>(t5); | |
| static_cast<void>(t6); | |
| return ReturnOk(); | |
| }; | |
| EXPECT_THAT(func().message(), | |
| AllOf(HasSubstr("EXPECTED A"), HasSubstr("EXPECTED B"))); | |
| } | |
| TEST(AssignOrReturn, WorksWithAppendIncludingLocals) { | |
| auto func = [&](absl::string_view str) -> absl::Status { | |
| int value [[maybe_unused]]; | |
| ABSL_ASSIGN_OR_RETURN(value, ReturnStatusOrError("EXPECTED A"), _ << str); | |
| return ReturnOk(); | |
| }; | |
| EXPECT_THAT(func("EXPECTED B").message(), | |
| AllOf(HasSubstr("EXPECTED A"), HasSubstr("EXPECTED B"))); | |
| } | |
| TEST(AssignOrReturn, WorksForExistingVariable) { | |
| auto func = []() -> absl::Status { | |
| int value = 1; | |
| ABSL_ASSIGN_OR_RETURN(value, ReturnStatusOrValue(2)); | |
| EXPECT_EQ(2, value); | |
| ABSL_ASSIGN_OR_RETURN(value, ReturnStatusOrValue(3)); | |
| EXPECT_EQ(3, value); | |
| ABSL_ASSIGN_OR_RETURN(value, ReturnStatusOrError("EXPECTED")); | |
| return ReturnError("ERROR"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| } | |
| TEST(AssignOrReturn, UniquePtrWorks) { | |
| auto func = []() -> absl::Status { | |
| ABSL_ASSIGN_OR_RETURN(std::unique_ptr<int> ptr, ReturnStatusOrPtrValue(1)); | |
| EXPECT_EQ(*ptr, 1); | |
| return ReturnError("EXPECTED"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| } | |
| TEST(AssignOrReturn, UniquePtrWorksForExistingVariable) { | |
| auto func = []() -> absl::Status { | |
| std::unique_ptr<int> ptr; | |
| ABSL_ASSIGN_OR_RETURN(ptr, ReturnStatusOrPtrValue(1)); | |
| EXPECT_EQ(*ptr, 1); | |
| ABSL_ASSIGN_OR_RETURN(ptr, ReturnStatusOrPtrValue(2)); | |
| EXPECT_EQ(*ptr, 2); | |
| return ReturnError("EXPECTED"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| } | |
| TEST(AssignOrReturn, ChainSourceLocation) { | |
| auto func1 = []() -> absl::StatusOr<std::unique_ptr<int>> { | |
| std::unique_ptr<int> ptr; | |
| ABSL_ASSIGN_OR_RETURN(ptr, ReturnStatusOrPtrValue(1)); | |
| return ptr; | |
| }; | |
| auto func2 = []() -> absl::StatusOr<std::unique_ptr<int>> { | |
| return absl::Status(absl::StatusCode::kInternal, "msg"); | |
| }; | |
| int func2_line = __builtin_LINE() - 2; | |
| auto func3 = [=]() -> absl::StatusOr<std::unique_ptr<int>> { | |
| std::unique_ptr<int> ptr; | |
| ABSL_ASSIGN_OR_RETURN(ptr, func1()); | |
| ABSL_ASSIGN_OR_RETURN(ptr, func2()); | |
| return ptr; | |
| }; | |
| int func3_line = __builtin_LINE() - 3; | |
| auto func4 = [=]() -> absl::StatusOr<std::unique_ptr<int>> { | |
| std::unique_ptr<int> ptr; | |
| ABSL_ASSIGN_OR_RETURN(ptr, func3()); | |
| ABSL_ASSIGN_OR_RETURN(ptr, func2()); | |
| return ptr; | |
| }; | |
| int func4_line = __builtin_LINE() - 4; | |
| absl::StatusOr<std::unique_ptr<int>> result = func4(); | |
| EXPECT_EQ(absl::StatusCode::kInternal, result.status().code()); | |
| CheckSourceLocation(result.status(), {func2_line, func3_line, func4_line}); | |
| } | |
| TEST(AssignOrReturn, NotChainSourceLocationWithEmptyMsg) { | |
| auto func1 = []() -> absl::StatusOr<std::unique_ptr<int>> { | |
| std::unique_ptr<int> ptr; | |
| ABSL_ASSIGN_OR_RETURN(ptr, ReturnStatusOrPtrValue(1)); | |
| return ptr; | |
| }; | |
| auto func2 = []() -> absl::StatusOr<std::unique_ptr<int>> { | |
| return absl::Status(absl::StatusCode::kInternal, ""); | |
| }; | |
| auto func3 = [=]() -> absl::StatusOr<std::unique_ptr<int>> { | |
| std::unique_ptr<int> ptr; | |
| ABSL_ASSIGN_OR_RETURN(ptr, func1()); | |
| ABSL_ASSIGN_OR_RETURN(ptr, func2()); | |
| return ptr; | |
| }; | |
| auto func4 = [=]() -> absl::StatusOr<std::unique_ptr<int>> { | |
| std::unique_ptr<int> ptr; | |
| ABSL_ASSIGN_OR_RETURN(ptr, func3()); | |
| ABSL_ASSIGN_OR_RETURN(ptr, func2()); | |
| return ptr; | |
| }; | |
| absl::StatusOr<std::unique_ptr<int>> result = func4(); | |
| EXPECT_EQ(absl::StatusCode::kInternal, result.status().code()); | |
| CheckSourceLocation(result.status()); | |
| } | |
| TEST(AssignOrReturn, ChainSourceLocationWith3ArgStatusMacro) { | |
| auto func1 = []() -> absl::StatusOr<std::unique_ptr<int>> { | |
| std::unique_ptr<int> ptr; | |
| ABSL_ASSIGN_OR_RETURN(ptr, ReturnStatusOrPtrValue(1)); | |
| return ptr; | |
| }; | |
| auto func2 = []() -> absl::StatusOr<std::unique_ptr<int>> { | |
| return absl::Status(absl::StatusCode::kInternal, ""); | |
| }; | |
| auto func3 = [=]() -> absl::StatusOr<std::unique_ptr<int>> { | |
| std::unique_ptr<int> ptr; | |
| ABSL_ASSIGN_OR_RETURN(ptr, func1()); | |
| ABSL_ASSIGN_OR_RETURN(ptr, func2(), _ << "hmm"); | |
| return ptr; | |
| }; | |
| int func3_line = __builtin_LINE() - 3; | |
| auto func4 = [=]() -> absl::StatusOr<std::unique_ptr<int>> { | |
| std::unique_ptr<int> ptr; | |
| ABSL_ASSIGN_OR_RETURN(ptr, func3()); | |
| ABSL_ASSIGN_OR_RETURN(ptr, func2()); | |
| return ptr; | |
| }; | |
| int func4_line = __builtin_LINE() - 4; | |
| absl::StatusOr<std::unique_ptr<int>> result = func4(); | |
| EXPECT_EQ(absl::StatusCode::kInternal, result.status().code()); | |
| CheckSourceLocation(result.status(), {func3_line, func4_line}); | |
| } | |
| TEST(ReturnIfError, Works) { | |
| auto func = []() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(ReturnError("EXPECTED")); | |
| return ReturnError("ERROR"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| } | |
| TEST(ReturnIfError, WorksWithSourceLocation) { | |
| using StatusCode = absl::StatusCode; | |
| { | |
| auto func = []() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(absl::Status(StatusCode::kUnknown, "EXPECTED")); | |
| return ReturnError("ERROR"); | |
| }; | |
| int error_line = __builtin_LINE() - 3; | |
| int func_line = error_line; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| CheckSourceLocation(func(), {error_line, func_line}); | |
| } | |
| { | |
| auto func1 = []() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(absl::Status(StatusCode::kUnknown, "EXPECTED")); | |
| return ReturnError("ERROR"); | |
| }; | |
| int error_line = __builtin_LINE() - 3; | |
| int func_line = error_line; | |
| auto func3 = [=]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(func1()); | |
| return ReturnError("ERROR_Func3"); | |
| }; | |
| int func3_line = __builtin_LINE() - 3; | |
| auto func4 = [=]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(func3()); | |
| return ReturnError("ERROR_Func4"); | |
| }; | |
| int func4_line = __builtin_LINE() - 3; | |
| CheckSourceLocation(func4(), | |
| {error_line, func_line, func3_line, func4_line}); | |
| } | |
| { | |
| auto func1 = []() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(absl::Status(StatusCode::kUnknown, "")); | |
| return ReturnError("ERROR"); | |
| }; | |
| auto func3 = [=]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(func1()); | |
| return ReturnError("ERROR_Func3"); | |
| }; | |
| auto func4 = [=]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(func3()); | |
| return ReturnError("ERROR_Func4"); | |
| }; | |
| CheckSourceLocation(func4()); | |
| } | |
| } | |
| TEST(ReturnIfError, WorksWithSourceLocationOn2Arg) { | |
| { | |
| auto func = []() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(absl::Status(absl::StatusCode::kUnknown, "EXPECTED")) | |
| << "foo"; | |
| return ReturnError("ERROR"); | |
| }; | |
| int error_line = __builtin_LINE() - 4; | |
| int func_line = error_line; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED; foo")); | |
| CheckSourceLocation(func(), {error_line, func_line}); | |
| } | |
| { | |
| auto func1 = []() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(absl::Status(absl::StatusCode::kUnknown, "EXPECTED")) | |
| << "foo"; | |
| return ReturnError("ERROR"); | |
| }; | |
| int error_line = __builtin_LINE() - 4; | |
| int func_line = error_line; | |
| auto func3 = [=]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(func1()); | |
| return ReturnError("ERROR_Func3"); | |
| }; | |
| int func3_line = __builtin_LINE() - 3; | |
| auto func4 = [=]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(func3()); | |
| return ReturnError("ERROR_Func4"); | |
| }; | |
| int func4_line = __builtin_LINE() - 3; | |
| CheckSourceLocation(func4(), | |
| {error_line, func_line, func3_line, func4_line}); | |
| } | |
| { | |
| auto func1 = []() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(absl::Status(absl::StatusCode::kUnknown, "")); | |
| return ReturnError("ERROR"); | |
| }; | |
| auto func3 = [=]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(func1()) << "foo"; | |
| return ReturnError("ERROR_Func3"); | |
| }; | |
| int func3_line = __builtin_LINE() - 3; | |
| auto func4 = [=]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(func3()); | |
| return ReturnError("ERROR_Func4"); | |
| }; | |
| int func4_line = __builtin_LINE() - 3; | |
| EXPECT_THAT(func4().message(), Eq("foo")); | |
| CheckSourceLocation(func4(), {func3_line, func4_line}); | |
| } | |
| { | |
| auto func1 = []() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(ReturnOk()); | |
| ABSL_RETURN_IF_ERROR(absl::Status(absl::StatusCode::kUnknown, "")) << ""; | |
| return ReturnError("ERROR"); | |
| }; | |
| auto func3 = [=]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(func1()); | |
| return ReturnError("ERROR_Func3"); | |
| }; | |
| auto func4 = [=]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(func3()); | |
| return ReturnError("ERROR_Func4"); | |
| }; | |
| CheckSourceLocation(func4()); | |
| } | |
| } | |
| TEST(ReturnIfError, WorksWithBuilder) { | |
| auto func = []() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(ReturnOkBuilder()); | |
| ABSL_RETURN_IF_ERROR(ReturnOkBuilder()); | |
| ABSL_RETURN_IF_ERROR(ReturnErrorBuilder("EXPECTED")); | |
| return ReturnErrorBuilder("ERROR"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| // Test that ABSL_RETURN_IF_ERROR can also return the StatusBuilder directly. | |
| auto func2 = []() -> absl::StatusBuilder { | |
| ABSL_RETURN_IF_ERROR(ReturnOkBuilder()); | |
| ABSL_RETURN_IF_ERROR(ReturnOkBuilder()); | |
| ABSL_RETURN_IF_ERROR(ReturnErrorBuilder("EXPECTED")); | |
| return ReturnErrorBuilder("ERROR"); | |
| }; | |
| EXPECT_THAT(static_cast<absl::Status>(func2()).message(), Eq("EXPECTED")); | |
| } | |
| TEST(ReturnIfError, IfInputIsBuilderDoesNotEagerlyConvertToStatus) { | |
| auto func = []() -> absl::Status { | |
| auto builder = ReturnErrorBuilder("FIRST"); | |
| builder.SetPrepend(); | |
| // If this call decays the builder to Status first and then makes another | |
| // builder it will forget about the SetPrepend and the streaming will happen | |
| // in the wrong order. | |
| ABSL_RETURN_IF_ERROR(builder) << "SECOND "; | |
| return absl::OkStatus(); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("SECOND FIRST")); | |
| } | |
| TEST(ReturnIfError, WorksWithLambda) { | |
| auto func = []() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR([] { return ReturnOk(); }()); | |
| ABSL_RETURN_IF_ERROR([] { return ReturnError("EXPECTED"); }()); | |
| return ReturnError("ERROR"); | |
| }; | |
| EXPECT_THAT(func().message(), Eq("EXPECTED")); | |
| } | |
| TEST(ReturnIfError, WorksWithAppend) { | |
| auto fail_test_if_called = []() -> std::string { | |
| ADD_FAILURE(); | |
| return "FAILURE"; | |
| }; | |
| auto func = [&]() -> absl::Status { | |
| ABSL_RETURN_IF_ERROR(ReturnOk()) << fail_test_if_called(); | |
| ABSL_RETURN_IF_ERROR(ReturnError("EXPECTED A")) << "EXPECTED B"; | |
| return absl::OkStatus(); | |
| }; | |
| EXPECT_THAT(func().message(), | |
| AllOf(HasSubstr("EXPECTED A"), HasSubstr("EXPECTED B"))); | |
| } | |
| TEST(ReturnIfError, WorksWithVoidReturnAdaptor) { | |
| int code = 0; | |
| int phase = 0; | |
| auto adaptor = [&](absl::Status status) -> void { code = phase; }; | |
| auto func = [&]() -> void { | |
| phase = 1; | |
| ABSL_RETURN_IF_ERROR(ReturnOk()).With(adaptor); | |
| phase = 2; | |
| ABSL_RETURN_IF_ERROR(ReturnError("EXPECTED A")).With(adaptor); | |
| phase = 3; | |
| }; | |
| func(); | |
| EXPECT_EQ(phase, 2); | |
| EXPECT_EQ(code, 2); | |
| } | |
| } // namespace |