// 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 #include #include #include #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/attributes.h" #include "absl/base/optimization.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); static_assert(!std::is_default_constructible_v); static_assert(!std::is_copy_constructible_v); static_assert(!std::is_copy_constructible_v); static_assert(!std::is_copy_assignable_v); static_assert(!std::is_copy_assignable_v); 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 ReturnStatusOrValue(int v) { return v; } absl::StatusOr ReturnStatusOrError(absl::string_view msg) { return absl::Status(absl::StatusCode::kUnknown, msg); } template absl::StatusOr> ReturnStatusOrTupleValue(Args&&... v) { return std::tuple(std::forward(v)...); } template absl::StatusOr> ReturnStatusOrTupleError( absl::string_view msg) { return absl::Status(absl::StatusCode::kUnknown, msg); } absl::StatusOr ReturnStatusOrRef(int& v) { return v; } absl::StatusOr> ReturnStatusOrPtrValue(int v) { return std::make_unique(v); } void CheckSourceLocation( const absl::Status& status, std::vector 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 t1), ReturnStatusOrTupleValue(1, 1)); EXPECT_EQ((std::tuple{1, 1}), t1); ABSL_ASSIGN_OR_RETURN((const std::tuple, 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> t3), (ReturnStatusOrTupleError, 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("EXPECTED A")), adaptor(_)); // Silence errors about the unused values. static_cast(t4); static_cast(t5); static_cast(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 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 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 ptr; ABSL_ASSIGN_OR_RETURN(ptr, ReturnStatusOrPtrValue(1)); return ptr; }; auto func2 = []() -> absl::StatusOr> { return absl::Status(absl::StatusCode::kInternal, "msg"); }; int func2_line = __builtin_LINE() - 2; auto func3 = [=]() -> absl::StatusOr> { std::unique_ptr 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 ptr; ABSL_ASSIGN_OR_RETURN(ptr, func3()); ABSL_ASSIGN_OR_RETURN(ptr, func2()); return ptr; }; int func4_line = __builtin_LINE() - 4; absl::StatusOr> 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 ptr; ABSL_ASSIGN_OR_RETURN(ptr, ReturnStatusOrPtrValue(1)); return ptr; }; auto func2 = []() -> absl::StatusOr> { return absl::Status(absl::StatusCode::kInternal, ""); }; auto func3 = [=]() -> absl::StatusOr> { std::unique_ptr ptr; ABSL_ASSIGN_OR_RETURN(ptr, func1()); ABSL_ASSIGN_OR_RETURN(ptr, func2()); return ptr; }; auto func4 = [=]() -> absl::StatusOr> { std::unique_ptr ptr; ABSL_ASSIGN_OR_RETURN(ptr, func3()); ABSL_ASSIGN_OR_RETURN(ptr, func2()); return ptr; }; absl::StatusOr> result = func4(); EXPECT_EQ(absl::StatusCode::kInternal, result.status().code()); CheckSourceLocation(result.status()); } TEST(AssignOrReturn, ChainSourceLocationWith3ArgStatusMacro) { auto func1 = []() -> absl::StatusOr> { std::unique_ptr ptr; ABSL_ASSIGN_OR_RETURN(ptr, ReturnStatusOrPtrValue(1)); return ptr; }; auto func2 = []() -> absl::StatusOr> { return absl::Status(absl::StatusCode::kInternal, ""); }; auto func3 = [=]() -> absl::StatusOr> { std::unique_ptr 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 ptr; ABSL_ASSIGN_OR_RETURN(ptr, func3()); ABSL_ASSIGN_OR_RETURN(ptr, func2()); return ptr; }; int func4_line = __builtin_LINE() - 4; absl::StatusOr> 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(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