mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
This enables writing expressions such as ABSL_ASSIGN_OR_RETURN((std::tuple<int, int> t1), ...) to allow commas in the type name on MSVC's traditional preprocessor, which does not support __VA_OPT__. PiperOrigin-RevId: 919705428 Change-Id: I6887b5607d422b8bc4586068ed42b4e9d384ee44
635 lines
20 KiB
C++
635 lines
20 KiB
C++
// 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/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<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
|