diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index 415455e5846db..012d67bfa12c8 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -512,6 +512,14 @@ def _com_google_absl(): name = "abseil_algorithm", actual = "@com_google_absl//absl/algorithm:algorithm", ) + native.bind( + name = "abseil_variant", + actual = "@com_google_absl//absl/types:variant", + ) + native.bind( + name = "abseil_status", + actual = "@com_google_absl//absl/status", + ) def _com_google_protobuf(): _repository_impl("rules_python") diff --git a/ci/run_clang_tidy.sh b/ci/run_clang_tidy.sh index 56745372e0c03..b394ccfddd352 100755 --- a/ci/run_clang_tidy.sh +++ b/ci/run_clang_tidy.sh @@ -51,8 +51,13 @@ function exclude_chromium_url() { grep -v source/common/chromium_url/ } +# Exclude files in third_party which are temporary forks from other OSS projects. +function exclude_third_party() { + grep -v third_party/ +} + function filter_excludes() { - exclude_testdata | exclude_chromium_url | exclude_win32_impl + exclude_testdata | exclude_chromium_url | exclude_win32_impl | exclude_third_party } diff --git a/source/common/common/BUILD b/source/common/common/BUILD index 633ff831feab4..af25042d18c50 100644 --- a/source/common/common/BUILD +++ b/source/common/common/BUILD @@ -429,3 +429,11 @@ envoy_cc_library( "//source/common/buffer:buffer_lib", ], ) + +envoy_cc_library( + name = "statusor_lib", + hdrs = ["statusor.h"], + deps = [ + "//third_party/statusor:statusor_lib", + ], +) diff --git a/source/common/common/statusor.h b/source/common/common/statusor.h new file mode 100644 index 0000000000000..bb7201d3c4b60 --- /dev/null +++ b/source/common/common/statusor.h @@ -0,0 +1,42 @@ +#pragma once + +#include "third_party/statusor/statusor.h" + +/** + * Facility for returning either a valid value or an error in a form of Envoy::Status. + * + * IMPORTANT: StatusOr default constructor must not be used as it does not fit into any + * Envoy's use cases. The error extracting functions in the common/common/status.h will + * RELEASE_ASSERT on default initialized StatusOr. + * + * To return an error StatusOr object an error creating function from common/common/status.h must be + * used. + * TODO(yanavlasov): add clang-tidy or lint check to enforce this. + * + * Usage example: + * + * Envoy::StatusOr Foo() { + * ... + * if (codec_error) { + * return CodecProtocolError("Invalid protocol"); + * } + * return 123456; + * } + * + * void Bar() { + * auto status_or = Foo(); + * if (status_or.ok()) { + * int result = status_or.value(); + * ... + * } else { + * ASSERT(IsCodecProtocolError(status_or.status())); + * ENVOY_LOG(debug, "Codec error encountered: {}", status_or.status().message()); + * } + * } + */ + +namespace Envoy { + +using absl::StatusOr; // NOLINT(misc-unused-using-decls) + +} // namespace Envoy diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 3deaff82c3052..b2b394ae7d518 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -412,3 +412,15 @@ envoy_cc_library( "@envoy_api//envoy/extensions/filters/network/http_connection_manager/v3:pkg_cc_proto", ], ) + +envoy_cc_library( + name = "status_lib", + srcs = ["status.cc"], + hdrs = ["status.h"], + external_deps = [ + "abseil_status", + ], + deps = [ + "//include/envoy/http:codes_interface", + ], +) diff --git a/source/common/http/status.cc b/source/common/http/status.cc new file mode 100644 index 0000000000000..96aa910bd9344 --- /dev/null +++ b/source/common/http/status.cc @@ -0,0 +1,123 @@ +#include "common/http/status.h" + +#include "absl/strings/str_cat.h" + +namespace Envoy { +namespace Http { + +namespace { + +constexpr absl::string_view EnvoyPayloadUrl = "Envoy"; + +absl::string_view statusCodeToString(StatusCode code) { + switch (code) { + case StatusCode::Ok: + return absl::OkStatus().ToString(); + case StatusCode::CodecProtocolError: + return "CodecProtocolError"; + case StatusCode::BufferFloodError: + return "BufferFloodError"; + case StatusCode::PrematureResponseError: + return "PrematureResponseError"; + case StatusCode::CodecClientError: + return "CodecClientError"; + } +} + +struct EnvoyStatusPayload { + EnvoyStatusPayload(StatusCode status_code) : status_code_(status_code) {} + const StatusCode status_code_; +}; + +struct PrematureResponsePayload : public EnvoyStatusPayload { + PrematureResponsePayload(Http::Code http_code) + : EnvoyStatusPayload(StatusCode::PrematureResponseError), http_code_(http_code) {} + const Http::Code http_code_; +}; + +template void storePayload(absl::Status& status, const T& payload) { + status.SetPayload( + EnvoyPayloadUrl, + absl::Cord(absl::string_view(reinterpret_cast(&payload), sizeof(payload)))); +} + +template const T* getPayload(const absl::Status& status) { + auto payload = status.GetPayload(EnvoyPayloadUrl); + ASSERT(payload.has_value(), "Must have payload"); + auto data = payload.value().Flatten(); + ASSERT(data.length() >= sizeof(T), "Invalid payload length"); + return reinterpret_cast(data.data()); +} + +} // namespace + +std::string toString(const Status& status) { + if (status.ok()) { + return status.ToString(); + } + std::string text; + auto status_code = getStatusCode(status); + if (status_code != StatusCode::PrematureResponseError) { + absl::StrAppend(&text, statusCodeToString(status_code), ": ", status.message()); + } else { + auto http_code = getPrematureResponseHttpCode(status); + absl::StrAppend(&text, "PrematureResponseError: HTTP code: ", http_code, ": ", + status.message()); + } + return text; +} + +Status codecProtocolError(absl::string_view message) { + absl::Status status(absl::StatusCode::kInternal, message); + storePayload(status, EnvoyStatusPayload(StatusCode::CodecProtocolError)); + return status; +} + +Status bufferFloodError(absl::string_view message) { + absl::Status status(absl::StatusCode::kInternal, message); + storePayload(status, EnvoyStatusPayload(StatusCode::BufferFloodError)); + return status; +} + +Status prematureResponseError(absl::string_view message, Http::Code http_code) { + absl::Status status(absl::StatusCode::kInternal, message); + storePayload(status, PrematureResponsePayload(http_code)); + return status; +} + +Status codecClientError(absl::string_view message) { + absl::Status status(absl::StatusCode::kInternal, message); + storePayload(status, EnvoyStatusPayload(StatusCode::CodecClientError)); + return status; +} + +// Methods for checking and extracting error information +StatusCode getStatusCode(const Status& status) { + return status.ok() ? StatusCode::Ok : getPayload(status)->status_code_; +} + +bool isCodecProtocolError(const Status& status) { + return getStatusCode(status) == StatusCode::CodecProtocolError; +} + +bool isBufferFloodError(const Status& status) { + return getStatusCode(status) == StatusCode::BufferFloodError; +} + +bool isPrematureResponseError(const Status& status) { + return getStatusCode(status) == StatusCode::PrematureResponseError; +} + +Http::Code getPrematureResponseHttpCode(const Status& status) { + const auto* payload = getPayload(status); + ASSERT(payload->status_code_ == StatusCode::PrematureResponseError, + "Must be PrematureResponseError"); + return payload->http_code_; +} + +bool isCodecClientError(const Status& status) { + return getStatusCode(status) == StatusCode::CodecClientError; +} + +} // namespace Http +} // namespace Envoy diff --git a/source/common/http/status.h b/source/common/http/status.h new file mode 100644 index 0000000000000..3efc54ee1a2f0 --- /dev/null +++ b/source/common/http/status.h @@ -0,0 +1,113 @@ +#pragma once + +#include +#include + +#include "envoy/http/codes.h" + +#include "absl/status/status.h" +#include "absl/strings/string_view.h" + +/** + * Facility for returning rich error information. + * This facility is to be used in place of exceptions, in components where + * exceptions safety is not guaranteed (i.e. codecs). + * + * Envoy::Status is an alias of absl::Status. + * IMPORTANT: `absl::Status` constructor `absl::Status::code()` and absl::Status::ToString()` + * methods must not be used as they will not return correct error information. Instead the error + * value creating and corresponding error checking functions defined below must be used. + * TODO(yanavlasov): add clang-tidy or lint check to enforce this. + * + * Usage example: + * + * Envoy::Status Foo() { + * ... + * if (codec_error) { + * return CodecProtocolError("Invalid protocol"); + * } + * return Envoy::OkStatus(); + * } + * + * void Bar() { + * auto status = Foo(); + * if (status.ok()) { + * ... + * } else { + * ASSERT(IsCodecProtocolError(status)); + * ENVOY_LOG(debug, "Codec error encountered: {}", status.message()); + * } + * } + */ + +namespace Envoy { +namespace Http { + +/** + * Status codes for representing classes of Envoy errors. + */ +enum class StatusCode : int { + Ok = 0, + + /** + * Indicates a non-recoverable protocol error that should result in connection termination. + */ + CodecProtocolError = 1, + + /** + * Indicates detection of outbound frame queue flood. + */ + BufferFloodError = 2, + + /** + * Indicates a response is received on a connection that did not send a request. In practice + * this can only happen on HTTP/1.1 connections. + */ + PrematureResponseError = 3, + + /** + * Indicates a client (local) side error which should not happen. + */ + CodecClientError = 4 +}; + +using Status = absl::Status; + +inline Status okStatus() { return absl::OkStatus(); } + +/** + * Returns the combination of the error code name, message and any additional error attributes. + */ +std::string toString(const Status& status); + +/** + * Functions for creating error values. The error code of the returned status object matches the + * name of the function. + */ +Status codecProtocolError(absl::string_view message); +Status bufferFloodError(absl::string_view message); +Status prematureResponseError(absl::string_view message, Http::Code http_code); +Status codecClientError(absl::string_view message); + +/** + * Returns Envoy::StatusCode of the given status object. + * If the status object does not contain valid Envoy::Status value the function will RELEASE_ASSERT. + */ +StatusCode getStatusCode(const Status& status); + +/** + * Returns true if the given status matches error code implied by the name of the function. + */ +ABSL_MUST_USE_RESULT bool isCodecProtocolError(const Status& status); +ABSL_MUST_USE_RESULT bool isBufferFloodError(const Status& status); +ABSL_MUST_USE_RESULT bool isPrematureResponseError(const Status& status); +ABSL_MUST_USE_RESULT bool isCodecClientError(const Status& status); + +/** + * Returns Http::Code value of the PrematureResponseError status. + * IsPrematureResponseError(status) must be true which is checked by RELEASE_ASSERT. + */ +Http::Code getPrematureResponseHttpCode(const Status& status); + +} // namespace Http +} // namespace Envoy diff --git a/test/common/common/BUILD b/test/common/common/BUILD index 8dbb40bca2f3b..288afab64682a 100644 --- a/test/common/common/BUILD +++ b/test/common/common/BUILD @@ -265,3 +265,12 @@ envoy_cc_test( "//source/common/common:version_lib", ], ) + +envoy_cc_test( + name = "statusor_test", + srcs = ["statusor_test.cc"], + deps = [ + "//source/common/common:statusor_lib", + "//source/common/http:status_lib", + ], +) diff --git a/test/common/common/statusor_test.cc b/test/common/common/statusor_test.cc new file mode 100644 index 0000000000000..2b42e3c6bf67a --- /dev/null +++ b/test/common/common/statusor_test.cc @@ -0,0 +1,19 @@ +#include "common/common/statusor.h" +#include "common/http/status.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { + +TEST(StatusOr, Initialization) { + StatusOr statusor( + Http::prematureResponseError("foobar", Http::Code::ProxyAuthenticationRequired)); + EXPECT_FALSE(statusor.ok()); + EXPECT_TRUE(Http::isPrematureResponseError(statusor.status())); + EXPECT_EQ("foobar", statusor.status().message()); + EXPECT_EQ(Http::Code::ProxyAuthenticationRequired, + Http::getPrematureResponseHttpCode(statusor.status())); +} + +} // namespace Envoy diff --git a/test/common/http/BUILD b/test/common/http/BUILD index dce641d6475c3..5382d74c085ca 100644 --- a/test/common/http/BUILD +++ b/test/common/http/BUILD @@ -384,3 +384,11 @@ envoy_cc_test( "//test/test_common:utility_lib", ], ) + +envoy_cc_test( + name = "status_test", + srcs = ["status_test.cc"], + deps = [ + "//source/common/http:status_lib", + ], +) diff --git a/test/common/http/status_test.cc b/test/common/http/status_test.cc new file mode 100644 index 0000000000000..4783b64dd0909 --- /dev/null +++ b/test/common/http/status_test.cc @@ -0,0 +1,71 @@ +#include "common/http/status.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Http { + +TEST(Status, Ok) { + auto status = okStatus(); + EXPECT_TRUE(status.ok()); + EXPECT_TRUE(status.message().empty()); + EXPECT_EQ("OK", toString(status)); + EXPECT_EQ(StatusCode::Ok, getStatusCode(status)); + EXPECT_FALSE(isCodecProtocolError(status)); + EXPECT_FALSE(isBufferFloodError(status)); + EXPECT_FALSE(isPrematureResponseError(status)); + EXPECT_FALSE(isCodecClientError(status)); +} + +TEST(Status, CodecProtocolError) { + auto status = codecProtocolError("foobar"); + EXPECT_FALSE(status.ok()); + EXPECT_EQ("foobar", status.message()); + EXPECT_EQ("CodecProtocolError: foobar", toString(status)); + EXPECT_EQ(StatusCode::CodecProtocolError, getStatusCode(status)); + EXPECT_TRUE(isCodecProtocolError(status)); + EXPECT_FALSE(isBufferFloodError(status)); + EXPECT_FALSE(isPrematureResponseError(status)); + EXPECT_FALSE(isCodecClientError(status)); +} + +TEST(Status, BufferFloodError) { + auto status = bufferFloodError("foobar"); + EXPECT_FALSE(status.ok()); + EXPECT_EQ("foobar", status.message()); + EXPECT_EQ("BufferFloodError: foobar", toString(status)); + EXPECT_EQ(StatusCode::BufferFloodError, getStatusCode(status)); + EXPECT_FALSE(isCodecProtocolError(status)); + EXPECT_TRUE(isBufferFloodError(status)); + EXPECT_FALSE(isPrematureResponseError(status)); + EXPECT_FALSE(isCodecClientError(status)); +} + +TEST(Status, PrematureResponseError) { + auto status = prematureResponseError("foobar", Http::Code::ProxyAuthenticationRequired); + EXPECT_FALSE(status.ok()); + EXPECT_EQ("foobar", status.message()); + EXPECT_EQ("PrematureResponseError: HTTP code: 407: foobar", toString(status)); + EXPECT_EQ(StatusCode::PrematureResponseError, getStatusCode(status)); + EXPECT_FALSE(isCodecProtocolError(status)); + EXPECT_FALSE(isBufferFloodError(status)); + EXPECT_TRUE(isPrematureResponseError(status)); + EXPECT_EQ(Http::Code::ProxyAuthenticationRequired, getPrematureResponseHttpCode(status)); + EXPECT_FALSE(isCodecClientError(status)); +} + +TEST(Status, CodecClientError) { + auto status = codecClientError("foobar"); + EXPECT_FALSE(status.ok()); + EXPECT_EQ("foobar", status.message()); + EXPECT_EQ("CodecClientError: foobar", toString(status)); + EXPECT_EQ(StatusCode::CodecClientError, getStatusCode(status)); + EXPECT_FALSE(isCodecProtocolError(status)); + EXPECT_FALSE(isBufferFloodError(status)); + EXPECT_FALSE(isPrematureResponseError(status)); + EXPECT_TRUE(isCodecClientError(status)); +} + +} // namespace Http +} // namespace Envoy diff --git a/third_party/statusor/BUILD b/third_party/statusor/BUILD new file mode 100644 index 0000000000000..fe17659a53787 --- /dev/null +++ b/third_party/statusor/BUILD @@ -0,0 +1,33 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_cc_test", + "envoy_package", +) + +envoy_package() + +envoy_cc_library( + name = "statusor_lib", + srcs = [ + "statusor.cc", + ], + hdrs = [ + "statusor.h", + "statusor_internals.h", + ], + external_deps = [ + "abseil_status", + ], + deps = ["//source/common/common:assert_lib"], +) + +envoy_cc_test( + name = "statusor_test", + srcs = ["statusor_test.cc"], + deps = [ + ":statusor_lib", + ], +) diff --git a/third_party/statusor/statusor.cc b/third_party/statusor/statusor.cc new file mode 100644 index 0000000000000..20105404217ad --- /dev/null +++ b/third_party/statusor/statusor.cc @@ -0,0 +1,43 @@ +/** + * IMPORTANT: this file is a fork of the soon to be open-source absl::StatusOr class. + * When the absl::StatusOr lands this file will be removed. + */ + +/* + * Copyright 2019 Google LLC + * + * 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 + * + * http://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 "third_party/statusor/statusor.h" + +#include + +#include "common/common/assert.h" + +namespace absl { + +namespace internal_statusor { + +void Helper::HandleInvalidStatusCtorArg(absl::Status* status) { + const char* kMessage = "An OK status is not a valid constructor argument to StatusOr"; + ASSERT(false, kMessage); + // In optimized builds, we will fall back to ::util::error::INTERNAL. + *status = absl::Status(absl::StatusCode::kInternal, kMessage); +} + +void Helper::Crash(const absl::Status&) { abort(); } + +} // namespace internal_statusor + +} // namespace Envoy diff --git a/third_party/statusor/statusor.h b/third_party/statusor/statusor.h new file mode 100644 index 0000000000000..d8a7d48329e0b --- /dev/null +++ b/third_party/statusor/statusor.h @@ -0,0 +1,352 @@ +/** + * IMPORTANT: this file is a fork of the soon to be open-source absl::StatusOr class. + * When the absl::StatusOr lands this file will be removed. + */ + +/* + * Copyright 2019 Google LLC + * + * 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 + * + * http://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. + */ + +// StatusOr is the union of a Status object and a T +// object. StatusOr models the concept of an object that is either a +// usable value, or an error Status explaining why such a value is +// not present. To this end, StatusOr does not allow its Status +// value to be OkStatus(). +// +// The primary use-case for StatusOr is as the return value of a +// function which may fail. +// +// Example usage of a StatusOr: +// +// StatusOr result = DoBigCalculationThatCouldFail(); +// if (result) { +// result->DoSomethingCool(); +// } else { +// GOOGLE_LOG(ERROR) << result.status(); +// } +// +// Example that is guaranteed crash if the result holds no value: +// +// StatusOr result = DoBigCalculationThatCouldFail(); +// const Foo& foo = result.value(); +// foo.DoSomethingCool(); +// +// Example usage of a StatusOr>: +// +// StatusOr> result = FooFactory::MakeNewFoo(arg); +// if (!result) { +// GOOGLE_LOG(ERROR) << result.status(); +// } else if (*result == nullptr) { +// GOOGLE_LOG(ERROR) << "Unexpected null pointer"; +// } else { +// (*result)->DoSomethingCool(); +// } +// +// Example factory implementation returning StatusOr: +// +// StatusOr FooFactory::MakeFoo(int arg) { +// if (arg <= 0) { +// return ::cel_base::Status(::cel_base::INVALID_ARGUMENT, +// "Arg must be positive"); +// } +// return Foo(arg); +// } +// + +#include +#include +#include +#include + +#include "third_party/statusor/statusor_internals.h" + +#include "absl/base/attributes.h" +#include "absl/base/macros.h" + +namespace absl { + +// Returned StatusOr objects may not be ignored. +template class ABSL_MUST_USE_RESULT StatusOr; + +template +class StatusOr : private internal_statusor::StatusOrData, + private internal_statusor::TraitsBase::value, + std::is_move_constructible::value> { + template friend class StatusOr; + + typedef internal_statusor::StatusOrData Base; + +public: + using element_type = T; + + // Constructs a new StatusOr with Status::UNKNOWN status. This is marked + // 'explicit' to try to catch cases like 'return {};', where people think + // StatusOr> will be initialized with an empty vector, + // instead of a Status::UNKNOWN status. + explicit StatusOr(); + + // StatusOr will be copy constructible/assignable if T is copy + // constructible. + StatusOr(const StatusOr&) = default; + StatusOr& operator=(const StatusOr&) = default; + + // StatusOr will be move constructible/assignable if T is move + // constructible. + StatusOr(StatusOr&&) = default; + StatusOr& operator=(StatusOr&&) = default; + + // Conversion copy/move constructor, T must be convertible from U. + // These should not participate in overload resolution if U + // is not convertible to T. + template StatusOr(const StatusOr& other); + template StatusOr(StatusOr&& other); + + // Conversion copy/move assignment operator, T must be convertible from U. + template StatusOr& operator=(const StatusOr& other); + template StatusOr& operator=(StatusOr&& other); + + // Constructs a new StatusOr with the given value. After calling this + // constructor, this->ok() will be true and the contained value may be + // retrieved with value(), operator*(), or operator->(). + // + // NOTE: Not explicit - we want to use StatusOr as a return type + // so it is convenient and sensible to be able to do 'return T()' + // when the return type is StatusOr. + // + // REQUIRES: T is copy constructible. + StatusOr(const T& value); + + // Constructs a new StatusOr with the given non-ok status. After calling this + // constructor, this->ok() will be false and calls to value() will + // CHECK-fail. + // + // NOTE: Not explicit - we want to use StatusOr as a return + // value, so it is convenient and sensible to be able to do 'return + // Status()' when the return type is StatusOr. + // + // REQUIRES: !status.ok(). This requirement is checked by ASSERT. + // In optimized builds, passing OkStatus() here will have the effect + // of passing INTERNAL as a fallback. + StatusOr(const absl::Status& status); + StatusOr& operator=(const absl::Status& status); + + // Similar to the `const T&` overload. + // + // REQUIRES: T is move constructible. + StatusOr(T&& value); + + // RValue versions of the operations declared above. + StatusOr(absl::Status&& status); + StatusOr& operator=(absl::Status&& status); + + // Returns this->ok() + explicit operator bool() const { return ok(); } + + // Returns this->status().ok() + ABSL_MUST_USE_RESULT bool ok() const { return this->status_.ok(); } + + // Returns a reference to our status. If this contains a T, then + // returns OkStatus(). + const absl::Status& status() const&; + absl::Status status() &&; + + // Returns a reference to our current value, or ASSERT-fails if !this->ok(). If + // you have already checked the status using this->ok() or operator bool(), + // then you probably want to use operator*() or operator->() to access the + // current value instead of value(). + // + // Note: for value types that are cheap to copy, prefer simple code: + // + // T value = status_or.value(); + // + // Otherwise, if the value type is expensive to copy, but can be left + // in the StatusOr, simply assign to a reference: + // + // T& value = status_or.value(); // or `const T&` + // + // Otherwise, if the value type supports an efficient move, it can be + // used as follows: + // + // T value = std::move(status_or).value(); + // + // The std::move on status_or instead of on the whole expression enables + // warnings about possible uses of the status_or object after the move. + + const T& value() const&; + T& value() &; + const T&& value() const&&; + T&& value() &&; + + // Returns a reference to the current value. + // + // REQUIRES: this->ok() == true, otherwise the behavior is undefined. + // + // Use this->ok() or `operator bool()` to verify that there is a current + // value. Alternatively, see value() for a similar API that guarantees + // ASSERT-failing if there is no current value. + const T& operator*() const&; + T& operator*() &; + const T&& operator*() const&&; + T&& operator*() &&; + + // Returns a pointer to the current value. + // + // REQUIRES: this->ok() == true, otherwise the behavior is undefined. + // + // Use this->ok() or `operator bool()` to verify that there is a current + // value. + const T* operator->() const; + T* operator->(); + + // Returns a copy of the current value if this->ok() == true. Otherwise + // returns a default value. + template T value_or(U&& default_value) const&; + template T value_or(U&& default_value) &&; + + // Ignores any errors. This method does nothing except potentially suppress + // complaints from any tools that are checking that errors are not dropped on + // the floor. + void IgnoreError() const; +}; + +//////////////////////////////////////////////////////////////////////////////// +// Implementation details for StatusOr + +template +StatusOr::StatusOr() : Base(absl::Status(absl::StatusCode::kUnknown, "")) {} + +template StatusOr::StatusOr(const T& value) : Base(value) {} + +template StatusOr::StatusOr(const absl::Status& status) : Base(status) {} + +template StatusOr& StatusOr::operator=(const absl::Status& status) { + this->Assign(status); + return *this; +} + +template StatusOr::StatusOr(T&& value) : Base(std::move(value)) {} + +template StatusOr::StatusOr(absl::Status&& status) : Base(std::move(status)) {} + +template StatusOr& StatusOr::operator=(absl::Status&& status) { + this->Assign(std::move(status)); + return *this; +} + +template +template +inline StatusOr::StatusOr(const StatusOr& other) + : Base(static_cast::Base&>(other)) {} + +template +template +inline StatusOr& StatusOr::operator=(const StatusOr& other) { + if (other.ok()) + this->Assign(other.value()); + else + this->Assign(other.status()); + return *this; +} + +template +template +inline StatusOr::StatusOr(StatusOr&& other) + : Base(static_cast::Base&&>(other)) {} + +template +template +inline StatusOr& StatusOr::operator=(StatusOr&& other) { + if (other.ok()) { + this->Assign(std::move(other).value()); + } else { + this->Assign(std::move(other).status()); + } + return *this; +} + +template const absl::Status& StatusOr::status() const& { return this->status_; } +template absl::Status StatusOr::status() && { + return ok() ? absl::OkStatus() : std::move(this->status_); +} + +template const T& StatusOr::value() const& { + this->EnsureOk(); + return this->data_; +} + +template T& StatusOr::value() & { + this->EnsureOk(); + return this->data_; +} + +template const T&& StatusOr::value() const&& { + this->EnsureOk(); + return std::move(this->data_); +} + +template T&& StatusOr::value() && { + this->EnsureOk(); + return std::move(this->data_); +} + +template const T& StatusOr::operator*() const& { + this->EnsureOk(); + return this->data_; +} + +template T& StatusOr::operator*() & { + this->EnsureOk(); + return this->data_; +} + +template const T&& StatusOr::operator*() const&& { + this->EnsureOk(); + return std::move(this->data_); +} + +template T&& StatusOr::operator*() && { + this->EnsureOk(); + return std::move(this->data_); +} + +template const T* StatusOr::operator->() const { + this->EnsureOk(); + return &this->data_; +} + +template T* StatusOr::operator->() { + this->EnsureOk(); + return &this->data_; +} + +template template T StatusOr::value_or(U&& default_value) const& { + if (ok()) { + return this->data_; + } + return std::forward(default_value); +} + +template template T StatusOr::value_or(U&& default_value) && { + if (ok()) { + return std::move(this->data_); + } + return std::forward(default_value); +} + +template void StatusOr::IgnoreError() const { + // no-op +} + +} // namespace absl diff --git a/third_party/statusor/statusor_internals.h b/third_party/statusor/statusor_internals.h new file mode 100644 index 0000000000000..ffe3f91af2c75 --- /dev/null +++ b/third_party/statusor/statusor_internals.h @@ -0,0 +1,244 @@ +/** + * IMPORTANT: this file is a fork of the soon to be open-source absl::StatusOr class. + * When the absl::StatusOr lands this file will be removed. + */ + +/* + * Copyright 2019 Google LLC + * + * 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 + * + * http://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 +#include +#include + +#include "absl/base/attributes.h" +#include "absl/meta/type_traits.h" +#include "absl/status/status.h" + +namespace absl { + +namespace internal_statusor { + +class Helper { +public: + // Move type-agnostic error handling to the .cc. + static void HandleInvalidStatusCtorArg(absl::Status*); + ABSL_ATTRIBUTE_NORETURN static void Crash(const absl::Status& status); +}; + +// Construct an instance of T in `p` through placement new, passing Args... to +// the constructor. +// This abstraction is here mostly for the gcc performance fix. +template void PlacementNew(void* p, Args&&... args) { +#if defined(__GNUC__) && !defined(__clang__) + // Teach gcc that 'p' cannot be null, fixing code size issues. + if (p == nullptr) + __builtin_unreachable(); +#endif + new (p) T(std::forward(args)...); +} + +// Helper base class to hold the data and all operations. +// We move all this to a base class to allow mixing with the appropriate +// TraitsBase specialization. +template class StatusOrData { + template friend class StatusOrData; + +public: + StatusOrData() = delete; + + StatusOrData(const StatusOrData& other) { + if (other.ok()) { + MakeValue(other.data_); + MakeStatus(); + } else { + MakeStatus(other.status_); + } + } + + StatusOrData(StatusOrData&& other) noexcept { + if (other.ok()) { + MakeValue(std::move(other.data_)); + MakeStatus(); + } else { + MakeStatus(std::move(other.status_)); + } + } + + template StatusOrData(const StatusOrData& other) { + if (other.ok()) { + MakeValue(other.data_); + MakeStatus(); + } else { + MakeStatus(other.status_); + } + } + + template StatusOrData(StatusOrData&& other) { + if (other.ok()) { + MakeValue(std::move(other.data_)); + MakeStatus(); + } else { + MakeStatus(std::move(other.status_)); + } + } + + explicit StatusOrData(const T& value) : data_(value) { MakeStatus(); } + explicit StatusOrData(T&& value) : data_(std::move(value)) { MakeStatus(); } + + explicit StatusOrData(const absl::Status& status) : status_(status) { EnsureNotOk(); } + explicit StatusOrData(absl::Status&& status) : status_(std::move(status)) { EnsureNotOk(); } + + StatusOrData& operator=(const StatusOrData& other) { + if (this == &other) + return *this; + if (other.ok()) + Assign(other.data_); + else + Assign(other.status_); + return *this; + } + + StatusOrData& operator=(StatusOrData&& other) { + if (this == &other) + return *this; + if (other.ok()) + Assign(std::move(other.data_)); + else + Assign(std::move(other.status_)); + return *this; + } + + ~StatusOrData() { + if (ok()) { + status_.~Status(); + data_.~T(); + } else { + status_.~Status(); + } + } + + void Assign(const T& value) { + if (ok()) { + data_.~T(); + MakeValue(value); + } else { + MakeValue(value); + status_ = absl::OkStatus(); + } + } + + void Assign(T&& value) { + if (ok()) { + data_.~T(); + MakeValue(std::move(value)); + } else { + MakeValue(std::move(value)); + status_ = absl::OkStatus(); + } + } + + void Assign(const absl::Status& status) { + Clear(); + status_ = status; + EnsureNotOk(); + } + + void Assign(absl::Status&& status) { + Clear(); + status_ = std::move(status); + EnsureNotOk(); + } + + bool ok() const { return status_.ok(); } + +protected: + // status_ will always be active after the constructor. + // We make it a union to be able to initialize exactly how we need without + // waste. + // E/g. in the copy constructor we use the default constructor of + // Status in the ok() path to avoid an extra Ref call. + union { + absl::Status status_; + }; + + // data_ is active iff status_.ok()==true + struct Dummy {}; + union { + // When T is const, we need some non-const object we can cast to void* for + // the placement new. dummy_ is that object. + Dummy dummy_; + T data_; + }; + + void Clear() { + if (ok()) + data_.~T(); + } + + void EnsureOk() const { + if (!ok()) + Helper::Crash(status_); + } + + void EnsureNotOk() { + if (ok()) + Helper::HandleInvalidStatusCtorArg(&status_); + } + + // Construct the value (i.e. data_) through placement new with the passed + // argument. + template void MakeValue(Arg&& arg) { + internal_statusor::PlacementNew(&dummy_, std::forward(arg)); + } + + // Construct the status (i.e. status_) through placement new with the passed + // argument. + template void MakeStatus(Args&&... args) { + internal_statusor::PlacementNew(&status_, std::forward(args)...); + } +}; + +// Helper base class to allow implicitly deleted constructors and assignment +// operations in StatusOr. +// TraitsBase will explicitly delete what it can't support and StatusOr will +// inherit that behavior implicitly. +template struct TraitsBase { + TraitsBase() = default; + TraitsBase(const TraitsBase&) = default; + TraitsBase(TraitsBase&&) = default; + TraitsBase& operator=(const TraitsBase&) = default; + TraitsBase& operator=(TraitsBase&&) = default; +}; + +template <> struct TraitsBase { + TraitsBase() = default; + TraitsBase(const TraitsBase&) = delete; + TraitsBase(TraitsBase&&) = default; + TraitsBase& operator=(const TraitsBase&) = delete; + TraitsBase& operator=(TraitsBase&&) = default; +}; + +template <> struct TraitsBase { + TraitsBase() = default; + TraitsBase(const TraitsBase&) = delete; + TraitsBase(TraitsBase&&) = delete; + TraitsBase& operator=(const TraitsBase&) = delete; + TraitsBase& operator=(TraitsBase&&) = delete; +}; + +} // namespace internal_statusor + +} // namespace absl diff --git a/third_party/statusor/statusor_test.cc b/third_party/statusor/statusor_test.cc new file mode 100644 index 0000000000000..b627c518476e1 --- /dev/null +++ b/third_party/statusor/statusor_test.cc @@ -0,0 +1,441 @@ +/** + * IMPORTANT: this file is a fork of the soon to be open-source absl::StatusOr class. + * When the absl::StatusOr lands this file will be removed. + */ + +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 + + http://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. +==============================================================================*/ + +// Unit tests for StatusOr + +#include +#include + +#include "third_party/statusor/statusor.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace absl { +namespace { + + +class Base1 { + public: + virtual ~Base1() {} + int pad_; +}; + +class Base2 { + public: + virtual ~Base2() {} + int yetotherpad_; +}; + +class Derived : public Base1, public Base2 { + public: + ~Derived() override {} + int evenmorepad_; +}; + +class CopyNoAssign { + public: + explicit CopyNoAssign(int value) : foo_(value) {} + CopyNoAssign(const CopyNoAssign& other) : foo_(other.foo_) {} + int foo_; + + private: + const CopyNoAssign& operator=(const CopyNoAssign&); +}; + +class NoDefaultConstructor { + public: + explicit NoDefaultConstructor(int foo); +}; + +static_assert(!std::is_default_constructible(), + "Should not be default-constructible."); + +StatusOr> ReturnUniquePtr() { + // Uses implicit constructor from T&& + return std::unique_ptr(new int(0)); +} + +TEST(StatusOr, ElementType) { + static_assert(std::is_same::element_type, int>(), ""); + static_assert(std::is_same::element_type, char>(), ""); +} + +TEST(StatusOr, NullPointerStatusOr) { + // As a very special case, null-plain-pointer StatusOr used to be an + // error. Test that it no longer is. + StatusOr null_status(nullptr); + EXPECT_TRUE(null_status.ok()); + EXPECT_EQ(null_status.value(), nullptr); +} + +TEST(StatusOr, TestNoDefaultConstructorInitialization) { + // Explicitly initialize it with an error code. + StatusOr statusor(absl::CancelledError("")); + EXPECT_FALSE(statusor.ok()); + EXPECT_EQ(statusor.status().code(), absl::StatusCode::kCancelled); + + // Default construction of StatusOr initializes it with an UNKNOWN error code. + StatusOr statusor2; + EXPECT_FALSE(statusor2.ok()); + EXPECT_EQ(statusor2.status().code(), absl::StatusCode::kUnknown); +} + +TEST(StatusOr, TestMoveOnlyInitialization) { + StatusOr> thing(ReturnUniquePtr()); + ASSERT_TRUE(thing.ok()); + EXPECT_EQ(0, *thing.value()); + int* previous = thing.value().get(); + + thing = ReturnUniquePtr(); + EXPECT_TRUE(thing.ok()); + EXPECT_EQ(0, *thing.value()); + EXPECT_NE(previous, thing.value().get()); +} + +TEST(StatusOr, TestMoveOnlyStatusCtr) { + StatusOr> thing(absl::CancelledError("")); + ASSERT_FALSE(thing.ok()); +} + +TEST(StatusOr, TestMoveOnlyValueExtraction) { + StatusOr> thing(ReturnUniquePtr()); + ASSERT_TRUE(thing.ok()); + std::unique_ptr ptr = std::move(thing).value(); + EXPECT_EQ(0, *ptr); + + thing = std::move(ptr); + ptr = std::move(thing.value()); + EXPECT_EQ(0, *ptr); +} + +TEST(StatusOr, TestMoveOnlyConversion) { + StatusOr> const_thing(ReturnUniquePtr()); + EXPECT_TRUE(const_thing.ok()); + EXPECT_EQ(0, *const_thing.value()); + + // Test rvalue converting assignment + const int* const_previous = const_thing.value().get(); + const_thing = ReturnUniquePtr(); + EXPECT_TRUE(const_thing.ok()); + EXPECT_EQ(0, *const_thing.value()); + EXPECT_NE(const_previous, const_thing.value().get()); +} + +TEST(StatusOr, TestMoveOnlyVector) { + // Sanity check that StatusOr works in vector. + std::vector>> vec; + vec.push_back(ReturnUniquePtr()); + vec.resize(2); + auto another_vec = std::move(vec); + EXPECT_EQ(0, *another_vec[0].value()); + EXPECT_EQ(absl::StatusCode::kUnknown, another_vec[1].status().code()); +} + +TEST(StatusOr, TestMoveWithValuesAndErrors) { + StatusOr status_or(std::string(1000, '0')); + StatusOr value1(std::string(1000, '1')); + StatusOr value2(std::string(1000, '2')); + StatusOr error1(Status(absl::StatusCode::kUnknown, "error1")); + StatusOr error2(Status(absl::StatusCode::kUnknown, "error2")); + + ASSERT_TRUE(status_or.ok()); + EXPECT_EQ(std::string(1000, '0'), status_or.value()); + + // Overwrite the value in status_or with another value. + status_or = std::move(value1); + ASSERT_TRUE(status_or.ok()); + EXPECT_EQ(std::string(1000, '1'), status_or.value()); + + // Overwrite the value in status_or with an error. + status_or = std::move(error1); + ASSERT_FALSE(status_or.ok()); + EXPECT_EQ("error1", status_or.status().message()); + + // Overwrite the error in status_or with another error. + status_or = std::move(error2); + ASSERT_FALSE(status_or.ok()); + EXPECT_EQ("error2", status_or.status().message()); + + // Overwrite the error with a value. + status_or = std::move(value2); + ASSERT_TRUE(status_or.ok()); + EXPECT_EQ(std::string(1000, '2'), status_or.value()); +} + +TEST(StatusOr, TestCopyWithValuesAndErrors) { + StatusOr status_or(std::string(1000, '0')); + StatusOr value1(std::string(1000, '1')); + StatusOr value2(std::string(1000, '2')); + StatusOr error1(Status(absl::StatusCode::kUnknown, "error1")); + StatusOr error2(Status(absl::StatusCode::kUnknown, "error2")); + + ASSERT_TRUE(status_or.ok()); + EXPECT_EQ(std::string(1000, '0'), status_or.value()); + + // Overwrite the value in status_or with another value. + status_or = value1; + ASSERT_TRUE(status_or.ok()); + EXPECT_EQ(std::string(1000, '1'), status_or.value()); + + // Overwrite the value in status_or with an error. + status_or = error1; + ASSERT_FALSE(status_or.ok()); + EXPECT_EQ("error1", status_or.status().message()); + + // Overwrite the error in status_or with another error. + status_or = error2; + ASSERT_FALSE(status_or.ok()); + EXPECT_EQ("error2", status_or.status().message()); + + // Overwrite the error with a value. + status_or = value2; + ASSERT_TRUE(status_or.ok()); + EXPECT_EQ(std::string(1000, '2'), status_or.value()); + + // Verify original values unchanged. + EXPECT_EQ(std::string(1000, '1'), value1.value()); + EXPECT_EQ("error1", error1.status().message()); + EXPECT_EQ("error2", error2.status().message()); + EXPECT_EQ(std::string(1000, '2'), value2.value()); +} + +TEST(StatusOr, TestDefaultCtor) { + StatusOr thing; + EXPECT_FALSE(thing.ok()); + EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown); +} + +TEST(StatusOrDeathTest, TestDefaultCtorValue) { + StatusOr thing; + EXPECT_DEATH(thing.value(), ""); + + const StatusOr thing2; + EXPECT_DEATH(thing.value(), ""); +} + +TEST(StatusOr, TestStatusCtor) { + StatusOr thing(Status(absl::StatusCode::kCancelled, "")); + EXPECT_FALSE(thing.ok()); + EXPECT_EQ(thing.status().code(), absl::StatusCode::kCancelled); +} + +TEST(StatusOr, TestValueCtor) { + const int kI = 4; + const StatusOr thing(kI); + EXPECT_TRUE(thing.ok()); + EXPECT_EQ(kI, thing.value()); +} + +TEST(StatusOr, TestCopyCtorStatusOk) { + const int kI = 4; + const StatusOr original(kI); + const StatusOr copy(original); + EXPECT_EQ(copy.status(), original.status()); + EXPECT_EQ(original.value(), copy.value()); +} + +TEST(StatusOr, TestCopyCtorStatusNotOk) { + StatusOr original(Status(absl::StatusCode::kCancelled, "")); + StatusOr copy(original); + EXPECT_EQ(copy.status(), original.status()); +} + +TEST(StatusOr, TestCopyCtorNonAssignable) { + const int kI = 4; + CopyNoAssign value(kI); + StatusOr original(value); + StatusOr copy(original); + EXPECT_EQ(copy.status(), original.status()); + EXPECT_EQ(original.value().foo_, copy.value().foo_); +} + +TEST(StatusOr, TestCopyCtorStatusOKConverting) { + const int kI = 4; + StatusOr original(kI); + StatusOr copy(original); + EXPECT_EQ(copy.status(), original.status()); + EXPECT_DOUBLE_EQ(original.value(), copy.value()); +} + +TEST(StatusOr, TestCopyCtorStatusNotOkConverting) { + StatusOr original(Status(absl::StatusCode::kCancelled, "")); + StatusOr copy(original); + EXPECT_EQ(copy.status(), original.status()); +} + +TEST(StatusOr, TestAssignmentStatusOk) { + const int kI = 4; + StatusOr source(kI); + StatusOr target; + target = source; + EXPECT_EQ(target.status(), source.status()); + EXPECT_EQ(source.value(), target.value()); +} + +TEST(StatusOr, TestAssignmentStatusNotOk) { + StatusOr source(Status(absl::StatusCode::kCancelled, "")); + StatusOr target; + target = source; + EXPECT_EQ(target.status(), source.status()); +} + +TEST(StatusOr, TestStatus) { + StatusOr good(4); + EXPECT_TRUE(good.ok()); + StatusOr bad(Status(absl::StatusCode::kCancelled, "")); + EXPECT_FALSE(bad.ok()); + EXPECT_EQ(bad.status(), Status(absl::StatusCode::kCancelled, "")); +} + +TEST(StatusOr, TestValue) { + const int kI = 4; + StatusOr thing(kI); + EXPECT_EQ(kI, thing.value()); +} + +TEST(StatusOr, TestValueConst) { + const int kI = 4; + const StatusOr thing(kI); + EXPECT_EQ(kI, thing.value()); +} + +TEST(StatusOrDeathTest, TestValueNotOk) { + StatusOr thing(Status(absl::StatusCode::kCancelled, "cancelled")); + EXPECT_DEATH(thing.value(), ""); +} + +TEST(StatusOrDeathTest, TestValueNotOkConst) { + const StatusOr thing(Status(absl::StatusCode::kUnknown, "")); + EXPECT_DEATH(thing.value(), ""); +} + +TEST(StatusOr, TestPointerDefaultCtor) { + StatusOr thing; + EXPECT_FALSE(thing.ok()); + EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown); +} + +TEST(StatusOrDeathTest, TestPointerDefaultCtorValue) { + StatusOr thing; + EXPECT_DEATH(thing.value(), ""); +} + +TEST(StatusOr, TestPointerStatusCtor) { + StatusOr thing(Status(absl::StatusCode::kCancelled, "")); + EXPECT_FALSE(thing.ok()); + EXPECT_EQ(thing.status(), Status(absl::StatusCode::kCancelled, "")); +} + +TEST(StatusOr, TestPointerValueCtor) { + const int kI = 4; + StatusOr thing(&kI); + EXPECT_TRUE(thing.ok()); + EXPECT_EQ(&kI, thing.value()); +} + +TEST(StatusOr, TestPointerCopyCtorStatusOk) { + const int kI = 0; + StatusOr original(&kI); + StatusOr copy(original); + EXPECT_EQ(copy.status(), original.status()); + EXPECT_EQ(original.value(), copy.value()); +} + +TEST(StatusOr, TestPointerCopyCtorStatusNotOk) { + StatusOr original(Status(absl::StatusCode::kCancelled, "")); + StatusOr copy(original); + EXPECT_EQ(copy.status(), original.status()); +} + +TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) { + Derived derived; + StatusOr original(&derived); + StatusOr copy(original); + EXPECT_EQ(copy.status(), original.status()); + EXPECT_EQ(static_cast(original.value()), + copy.value()); +} + +TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) { + StatusOr original(Status(absl::StatusCode::kCancelled, "")); + StatusOr copy(original); + EXPECT_EQ(copy.status(), original.status()); +} + +TEST(StatusOr, TestPointerAssignmentStatusOk) { + const int kI = 0; + StatusOr source(&kI); + StatusOr target; + target = source; + EXPECT_EQ(target.status(), source.status()); + EXPECT_EQ(source.value(), target.value()); +} + +TEST(StatusOr, TestPointerAssignmentStatusNotOk) { + StatusOr source(Status(absl::StatusCode::kCancelled, "")); + StatusOr target; + target = source; + EXPECT_EQ(target.status(), source.status()); +} + +TEST(StatusOr, TestPointerStatus) { + const int kI = 0; + StatusOr good(&kI); + EXPECT_TRUE(good.ok()); + StatusOr bad(Status(absl::StatusCode::kCancelled, "")); + EXPECT_EQ(bad.status(), Status(absl::StatusCode::kCancelled, "")); +} + +TEST(StatusOr, TestPointerValue) { + const int kI = 0; + StatusOr thing(&kI); + EXPECT_EQ(&kI, thing.value()); +} + +TEST(StatusOr, TestPointerValueConst) { + const int kI = 0; + const StatusOr thing(&kI); + EXPECT_EQ(&kI, thing.value()); +} + +// NOTE(tucker): StatusOr does not support this kind +// of resize op. +// TEST(StatusOr, StatusOrVectorOfUniquePointerCanResize) { +// using EvilType = std::vector>; +// static_assert(std::is_copy_constructible::value, ""); +// std::vector> v(5); +// v.reserve(v.capacity() + 10); +// } + +TEST(StatusOrDeathTest, TestPointerValueNotOk) { + StatusOr thing(Status(absl::StatusCode::kCancelled, "cancelled")); + EXPECT_DEATH(thing.value(), ""); +} + +TEST(StatusOrDeathTest, TestPointerValueNotOkConst) { + const StatusOr thing(Status(absl::StatusCode::kCancelled, "cancelled")); + EXPECT_DEATH(thing.value(), ""); +} + +// Benchmarks were removed as we not intend to change forked code. + +} // namespace +} // namespace absl diff --git a/tools/code_format/check_format.py b/tools/code_format/check_format.py index 416a8bd6eca37..d3392637bb7c6 100755 --- a/tools/code_format/check_format.py +++ b/tools/code_format/check_format.py @@ -18,7 +18,7 @@ EXCLUDED_PREFIXES = ("./generated/", "./thirdparty/", "./build", "./.git/", "./bazel-", "./.cache", "./source/extensions/extensions_build_config.bzl", "./bazel/toolchains/configs/", "./tools/testdata/check_format/", - "./tools/pyformat/") + "./tools/pyformat/", "./third_party/") SUFFIXES = ("BUILD", "WORKSPACE", ".bzl", ".cc", ".h", ".java", ".m", ".md", ".mm", ".proto", ".rst") DOCS_SUFFIX = (".md", ".rst")