aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Firestore/core/src/firebase/firestore/immutable/CMakeLists.txt2
-rw-r--r--Firestore/core/src/firebase/firestore/util/CMakeLists.txt5
-rw-r--r--Firestore/core/src/firebase/firestore/util/firebase_assert.h11
-rw-r--r--Firestore/core/src/firebase/firestore/util/status.cc135
-rw-r--r--Firestore/core/src/firebase/firestore/util/status.h143
-rw-r--r--Firestore/core/src/firebase/firestore/util/statusor.cc41
-rw-r--r--Firestore/core/src/firebase/firestore/util/statusor.h322
-rw-r--r--Firestore/core/src/firebase/firestore/util/statusor_internals.h258
-rw-r--r--Firestore/core/test/firebase/firestore/util/CMakeLists.txt3
-rw-r--r--Firestore/core/test/firebase/firestore/util/status_test.cc107
-rw-r--r--Firestore/core/test/firebase/firestore/util/status_test_util.h35
-rw-r--r--Firestore/core/test/firebase/firestore/util/statusor_test.cc436
12 files changed, 1493 insertions, 5 deletions
diff --git a/Firestore/core/src/firebase/firestore/immutable/CMakeLists.txt b/Firestore/core/src/firebase/firestore/immutable/CMakeLists.txt
index e8a95cd..4079307 100644
--- a/Firestore/core/src/firebase/firestore/immutable/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/immutable/CMakeLists.txt
@@ -18,4 +18,6 @@ cc_library(
array_sorted_map.cc
array_sorted_map.h
map_entry.h
+ DEPENDS
+ firebase_firestore_util
)
diff --git a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
index 3e32111..7a080d4 100644
--- a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
@@ -118,6 +118,11 @@ cc_library(
ordered_code.cc
ordered_code.h
secure_random.h
+ status.cc
+ status.h
+ statusor.cc
+ statusor.h
+ statusor_internals.h
string_util.cc
string_util.h
DEPENDS
diff --git a/Firestore/core/src/firebase/firestore/util/firebase_assert.h b/Firestore/core/src/firebase/firestore/util/firebase_assert.h
index 76768e6..20c8429 100644
--- a/Firestore/core/src/firebase/firestore/util/firebase_assert.h
+++ b/Firestore/core/src/firebase/firestore/util/firebase_assert.h
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include "Firestore/core/src/firebase/firestore/util/log.h"
+#include "absl/base/attributes.h"
#define FIREBASE_EXPAND_STRINGIFY_(X) #X
#define FIREBASE_EXPAND_STRINGIFY(X) FIREBASE_EXPAND_STRINGIFY_(X)
@@ -107,11 +108,11 @@ namespace firestore {
namespace util {
// A no-return helper function. To raise an assertion, use Macro instead.
-void FailAssert(const char* file,
- const char* func,
- const int line,
- const char* format,
- ...);
+ABSL_ATTRIBUTE_NORETURN void FailAssert(const char* file,
+ const char* func,
+ const int line,
+ const char* format,
+ ...);
} // namespace util
} // namespace firestore
diff --git a/Firestore/core/src/firebase/firestore/util/status.cc b/Firestore/core/src/firebase/firestore/util/status.cc
new file mode 100644
index 0000000..0863139
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/status.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2015, 2018 Google
+ *
+ * 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 "Firestore/core/src/firebase/firestore/util/status.h"
+
+#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+Status::Status(FirestoreErrorCode code, absl::string_view msg) {
+ FIREBASE_ASSERT(code != FirestoreErrorCode::Ok);
+ state_ = std::unique_ptr<State>(new State);
+ state_->code = code;
+ state_->msg = static_cast<std::string>(msg);
+}
+
+void Status::Update(const Status& new_status) {
+ if (ok()) {
+ *this = new_status;
+ }
+}
+
+void Status::SlowCopyFrom(const State* src) {
+ if (src == nullptr) {
+ state_ = nullptr;
+ } else {
+ state_ = std::unique_ptr<State>(new State(*src));
+ }
+}
+
+const std::string& Status::empty_string() {
+ static std::string* empty = new std::string;
+ return *empty;
+}
+
+std::string Status::ToString() const {
+ if (state_ == nullptr) {
+ return "OK";
+ } else {
+ std::string result;
+ switch (code()) {
+ case FirestoreErrorCode::Cancelled:
+ result = "Cancelled";
+ break;
+ case FirestoreErrorCode::Unknown:
+ result = "Unknown";
+ break;
+ case FirestoreErrorCode::InvalidArgument:
+ result = "Invalid argument";
+ break;
+ case FirestoreErrorCode::DeadlineExceeded:
+ result = "Deadline exceeded";
+ break;
+ case FirestoreErrorCode::NotFound:
+ result = "Not found";
+ break;
+ case FirestoreErrorCode::AlreadyExists:
+ result = "Already exists";
+ break;
+ case FirestoreErrorCode::PermissionDenied:
+ result = "Permission denied";
+ break;
+ case FirestoreErrorCode::Unauthenticated:
+ result = "Unauthenticated";
+ break;
+ case FirestoreErrorCode::ResourceExhausted:
+ result = "Resource exhausted";
+ break;
+ case FirestoreErrorCode::FailedPrecondition:
+ result = "Failed precondition";
+ break;
+ case FirestoreErrorCode::Aborted:
+ result = "Aborted";
+ break;
+ case FirestoreErrorCode::OutOfRange:
+ result = "Out of range";
+ break;
+ case FirestoreErrorCode::Unimplemented:
+ result = "Unimplemented";
+ break;
+ case FirestoreErrorCode::Internal:
+ result = "Internal";
+ break;
+ case FirestoreErrorCode::Unavailable:
+ result = "Unavailable";
+ break;
+ case FirestoreErrorCode::DataLoss:
+ result = "Data loss";
+ break;
+ default:
+ result = StringPrintf("Unknown code(%d)", static_cast<int>(code()));
+ break;
+ }
+ result += ": ";
+ result += state_->msg;
+ return result;
+ }
+}
+
+void Status::IgnoreError() const {
+ // no-op
+}
+
+std::ostream& operator<<(std::ostream& os, const Status& x) {
+ os << x.ToString();
+ return os;
+}
+
+std::string StatusCheckOpHelperOutOfLine(const Status& v, const char* msg) {
+ FIREBASE_ASSERT(!v.ok());
+ std::string r("Non-OK-status: ");
+ r += msg;
+ r += " status: ";
+ r += v.ToString();
+ return r;
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/status.h b/Firestore/core/src/firebase/firestore/util/status.h
new file mode 100644
index 0000000..0a65aa3
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/status.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2015, 2018 Google
+ *
+ * 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUS_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUS_H_
+
+#include <functional>
+#include <iosfwd>
+#include <memory>
+#include <string>
+
+#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+/// Denotes success or failure of a call.
+class ABSL_MUST_USE_RESULT Status {
+ public:
+ /// Create a success status.
+ Status() {
+ }
+
+ /// \brief Create a status with the specified error code and msg as a
+ /// human-readable string containing more detailed information.
+ Status(FirestoreErrorCode code, absl::string_view msg);
+
+ /// Copy the specified status.
+ Status(const Status& s);
+ void operator=(const Status& s);
+
+ static Status OK() {
+ return Status();
+ }
+
+ /// Returns true iff the status indicates success.
+ bool ok() const {
+ return (state_ == nullptr);
+ }
+
+ FirestoreErrorCode code() const {
+ return ok() ? FirestoreErrorCode::Ok : state_->code;
+ }
+
+ const std::string& error_message() const {
+ return ok() ? empty_string() : state_->msg;
+ }
+
+ bool operator==(const Status& x) const;
+ bool operator!=(const Status& x) const;
+
+ /// \brief If `ok()`, stores `new_status` into `*this`. If `!ok()`,
+ /// preserves the current status, but may augment with additional
+ /// information about `new_status`.
+ ///
+ /// Convenient way of keeping track of the first error encountered.
+ /// Instead of:
+ /// `if (overall_status.ok()) overall_status = new_status`
+ /// Use:
+ /// `overall_status.Update(new_status);`
+ void Update(const Status& new_status);
+
+ /// \brief Return a string representation of this status suitable for
+ /// printing. Returns the string `"OK"` for success.
+ std::string ToString() const;
+
+ // 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;
+
+ private:
+ static const std::string& empty_string();
+ struct State {
+ FirestoreErrorCode code;
+ std::string msg;
+ };
+ // OK status has a `NULL` state_. Otherwise, `state_` points to
+ // a `State` structure containing the error code and message(s)
+ std::unique_ptr<State> state_;
+
+ void SlowCopyFrom(const State* src);
+};
+
+inline Status::Status(const Status& s)
+ : state_((s.state_ == nullptr) ? nullptr : new State(*s.state_)) {
+}
+
+inline void Status::operator=(const Status& s) {
+ // The following condition catches both aliasing (when this == &s),
+ // and the common case where both s and *this are ok.
+ if (state_ != s.state_) {
+ SlowCopyFrom(s.state_.get());
+ }
+}
+
+inline bool Status::operator==(const Status& x) const {
+ return (this->state_ == x.state_) || (ToString() == x.ToString());
+}
+
+inline bool Status::operator!=(const Status& x) const {
+ return !(*this == x);
+}
+
+std::ostream& operator<<(std::ostream& os, const Status& x);
+
+typedef std::function<void(const Status&)> StatusCallback;
+
+extern std::string StatusCheckOpHelperOutOfLine(const Status& v,
+ const char* msg);
+
+#define STATUS_CHECK_OK(val) \
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION( \
+ val.ok(), val.ok(), StatusCheckOpHelperOutOfLine(val, #val).c_str())
+
+// DEBUG only version of STATUS_CHECK_OK. Compiler still parses 'val' even in
+// opt mode.
+#define STATUS_DCHECK_OK(val) \
+ FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION( \
+ val.ok(), val.ok(), StatusCheckOpHelperOutOfLine(val, #val).c_str())
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUS_H_
diff --git a/Firestore/core/src/firebase/firestore/util/statusor.cc b/Firestore/core/src/firebase/firestore/util/statusor.cc
new file mode 100644
index 0000000..be1e03a
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/statusor.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017, 2018 Google
+ *
+ * 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 "Firestore/core/src/firebase/firestore/util/statusor.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+namespace internal_statusor {
+
+void Helper::HandleInvalidStatusCtorArg(Status* status) {
+ const char* kMessage =
+ "An OK status is not a valid constructor argument to StatusOr<T>";
+ FIREBASE_DEV_ASSERT_MESSAGE(false, kMessage);
+ // Fall back to Internal for non-debug builds
+ *status = Status(FirestoreErrorCode::Internal, kMessage);
+}
+
+void Helper::Crash(const Status& status) {
+ FIREBASE_ASSERT_MESSAGE(
+ false, "Attempting to fetch value instead of handling error ",
+ status.ToString().c_str());
+}
+
+} // namespace internal_statusor
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/statusor.h b/Firestore/core/src/firebase/firestore/util/statusor.h
new file mode 100644
index 0000000..dc5644a
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/statusor.h
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2017, 2018 Google
+ *
+ * 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<T> 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<T> does not allow its Status
+// value to be Status::OK. Furthermore, the value of a StatusOr<T*>
+// must not be null. This is enforced by a debug check in most cases,
+// but even when it is not, clients must not set the value to null.
+//
+// The primary use-case for StatusOr<T> is as the return value of a
+// function which may fail.
+//
+// Example client usage for a StatusOr<T>, where T is not a pointer:
+//
+// StatusOr<float> result = DoBigCalculationThatCouldFail();
+// if (result.ok()) {
+// float answer = result.ValueOrDie();
+// printf("Big calculation yielded: %f", answer);
+// } else {
+// LOG(ERROR) << result.status();
+// }
+//
+// Example client usage for a StatusOr<T*>:
+//
+// StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
+// if (result.ok()) {
+// std::unique_ptr<Foo> foo(result.ValueOrDie());
+// foo->DoSomethingCool();
+// } else {
+// LOG(ERROR) << result.status();
+// }
+//
+// Example client usage for a StatusOr<std::unique_ptr<T>>:
+//
+// StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
+// if (result.ok()) {
+// std::unique_ptr<Foo> foo = std::move(result.ValueOrDie());
+// foo->DoSomethingCool();
+// } else {
+// LOG(ERROR) << result.status();
+// }
+//
+// Example factory implementation returning StatusOr<T*>:
+//
+// StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
+// if (arg <= 0) {
+// return tensorflow::InvalidArgument("Arg must be positive");
+// } else {
+// return new Foo(arg);
+// }
+// }
+//
+// Note that the assignment operators require that destroying the currently
+// stored value cannot invalidate the argument; in other words, the argument
+// cannot be an alias for the current value, or anything owned by the current
+// value.
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_H_
+
+#include <utility>
+
+#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
+#include "Firestore/core/src/firebase/firestore/util/status.h"
+#include "Firestore/core/src/firebase/firestore/util/statusor_internals.h"
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+template <typename T>
+class ABSL_MUST_USE_RESULT StatusOr
+ : private internal_statusor::StatusOrData<T>,
+ private internal_statusor::TraitsBase<
+ std::is_copy_constructible<T>::value,
+ std::is_move_constructible<T>::value> {
+ template <typename U>
+ friend class StatusOr;
+
+ typedef internal_statusor::StatusOrData<T> Base;
+
+ public:
+ typedef T element_type;
+
+ // Constructs a new StatusOr with FirebaseErrorCode::Unknown status. This is
+ // marked 'explicit' to try to catch cases like 'return {};', where people
+ // think StatusOr<std::vector<int>> will be initialized with an empty vector,
+ // instead of a FirebaseErrorCode::Unknown status.
+ explicit StatusOr(); // NOLINT: allow explicit zero-parameter ctor
+
+ // StatusOr<T> will be copy constructible/assignable if T is copy
+ // constructible.
+ StatusOr(const StatusOr&) = default;
+ StatusOr& operator=(const StatusOr&) = default;
+
+ // StatusOr<T> 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.
+ // TODO(b/62186717): These should not participate in overload resolution if U
+ // is not convertible to T.
+ template <typename U>
+ StatusOr(const StatusOr<U>& other);
+ template <typename U>
+ StatusOr(StatusOr<U>&& other);
+
+ // Conversion copy/move assignment operator, T must be convertible from U.
+ template <typename U>
+ StatusOr& operator=(const StatusOr<U>& other);
+ template <typename U>
+ StatusOr& operator=(StatusOr<U>&& other);
+
+ // Constructs a new StatusOr with the given value. After calling this
+ // constructor, calls to ValueOrDie() will succeed, and calls to status() will
+ // return OK.
+ //
+ // NOTE: Not explicit - we want to use StatusOr<T> as a return type
+ // so it is convenient and sensible to be able to do 'return T()'
+ // when the return type is StatusOr<T>.
+ //
+ // REQUIRES: T is copy constructible.
+ StatusOr(const T& value); // NOLINT: allow non-explicit 1-param ctor
+
+ // Constructs a new StatusOr with the given non-ok status. After calling
+ // this constructor, calls to ValueOrDie() will CHECK-fail.
+ //
+ // NOTE: Not explicit - we want to use StatusOr<T> as a return
+ // value, so it is convenient and sensible to be able to do 'return
+ // Status()' when the return type is StatusOr<T>.
+ //
+ // REQUIRES: !status.ok(). This requirement is DCHECKed.
+ // In optimized builds, passing Status::OK() here will have the effect
+ // of passing tensorflow::error::INTERNAL as a fallback.
+ StatusOr(const Status& status); // NOLINT: allow non-explicit 1-param ctor
+ StatusOr& operator=(const Status& status);
+
+ // TODO(b/62186997): Add operator=(T) overloads.
+
+ // Similar to the `const T&` overload.
+ //
+ // REQUIRES: T is move constructible.
+ StatusOr(T&& value); // NOLINT: allow non-explicit 1-param ctor
+
+ // RValue versions of the operations declared above.
+ StatusOr(Status&& status); // NOLINT: allow non-explicit 1-param ctor
+ StatusOr& operator=(Status&& status);
+
+ // Returns this->status().ok()
+ bool ok() const {
+ return this->status_.ok();
+ }
+
+ // Returns a reference to our status. If this contains a T, then
+ // returns Status::OK().
+ const Status& status() const&;
+ Status status() &&;
+
+ // Returns a reference to our current value, or CHECK-fails if !this->ok().
+ //
+ // Note: for value types that are cheap to copy, prefer simple code:
+ //
+ // T value = statusor.ValueOrDie();
+ //
+ // Otherwise, if the value type is expensive to copy, but can be left
+ // in the StatusOr, simply assign to a reference:
+ //
+ // T& value = statusor.ValueOrDie(); // or `const T&`
+ //
+ // Otherwise, if the value type supports an efficient move, it can be
+ // used as follows:
+ //
+ // T value = std::move(statusor).ValueOrDie();
+ //
+ // The std::move on statusor instead of on the whole expression enables
+ // warnings about possible uses of the statusor object after the move.
+ // C++ style guide waiver for ref-qualified overloads granted in cl/143176389
+ // See go/ref-qualifiers for more details on such overloads.
+ const T& ValueOrDie() const&;
+ T& ValueOrDie() &;
+ const T&& ValueOrDie() const&&;
+ T&& ValueOrDie() &&;
+
+ T ConsumeValueOrDie() {
+ return std::move(ValueOrDie());
+ }
+
+ // 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<T>
+
+template <typename T>
+StatusOr<T>::StatusOr() : Base(Status(FirestoreErrorCode::Unknown, "")) {
+}
+
+template <typename T>
+StatusOr<T>::StatusOr(const T& value) : Base(value) {
+}
+
+template <typename T>
+StatusOr<T>::StatusOr(const Status& status) : Base(status) {
+}
+
+template <typename T>
+StatusOr<T>& StatusOr<T>::operator=(const Status& status) {
+ this->Assign(status);
+ return *this;
+}
+
+template <typename T>
+StatusOr<T>::StatusOr(T&& value) : Base(std::move(value)) {
+}
+
+template <typename T>
+StatusOr<T>::StatusOr(Status&& status) : Base(std::move(status)) {
+}
+
+template <typename T>
+StatusOr<T>& StatusOr<T>::operator=(Status&& status) {
+ this->Assign(std::move(status));
+ return *this;
+}
+
+template <typename T>
+template <typename U>
+inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
+ : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {
+}
+
+template <typename T>
+template <typename U>
+inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
+ if (other.ok())
+ this->Assign(other.ValueOrDie());
+ else
+ this->Assign(other.status());
+ return *this;
+}
+
+template <typename T>
+template <typename U>
+inline StatusOr<T>::StatusOr(StatusOr<U>&& other)
+ : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {
+}
+
+template <typename T>
+template <typename U>
+inline StatusOr<T>& StatusOr<T>::operator=(StatusOr<U>&& other) {
+ if (other.ok()) {
+ this->Assign(std::move(other).ValueOrDie());
+ } else {
+ this->Assign(std::move(other).status());
+ }
+ return *this;
+}
+
+template <typename T>
+const Status& StatusOr<T>::status() const& {
+ return this->status_;
+}
+template <typename T>
+Status StatusOr<T>::status() && {
+ return ok() ? Status::OK() : std::move(this->status_);
+}
+
+template <typename T>
+const T& StatusOr<T>::ValueOrDie() const& {
+ this->EnsureOk();
+ return this->data_;
+}
+
+template <typename T>
+T& StatusOr<T>::ValueOrDie() & {
+ this->EnsureOk();
+ return this->data_;
+}
+
+template <typename T>
+const T&& StatusOr<T>::ValueOrDie() const&& {
+ this->EnsureOk();
+ return std::move(this->data_);
+}
+
+template <typename T>
+T&& StatusOr<T>::ValueOrDie() && {
+ this->EnsureOk();
+ return std::move(this->data_);
+}
+
+template <typename T>
+void StatusOr<T>::IgnoreError() const {
+ // no-op
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_H_
diff --git a/Firestore/core/src/firebase/firestore/util/statusor_internals.h b/Firestore/core/src/firebase/firestore/util/statusor_internals.h
new file mode 100644
index 0000000..d6c8de1
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/statusor_internals.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2017, 2018 Google
+ *
+ * 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_INTERNALS_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_INTERNALS_H_
+
+#include <utility>
+
+#include "Firestore/core/src/firebase/firestore/util/status.h"
+#include "absl/base/attributes.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+namespace internal_statusor {
+
+class Helper {
+ public:
+ // Move type-agnostic error handling to the .cc.
+ static void HandleInvalidStatusCtorArg(Status*);
+ ABSL_ATTRIBUTE_NORETURN static void Crash(const 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 <typename T, typename... Args>
+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>(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 <typename T>
+class StatusOrData {
+ template <typename U>
+ 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 <typename U>
+ StatusOrData(const StatusOrData<U>& other) {
+ if (other.ok()) {
+ MakeValue(other.data_);
+ MakeStatus();
+ } else {
+ MakeStatus(other.status_);
+ }
+ }
+
+ template <typename U>
+ StatusOrData(StatusOrData<U>&& 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 Status& status) : status_(status) {
+ EnsureNotOk();
+ }
+ explicit StatusOrData(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_ = Status::OK();
+ }
+ }
+
+ void Assign(T&& value) {
+ if (ok()) {
+ data_.~T();
+ MakeValue(std::move(value));
+ } else {
+ MakeValue(std::move(value));
+ status_ = Status::OK();
+ }
+ }
+
+ void Assign(const Status& status) {
+ Clear();
+ status_ = status;
+ EnsureNotOk();
+ }
+
+ void Assign(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.
+ // Eg. in the copy constructor we use the default constructor of Status in
+ // the ok() path to avoid an extra Ref call.
+ union {
+ 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 (ie. data_) through placement new with the passed
+ // argument.
+ template <typename Arg>
+ void MakeValue(Arg&& arg) {
+ internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg));
+ }
+
+ // Construct the status (ie. status_) through placement new with the passed
+ // argument.
+ template <typename... Args>
+ void MakeStatus(Args&&... args) {
+ internal_statusor::PlacementNew<Status>(&status_,
+ std::forward<Args>(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 <bool Copy, bool Move>
+struct TraitsBase {
+ TraitsBase() = default;
+ TraitsBase(const TraitsBase&) = default;
+ TraitsBase(TraitsBase&&) = default;
+ TraitsBase& operator=(const TraitsBase&) = default;
+ TraitsBase& operator=(TraitsBase&&) = default;
+};
+
+template <>
+struct TraitsBase<false, true> {
+ TraitsBase() = default;
+ TraitsBase(const TraitsBase&) = delete;
+ TraitsBase(TraitsBase&&) = default;
+ TraitsBase& operator=(const TraitsBase&) = delete;
+ TraitsBase& operator=(TraitsBase&&) = default;
+};
+
+template <>
+struct TraitsBase<false, false> {
+ TraitsBase() = default;
+ TraitsBase(const TraitsBase&) = delete;
+ TraitsBase(TraitsBase&&) = delete;
+ TraitsBase& operator=(const TraitsBase&) = delete;
+ TraitsBase& operator=(TraitsBase&&) = delete;
+};
+
+} // namespace internal_statusor
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_INTERNALS_H_
diff --git a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
index 0bddf06..13482b0 100644
--- a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
+++ b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
@@ -45,6 +45,9 @@ cc_test(
comparison_test.cc
iterator_adaptors_test.cc
ordered_code_test.cc
+ status_test.cc
+ status_test_util.h
+ statusor_test.cc
string_printf_test.cc
string_util_test.cc
DEPENDS
diff --git a/Firestore/core/test/firebase/firestore/util/status_test.cc b/Firestore/core/test/firebase/firestore/util/status_test.cc
new file mode 100644
index 0000000..e5cb8dc
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/util/status_test.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2015, 2018 Google
+ *
+ * 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 "Firestore/core/src/firebase/firestore/util/status.h"
+
+#include "Firestore/core/test/firebase/firestore/util/status_test_util.h"
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+TEST(Status, OK) {
+ EXPECT_EQ(Status::OK().code(), FirestoreErrorCode::Ok);
+ EXPECT_EQ(Status::OK().error_message(), "");
+ EXPECT_OK(Status::OK());
+ ASSERT_OK(Status::OK());
+ STATUS_CHECK_OK(Status::OK());
+ EXPECT_EQ(Status::OK(), Status());
+ Status s;
+ EXPECT_TRUE(s.ok());
+}
+
+TEST(DeathStatus, CheckOK) {
+ Status status(FirestoreErrorCode::InvalidArgument, "Invalid");
+ ASSERT_ANY_THROW(STATUS_CHECK_OK(status));
+}
+
+TEST(Status, Set) {
+ Status status;
+ status = Status(FirestoreErrorCode::Cancelled, "Error message");
+ EXPECT_EQ(status.code(), FirestoreErrorCode::Cancelled);
+ EXPECT_EQ(status.error_message(), "Error message");
+}
+
+TEST(Status, Copy) {
+ Status a(FirestoreErrorCode::InvalidArgument, "Invalid");
+ Status b(a);
+ ASSERT_EQ(a.ToString(), b.ToString());
+}
+
+TEST(Status, Assign) {
+ Status a(FirestoreErrorCode::InvalidArgument, "Invalid");
+ Status b;
+ b = a;
+ ASSERT_EQ(a.ToString(), b.ToString());
+}
+
+TEST(Status, Update) {
+ Status s;
+ s.Update(Status::OK());
+ ASSERT_TRUE(s.ok());
+ Status a(FirestoreErrorCode::InvalidArgument, "Invalid");
+ s.Update(a);
+ ASSERT_EQ(s.ToString(), a.ToString());
+ Status b(FirestoreErrorCode::Internal, "Internal");
+ s.Update(b);
+ ASSERT_EQ(s.ToString(), a.ToString());
+ s.Update(Status::OK());
+ ASSERT_EQ(s.ToString(), a.ToString());
+ ASSERT_FALSE(s.ok());
+}
+
+TEST(Status, EqualsOK) {
+ ASSERT_EQ(Status::OK(), Status());
+}
+
+TEST(Status, EqualsSame) {
+ Status a(FirestoreErrorCode::InvalidArgument, "Invalid");
+ Status b(FirestoreErrorCode::InvalidArgument, "Invalid");
+ ASSERT_EQ(a, b);
+}
+
+TEST(Status, EqualsCopy) {
+ const Status a(FirestoreErrorCode::InvalidArgument, "Invalid");
+ const Status b = a;
+ ASSERT_EQ(a, b);
+}
+
+TEST(Status, EqualsDifferentCode) {
+ const Status a(FirestoreErrorCode::InvalidArgument, "message");
+ const Status b(FirestoreErrorCode::Internal, "message");
+ ASSERT_NE(a, b);
+}
+
+TEST(Status, EqualsDifferentMessage) {
+ const Status a(FirestoreErrorCode::InvalidArgument, "message");
+ const Status b(FirestoreErrorCode::InvalidArgument, "another");
+ ASSERT_NE(a, b);
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/util/status_test_util.h b/Firestore/core/test/firebase/firestore/util/status_test_util.h
new file mode 100644
index 0000000..745f3aa
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/util/status_test_util.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015, 2018 Google
+ *
+ * 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.
+ */
+
+#ifndef FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_UTIL_STATUS_TEST_UTIL_H_
+#define FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_UTIL_STATUS_TEST_UTIL_H_
+
+#include "Firestore/core/src/firebase/firestore/util/status.h"
+#include "gtest/gtest.h"
+
+// Macros for testing the results of functions that return tensorflow::Status.
+#define EXPECT_OK(statement) \
+ EXPECT_EQ(::firebase::firestore::util::Status::OK(), (statement))
+#define ASSERT_OK(statement) \
+ ASSERT_EQ(::firebase::firestore::util::Status::OK(), (statement))
+
+// There are no EXPECT_NOT_OK/ASSERT_NOT_OK macros since they would not
+// provide much value (when they fail, they would just print the OK status
+// which conveys no more information than EXPECT_FALSE(status.ok());
+// If you want to check for particular errors, a better alternative is:
+// EXPECT_EQ(..expected tensorflow::error::Code..., status.code());
+
+#endif // FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_UTIL_STATUS_TEST_UTIL_H_
diff --git a/Firestore/core/test/firebase/firestore/util/statusor_test.cc b/Firestore/core/test/firebase/firestore/util/statusor_test.cc
new file mode 100644
index 0000000..6c9ccf5
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/util/statusor_test.cc
@@ -0,0 +1,436 @@
+/*
+ * Copyright 2017, 2018 Google
+ *
+ * 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 "Firestore/core/src/firebase/firestore/util/statusor.h"
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+namespace {
+
+using std::string;
+
+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<NoDefaultConstructor>(),
+ "Should not be default-constructible.");
+
+StatusOr<std::unique_ptr<int>> ReturnUniquePtr() {
+ // Uses implicit constructor from T&&
+ return std::unique_ptr<int>(new int(0));
+}
+
+TEST(StatusOr, ElementType) {
+ static_assert(std::is_same<StatusOr<int>::element_type, int>(), "");
+ static_assert(std::is_same<StatusOr<char>::element_type, char>(), "");
+}
+
+TEST(StatusOr, TestNoDefaultConstructorInitialization) {
+ // Explicitly initialize it with an error code.
+ StatusOr<NoDefaultConstructor> statusor(
+ Status(FirestoreErrorCode::Cancelled, ""));
+ EXPECT_FALSE(statusor.ok());
+ EXPECT_EQ(statusor.status().code(), FirestoreErrorCode::Cancelled);
+
+ // Default construction of StatusOr initializes it with an UNKNOWN error code.
+ StatusOr<NoDefaultConstructor> statusor2;
+ EXPECT_FALSE(statusor2.ok());
+ EXPECT_EQ(statusor2.status().code(), FirestoreErrorCode::Unknown);
+}
+
+TEST(StatusOr, TestMoveOnlyInitialization) {
+ StatusOr<std::unique_ptr<int>> thing(ReturnUniquePtr());
+ ASSERT_TRUE(thing.ok());
+ EXPECT_EQ(0, *thing.ValueOrDie());
+ int* previous = thing.ValueOrDie().get();
+
+ thing = ReturnUniquePtr();
+ EXPECT_TRUE(thing.ok());
+ EXPECT_EQ(0, *thing.ValueOrDie());
+ EXPECT_NE(previous, thing.ValueOrDie().get());
+}
+
+TEST(StatusOr, TestMoveOnlyStatusCtr) {
+ StatusOr<std::unique_ptr<int>> thing(
+ Status(FirestoreErrorCode::Cancelled, ""));
+ ASSERT_FALSE(thing.ok());
+}
+
+TEST(StatusOr, TestMoveOnlyValueExtraction) {
+ StatusOr<std::unique_ptr<int>> thing(ReturnUniquePtr());
+ ASSERT_TRUE(thing.ok());
+ std::unique_ptr<int> ptr = thing.ConsumeValueOrDie();
+ EXPECT_EQ(0, *ptr);
+
+ thing = std::move(ptr);
+ ptr = std::move(thing.ValueOrDie());
+ EXPECT_EQ(0, *ptr);
+}
+
+TEST(StatusOr, TestMoveOnlyConversion) {
+ StatusOr<std::unique_ptr<const int>> const_thing(ReturnUniquePtr());
+ EXPECT_TRUE(const_thing.ok());
+ EXPECT_EQ(0, *const_thing.ValueOrDie());
+
+ // Test rvalue converting assignment
+ const int* const_previous = const_thing.ValueOrDie().get();
+ const_thing = ReturnUniquePtr();
+ EXPECT_TRUE(const_thing.ok());
+ EXPECT_EQ(0, *const_thing.ValueOrDie());
+ EXPECT_NE(const_previous, const_thing.ValueOrDie().get());
+}
+
+TEST(StatusOr, TestMoveOnlyVector) {
+ // Sanity check that StatusOr<MoveOnly> works in vector.
+ std::vector<StatusOr<std::unique_ptr<int>>> vec;
+ vec.push_back(ReturnUniquePtr());
+ vec.resize(2);
+ auto another_vec = std::move(vec);
+ EXPECT_EQ(0, *another_vec[0].ValueOrDie());
+ EXPECT_EQ(FirestoreErrorCode::Unknown, another_vec[1].status().code());
+}
+
+TEST(StatusOr, TestMoveWithValuesAndErrors) {
+ StatusOr<string> status_or(string(1000, '0'));
+ StatusOr<string> value1(string(1000, '1'));
+ StatusOr<string> value2(string(1000, '2'));
+ StatusOr<string> error1(Status(FirestoreErrorCode::Unknown, "error1"));
+ StatusOr<string> error2(Status(FirestoreErrorCode::Unknown, "error2"));
+
+ ASSERT_TRUE(status_or.ok());
+ EXPECT_EQ(string(1000, '0'), status_or.ValueOrDie());
+
+ // Overwrite the value in status_or with another value.
+ status_or = std::move(value1);
+ ASSERT_TRUE(status_or.ok());
+ EXPECT_EQ(string(1000, '1'), status_or.ValueOrDie());
+
+ // 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().error_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().error_message());
+
+ // Overwrite the error with a value.
+ status_or = std::move(value2);
+ ASSERT_TRUE(status_or.ok());
+ EXPECT_EQ(string(1000, '2'), status_or.ValueOrDie());
+}
+
+TEST(StatusOr, TestCopyWithValuesAndErrors) {
+ StatusOr<string> status_or(string(1000, '0'));
+ StatusOr<string> value1(string(1000, '1'));
+ StatusOr<string> value2(string(1000, '2'));
+ StatusOr<string> error1(Status(FirestoreErrorCode::Unknown, "error1"));
+ StatusOr<string> error2(Status(FirestoreErrorCode::Unknown, "error2"));
+
+ ASSERT_TRUE(status_or.ok());
+ EXPECT_EQ(string(1000, '0'), status_or.ValueOrDie());
+
+ // Overwrite the value in status_or with another value.
+ status_or = value1;
+ ASSERT_TRUE(status_or.ok());
+ EXPECT_EQ(string(1000, '1'), status_or.ValueOrDie());
+
+ // Overwrite the value in status_or with an error.
+ status_or = error1;
+ ASSERT_FALSE(status_or.ok());
+ EXPECT_EQ("error1", status_or.status().error_message());
+
+ // Overwrite the error in status_or with another error.
+ status_or = error2;
+ ASSERT_FALSE(status_or.ok());
+ EXPECT_EQ("error2", status_or.status().error_message());
+
+ // Overwrite the error with a value.
+ status_or = value2;
+ ASSERT_TRUE(status_or.ok());
+ EXPECT_EQ(string(1000, '2'), status_or.ValueOrDie());
+
+ // Verify original values unchanged.
+ EXPECT_EQ(string(1000, '1'), value1.ValueOrDie());
+ EXPECT_EQ("error1", error1.status().error_message());
+ EXPECT_EQ("error2", error2.status().error_message());
+ EXPECT_EQ(string(1000, '2'), value2.ValueOrDie());
+}
+
+TEST(StatusOr, TestDefaultCtor) {
+ StatusOr<int> thing;
+ EXPECT_FALSE(thing.ok());
+ EXPECT_EQ(thing.status().code(), FirestoreErrorCode::Unknown);
+}
+
+TEST(StatusOrDeathTest, TestDefaultCtorValue) {
+ StatusOr<int> thing;
+ EXPECT_ANY_THROW(thing.ValueOrDie());
+
+ const StatusOr<int> thing2;
+ EXPECT_ANY_THROW(thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestStatusCtor) {
+ StatusOr<int> thing(Status(FirestoreErrorCode::Cancelled, ""));
+ EXPECT_FALSE(thing.ok());
+ EXPECT_EQ(thing.status().code(), FirestoreErrorCode::Cancelled);
+}
+
+TEST(StatusOr, TestValueCtor) {
+ const int kI = 4;
+ const StatusOr<int> thing(kI);
+ EXPECT_TRUE(thing.ok());
+ EXPECT_EQ(kI, thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestCopyCtorStatusOk) {
+ const int kI = 4;
+ const StatusOr<int> original(kI);
+ const StatusOr<int> copy(original);
+ EXPECT_EQ(copy.status(), original.status());
+ EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
+}
+
+TEST(StatusOr, TestCopyCtorStatusNotOk) {
+ StatusOr<int> original(Status(FirestoreErrorCode::Cancelled, ""));
+ StatusOr<int> copy(original);
+ EXPECT_EQ(copy.status(), original.status());
+}
+
+TEST(StatusOr, TestCopyCtorNonAssignable) {
+ const int kI = 4;
+ CopyNoAssign value(kI);
+ StatusOr<CopyNoAssign> original(value);
+ StatusOr<CopyNoAssign> copy(original);
+ EXPECT_EQ(copy.status(), original.status());
+ EXPECT_EQ(original.ValueOrDie().foo_, copy.ValueOrDie().foo_);
+}
+
+TEST(StatusOr, TestCopyCtorStatusOKConverting) {
+ const int kI = 4;
+ StatusOr<int> original(kI);
+ StatusOr<double> copy(original);
+ EXPECT_EQ(copy.status(), original.status());
+ EXPECT_DOUBLE_EQ(original.ValueOrDie(), copy.ValueOrDie());
+}
+
+TEST(StatusOr, TestCopyCtorStatusNotOkConverting) {
+ StatusOr<int> original(Status(FirestoreErrorCode::Cancelled, ""));
+ StatusOr<double> copy(original);
+ EXPECT_EQ(copy.status(), original.status());
+}
+
+TEST(StatusOr, TestAssignmentStatusOk) {
+ const int kI = 4;
+ StatusOr<int> source(kI);
+ StatusOr<int> target;
+ target = source;
+ EXPECT_EQ(target.status(), source.status());
+ EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie());
+}
+
+TEST(StatusOr, TestAssignmentStatusNotOk) {
+ StatusOr<int> source(Status(FirestoreErrorCode::Cancelled, ""));
+ StatusOr<int> target;
+ target = source;
+ EXPECT_EQ(target.status(), source.status());
+}
+
+TEST(StatusOr, TestStatus) {
+ StatusOr<int> good(4);
+ EXPECT_TRUE(good.ok());
+ StatusOr<int> bad(Status(FirestoreErrorCode::Cancelled, ""));
+ EXPECT_FALSE(bad.ok());
+ EXPECT_EQ(bad.status(), Status(FirestoreErrorCode::Cancelled, ""));
+}
+
+TEST(StatusOr, TestValue) {
+ const int kI = 4;
+ StatusOr<int> thing(kI);
+ EXPECT_EQ(kI, thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestValueConst) {
+ const int kI = 4;
+ const StatusOr<int> thing(kI);
+ EXPECT_EQ(kI, thing.ValueOrDie());
+}
+
+TEST(StatusOrDeathTest, TestValueNotOk) {
+ StatusOr<int> thing(Status(FirestoreErrorCode::Cancelled, "cancelled"));
+ EXPECT_ANY_THROW(thing.ValueOrDie());
+}
+
+TEST(StatusOrDeathTest, TestValueNotOkConst) {
+ const StatusOr<int> thing(Status(FirestoreErrorCode::Unknown, ""));
+ EXPECT_ANY_THROW(thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerDefaultCtor) {
+ StatusOr<int*> thing;
+ EXPECT_FALSE(thing.ok());
+ EXPECT_EQ(thing.status().code(), FirestoreErrorCode::Unknown);
+}
+
+TEST(StatusOrDeathTest, TestPointerDefaultCtorValue) {
+ StatusOr<int*> thing;
+ EXPECT_ANY_THROW(thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerStatusCtor) {
+ StatusOr<int*> thing(Status(FirestoreErrorCode::Cancelled, ""));
+ EXPECT_FALSE(thing.ok());
+ EXPECT_EQ(thing.status(), Status(FirestoreErrorCode::Cancelled, ""));
+}
+
+TEST(StatusOr, TestPointerValueCtor) {
+ const int kI = 4;
+ StatusOr<const int*> thing(&kI);
+ EXPECT_TRUE(thing.ok());
+ EXPECT_EQ(&kI, thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusOk) {
+ const int kI = 0;
+ StatusOr<const int*> original(&kI);
+ StatusOr<const int*> copy(original);
+ EXPECT_EQ(copy.status(), original.status());
+ EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusNotOk) {
+ StatusOr<int*> original(Status(FirestoreErrorCode::Cancelled, ""));
+ StatusOr<int*> copy(original);
+ EXPECT_EQ(copy.status(), original.status());
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) {
+ Derived derived;
+ StatusOr<Derived*> original(&derived);
+ StatusOr<Base2*> copy(original);
+ EXPECT_EQ(copy.status(), original.status());
+ EXPECT_EQ(static_cast<const Base2*>(original.ValueOrDie()),
+ copy.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) {
+ StatusOr<Derived*> original(Status(FirestoreErrorCode::Cancelled, ""));
+ StatusOr<Base2*> copy(original);
+ EXPECT_EQ(copy.status(), original.status());
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusOk) {
+ const int kI = 0;
+ StatusOr<const int*> source(&kI);
+ StatusOr<const int*> target;
+ target = source;
+ EXPECT_EQ(target.status(), source.status());
+ EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusNotOk) {
+ StatusOr<int*> source(Status(FirestoreErrorCode::Cancelled, ""));
+ StatusOr<int*> target;
+ target = source;
+ EXPECT_EQ(target.status(), source.status());
+}
+
+TEST(StatusOr, TestPointerStatus) {
+ const int kI = 0;
+ StatusOr<const int*> good(&kI);
+ EXPECT_TRUE(good.ok());
+ StatusOr<const int*> bad(Status(FirestoreErrorCode::Cancelled, ""));
+ EXPECT_EQ(bad.status(), Status(FirestoreErrorCode::Cancelled, ""));
+}
+
+TEST(StatusOr, TestPointerValue) {
+ const int kI = 0;
+ StatusOr<const int*> thing(&kI);
+ EXPECT_EQ(&kI, thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerValueConst) {
+ const int kI = 0;
+ const StatusOr<const int*> thing(&kI);
+ EXPECT_EQ(&kI, thing.ValueOrDie());
+}
+
+// NOTE(tucker): tensorflow::StatusOr does not support this kind
+// of resize op.
+// NOTE(rsgowman): We stole StatusOr from tensorflow, so this applies here too.
+// TEST(StatusOr, StatusOrVectorOfUniquePointerCanResize) {
+// using EvilType = std::vector<std::unique_ptr<int>>;
+// static_assert(std::is_copy_constructible<EvilType>::value, "");
+// std::vector<StatusOr<EvilType>> v(5);
+// v.reserve(v.capacity() + 10);
+// }
+
+TEST(StatusOrDeathTest, TestPointerValueNotOk) {
+ StatusOr<int*> thing(Status(FirestoreErrorCode::Cancelled, "cancelled"));
+ EXPECT_ANY_THROW(thing.ValueOrDie());
+}
+
+TEST(StatusOrDeathTest, TestPointerValueNotOkConst) {
+ const StatusOr<int*> thing(
+ Status(FirestoreErrorCode::Cancelled, "cancelled"));
+ EXPECT_ANY_THROW(thing.ValueOrDie());
+}
+
+} // namespace
+} // namespace util
+} // namespace firestore
+} // namespace firebase