blob: 178e0b4d2817ef6a9b9b7cf0d945e311383be2e7 [file] [log] [blame] [edit]
// Copyright (c) 2025 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "quiche/common/quiche_status_utils.h"
#include <optional>
#include <type_traits>
#include "absl/status/status.h"
#include "absl/status/status_matchers.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "quiche/common/platform/api/quiche_logging.h"
#include "quiche/common/platform/api/quiche_test.h"
#include "quiche/common/test_tools/quiche_test_utils.h"
namespace quiche {
namespace {
TEST(QuicheAssignOrReturnTest, HandlesValue) {
auto TestLambda = []() -> absl::Status {
QUICHE_ASSIGN_OR_RETURN(int x, absl::StatusOr<int>(1));
EXPECT_EQ(x, 1);
return absl::OkStatus();
};
QUICHE_EXPECT_OK(TestLambda());
}
TEST(QuicheAssignOrReturnTest, HandlesValueAndDoesNotCallErrorLambda) {
auto TestLambda = []() -> absl::Status {
bool error_lambda_called = false;
QUICHE_ASSIGN_OR_RETURN(int x, absl::StatusOr<int>(1),
[&](const absl::Status& status) {
error_lambda_called = true;
return status;
});
EXPECT_EQ(x, 1);
EXPECT_FALSE(error_lambda_called);
return absl::OkStatus();
};
QUICHE_EXPECT_OK(TestLambda());
}
TEST(QuicheAssignOrReturnTest, HandlesError) {
auto TestLambda = []() -> absl::Status {
QUICHE_ASSIGN_OR_RETURN([[maybe_unused]] int x,
absl::StatusOr<int>(absl::InternalError("error")));
return absl::OkStatus();
};
EXPECT_THAT(TestLambda(),
absl_testing::StatusIs(absl::StatusCode::kInternal, "error"));
}
TEST(QuicheAssignOrReturnTest, HandlesErrorAndCallsErrorLambda) {
auto TestLambda = []() -> absl::Status {
std::optional<absl::Status> captured_status;
QUICHE_ASSIGN_OR_RETURN([[maybe_unused]] int x,
absl::StatusOr<int>(absl::InternalError("error")),
[&](const absl::Status& status) {
captured_status = status;
return status;
});
EXPECT_THAT(captured_status, testing::Optional(absl_testing::StatusIs(
absl::StatusCode::kInternal, "error")));
return absl::OkStatus();
};
EXPECT_THAT(TestLambda(),
absl_testing::StatusIs(absl::StatusCode::kInternal, "error"));
}
TEST(QuicheAssignOrReturnTest, HandlesErrorAndUsesReturnValueFromLambda) {
auto TestLambda = []() -> absl::Status {
QUICHE_ASSIGN_OR_RETURN([[maybe_unused]] int x,
absl::StatusOr<int>(absl::InternalError("error")),
[](const absl::Status& status) {
return absl::InvalidArgumentError(absl::StrCat(
"custom message: ", status.message()));
});
return absl::OkStatus();
};
EXPECT_THAT(TestLambda(),
absl_testing::StatusIs(absl::StatusCode::kInvalidArgument,
"custom message: error"));
}
TEST(QuicheAssignOrReturnTest, CanBeUsedMultipleTimesInOneFunction) {
auto TestLambda = []() -> absl::Status {
QUICHE_ASSIGN_OR_RETURN(int x, absl::StatusOr<int>(1));
EXPECT_EQ(x, 1);
QUICHE_ASSIGN_OR_RETURN(int y, absl::StatusOr<int>(2),
[](const absl::Status& status) { return status; });
EXPECT_EQ(y, 2);
QUICHE_ASSIGN_OR_RETURN([[maybe_unused]] int z,
absl::StatusOr<int>(absl::InternalError("error")));
EXPECT_TRUE(false) << "Unreachable";
return absl::OkStatus();
};
EXPECT_THAT(TestLambda(),
absl_testing::StatusIs(absl::StatusCode::kInternal, "error"));
}
// Demonstrates that we can use `QUICHE_LOG` in an on-error lambda.
TEST(QuicheAssignOrReturnTest, CanLogOnError) {
auto TestLambda = []() -> absl::Status {
QUICHE_ASSIGN_OR_RETURN([[maybe_unused]] int x,
absl::StatusOr<int>(absl::InternalError("error")),
[&](const absl::Status& status) {
QUICHE_LOG(INFO) << "Not OK! " << status;
return status;
});
return absl::OkStatus();
};
EXPECT_THAT(TestLambda(),
absl_testing::StatusIs(absl::StatusCode::kInternal, "error"));
}
struct FinickyNonCopyableInt {
FinickyNonCopyableInt(int x) : value(x) {}
FinickyNonCopyableInt(FinickyNonCopyableInt&&) = default;
FinickyNonCopyableInt(FinickyNonCopyableInt&) = delete;
int value;
};
static_assert(std::is_move_constructible_v<FinickyNonCopyableInt>);
static_assert(!std::is_copy_constructible_v<FinickyNonCopyableInt>);
TEST(QuicheAssignOrReturnTest, HandlesNonCopyableValue) {
auto TestLambda = []() -> absl::Status {
QUICHE_ASSIGN_OR_RETURN(
FinickyNonCopyableInt non_copyable,
absl::StatusOr<FinickyNonCopyableInt>(FinickyNonCopyableInt(42)));
EXPECT_EQ(non_copyable.value, 42);
return absl::OkStatus();
};
QUICHE_EXPECT_OK(TestLambda());
}
} // namespace
} // namespace quiche