Adding RTCErrorOr class to be used by ORTC APIs.
This utility class can be used to represent either an error or a
successful return value. Follows the pattern of StatusOr in the protobuf
library.
This will be used by ORTC factory methods; for instance, CreateRtpSender
will either return an RtpSender or an error if the parameters are
invalid or some other failure occurs.
This CL also moves RTCError classes to a separate file, and adds tests
that were missing before.
BUG=webrtc:7013
Review-Url: https://codereview.webrtc.org/2692723002
Cr-Commit-Position: refs/heads/master@{#16659}
diff --git a/webrtc/api/BUILD.gn b/webrtc/api/BUILD.gn
index f0752f9..5a6051e 100644
--- a/webrtc/api/BUILD.gn
+++ b/webrtc/api/BUILD.gn
@@ -61,6 +61,8 @@
"peerconnectioninterface.h",
"peerconnectionproxy.h",
"proxy.h",
+ "rtcerror.cc",
+ "rtcerror.h",
"rtpparameters.h",
"rtpreceiverinterface.h",
"rtpsender.h",
@@ -198,4 +200,29 @@
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
}
}
+
+ rtc_test("rtc_api_unittests") {
+ testonly = true
+
+ sources = [
+ "rtcerror_unittest.cc",
+ ]
+
+ if (!build_with_chromium && is_clang) {
+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+ }
+
+ deps = [
+ ":libjingle_peerconnection_api",
+ "../base:rtc_base_tests_main",
+ "../base:rtc_base_tests_utils",
+ "../system_wrappers:metrics_default",
+ "../test:test_support",
+ ]
+
+ if (is_android) {
+ deps += [ "//testing/android/native_test:native_test_support" ]
+ }
+ }
}
diff --git a/webrtc/api/peerconnectioninterface.h b/webrtc/api/peerconnectioninterface.h
index 950dad8..a2e5e1b 100644
--- a/webrtc/api/peerconnectioninterface.h
+++ b/webrtc/api/peerconnectioninterface.h
@@ -78,6 +78,7 @@
#include "webrtc/api/dtmfsenderinterface.h"
#include "webrtc/api/jsep.h"
#include "webrtc/api/mediastreaminterface.h"
+#include "webrtc/api/rtcerror.h"
#include "webrtc/api/rtpreceiverinterface.h"
#include "webrtc/api/rtpsenderinterface.h"
#include "webrtc/api/stats/rtcstatscollectorcallback.h"
@@ -133,62 +134,6 @@
virtual ~StatsObserver() {}
};
-// Enumeration to represent distinct classes of errors that an application
-// may wish to act upon differently. These roughly map to DOMExceptions or
-// RTCError "errorDetailEnum" values in the web API, as described in the
-// comments below.
-enum class RTCErrorType {
- // No error.
- NONE,
- // A supplied parameter is valid, but currently unsupported.
- // Maps to InvalidAccessError DOMException.
- UNSUPPORTED_PARAMETER,
- // General error indicating that a supplied parameter is invalid.
- // Maps to InvalidAccessError or TypeError DOMException depending on context.
- INVALID_PARAMETER,
- // Slightly more specific than INVALID_PARAMETER; a parameter's value was
- // outside the allowed range.
- // Maps to RangeError DOMException.
- INVALID_RANGE,
- // Slightly more specific than INVALID_PARAMETER; an error occurred while
- // parsing string input.
- // Maps to SyntaxError DOMException.
- SYNTAX_ERROR,
- // The object does not support this operation in its current state.
- // Maps to InvalidStateError DOMException.
- INVALID_STATE,
- // An attempt was made to modify the object in an invalid way.
- // Maps to InvalidModificationError DOMException.
- INVALID_MODIFICATION,
- // An error occurred within an underlying network protocol.
- // Maps to NetworkError DOMException.
- NETWORK_ERROR,
- // The operation failed due to an internal error.
- // Maps to OperationError DOMException.
- INTERNAL_ERROR,
-};
-
-// Roughly corresponds to RTCError in the web api. Holds an error type and
-// possibly additional information specific to that error.
-//
-// Doesn't contain anything beyond a type now, but will in the future as more
-// errors are implemented.
-class RTCError {
- public:
- RTCError() : type_(RTCErrorType::NONE) {}
- explicit RTCError(RTCErrorType type) : type_(type) {}
-
- RTCErrorType type() const { return type_; }
- void set_type(RTCErrorType type) { type_ = type; }
-
- private:
- RTCErrorType type_;
-};
-
-// Outputs the error as a friendly string.
-// Update this method when adding a new error type.
-std::ostream& operator<<(std::ostream& stream, RTCErrorType error);
-
class PeerConnectionInterface : public rtc::RefCountInterface {
public:
// See http://dev.w3.org/2011/webrtc/editor/webrtc.html#state-definitions .
diff --git a/webrtc/api/rtcerror.cc b/webrtc/api/rtcerror.cc
new file mode 100644
index 0000000..15a3f29
--- /dev/null
+++ b/webrtc/api/rtcerror.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/api/rtcerror.h"
+
+#include "webrtc/base/arraysize.h"
+
+namespace {
+
+static const char* const kRTCErrorTypeNames[] = {
+ "NONE",
+ "UNSUPPORTED_OPERATION",
+ "UNSUPPORTED_PARAMETER",
+ "INVALID_PARAMETER",
+ "INVALID_RANGE",
+ "SYNTAX_ERROR",
+ "INVALID_STATE",
+ "INVALID_MODIFICATION",
+ "NETWORK_ERROR",
+ "RESOURCE_EXHAUSTED",
+ "INTERNAL_ERROR",
+};
+static_assert(static_cast<int>(webrtc::RTCErrorType::INTERNAL_ERROR) ==
+ (arraysize(kRTCErrorTypeNames) - 1),
+ "kRTCErrorTypeNames must have as many strings as RTCErrorType "
+ "has values.");
+
+} // namespace
+
+namespace webrtc {
+
+RTCError::RTCError(RTCError&& other)
+ : type_(other.type_), have_string_message_(other.have_string_message_) {
+ if (have_string_message_) {
+ new (&string_message_) std::string(std::move(other.string_message_));
+ } else {
+ static_message_ = other.static_message_;
+ }
+}
+
+RTCError& RTCError::operator=(RTCError&& other) {
+ type_ = other.type_;
+ if (other.have_string_message_) {
+ set_message(std::move(other.string_message_));
+ } else {
+ set_message(other.static_message_);
+ }
+ return *this;
+}
+
+RTCError::~RTCError() {
+ // If we hold a message string that was built, rather than a static string,
+ // we need to delete it.
+ if (have_string_message_) {
+ string_message_.~basic_string();
+ }
+}
+
+// static
+RTCError RTCError::OK() {
+ return RTCError();
+}
+
+const char* RTCError::message() const {
+ if (have_string_message_) {
+ return string_message_.c_str();
+ } else {
+ return static_message_;
+ }
+}
+
+void RTCError::set_message(const char* message) {
+ if (have_string_message_) {
+ string_message_.~basic_string();
+ have_string_message_ = false;
+ }
+ static_message_ = message;
+}
+
+void RTCError::set_message(std::string&& message) {
+ if (!have_string_message_) {
+ new (&string_message_) std::string(std::move(message));
+ have_string_message_ = true;
+ } else {
+ string_message_ = message;
+ }
+}
+
+std::ostream& operator<<(std::ostream& stream, RTCErrorType error) {
+ int index = static_cast<int>(error);
+ return stream << kRTCErrorTypeNames[index];
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/rtcerror.h b/webrtc/api/rtcerror.h
new file mode 100644
index 0000000..2271445
--- /dev/null
+++ b/webrtc/api/rtcerror.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_API_RTCERROR_H_
+#define WEBRTC_API_RTCERROR_H_
+
+#include <ostream>
+#include <string>
+#include <utility> // For std::move.
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+
+namespace webrtc {
+
+// Enumeration to represent distinct classes of errors that an application
+// may wish to act upon differently. These roughly map to DOMExceptions or
+// RTCError "errorDetailEnum" values in the web API, as described in the
+// comments below.
+enum class RTCErrorType {
+ // No error.
+ NONE,
+
+ // An operation is valid, but currently unsupported.
+ // Maps to OperationError DOMException.
+ UNSUPPORTED_OPERATION,
+
+ // A supplied parameter is valid, but currently unsupported.
+ // Maps to OperationError DOMException.
+ UNSUPPORTED_PARAMETER,
+
+ // General error indicating that a supplied parameter is invalid.
+ // Maps to InvalidAccessError or TypeError DOMException depending on context.
+ INVALID_PARAMETER,
+
+ // Slightly more specific than INVALID_PARAMETER; a parameter's value was
+ // outside the allowed range.
+ // Maps to RangeError DOMException.
+ INVALID_RANGE,
+
+ // Slightly more specific than INVALID_PARAMETER; an error occurred while
+ // parsing string input.
+ // Maps to SyntaxError DOMException.
+ SYNTAX_ERROR,
+
+ // The object does not support this operation in its current state.
+ // Maps to InvalidStateError DOMException.
+ INVALID_STATE,
+
+ // An attempt was made to modify the object in an invalid way.
+ // Maps to InvalidModificationError DOMException.
+ INVALID_MODIFICATION,
+
+ // An error occurred within an underlying network protocol.
+ // Maps to NetworkError DOMException.
+ NETWORK_ERROR,
+
+ // Some resource has been exhausted; file handles, hardware resources, ports,
+ // etc.
+ // Maps to OperationError DOMException.
+ RESOURCE_EXHAUSTED,
+
+ // The operation failed due to an internal error.
+ // Maps to OperationError DOMException.
+ INTERNAL_ERROR,
+};
+
+// Roughly corresponds to RTCError in the web api. Holds an error type, a
+// message, and possibly additional information specific to that error.
+//
+// Doesn't contain anything beyond a type and message now, but will in the
+// future as more errors are implemented.
+class RTCError {
+ public:
+ // Constructors.
+
+ // Creates a "no error" error.
+ RTCError() {}
+ explicit RTCError(RTCErrorType type) : type_(type) {}
+ // For performance, prefer using the constructor that takes a const char* if
+ // the message is a static string.
+ RTCError(RTCErrorType type, const char* message)
+ : type_(type), static_message_(message), have_string_message_(false) {}
+ RTCError(RTCErrorType type, std::string&& message)
+ : type_(type), string_message_(message), have_string_message_(true) {}
+
+ // Delete the copy constructor and assignment operator; there aren't any use
+ // cases where you should need to copy an RTCError, as opposed to moving it.
+ // Can revisit this decision if use cases arise in the future.
+ RTCError(const RTCError& other) = delete;
+ RTCError& operator=(const RTCError& other) = delete;
+
+ // Move constructor and move-assignment operator.
+ RTCError(RTCError&& other);
+ RTCError& operator=(RTCError&& other);
+
+ ~RTCError();
+
+ // Identical to default constructed error.
+ //
+ // Preferred over the default constructor for code readability.
+ static RTCError OK();
+
+ // Error type.
+ RTCErrorType type() const { return type_; }
+ void set_type(RTCErrorType type) { type_ = type; }
+
+ // Human-readable message describing the error. Shouldn't be used for
+ // anything but logging/diagnostics, since messages are not guaranteed to be
+ // stable.
+ const char* message() const;
+ // For performance, prefer using the method that takes a const char* if the
+ // message is a static string.
+ void set_message(const char* message);
+ void set_message(std::string&& message);
+
+ // Convenience method for situations where you only care whether or not an
+ // error occurred.
+ bool ok() const { return type_ == RTCErrorType::NONE; }
+
+ private:
+ RTCErrorType type_ = RTCErrorType::NONE;
+ // For performance, we use static strings wherever possible. But in some
+ // cases the error string may need to be constructed, in which case an
+ // std::string is used.
+ union {
+ const char* static_message_ = "";
+ std::string string_message_;
+ };
+ // Whether or not |static_message_| or |string_message_| is being used in the
+ // above union.
+ bool have_string_message_ = false;
+};
+
+// Outputs the error as a friendly string. Update this method when adding a new
+// error type.
+//
+// Only intended to be used for logging/disagnostics.
+std::ostream& operator<<(std::ostream& stream, RTCErrorType error);
+
+// Helper macro that can be used by implementations to create an error with a
+// message and log it. |message| should be a string literal or movable
+// std::string.
+#define LOG_AND_RETURN_ERROR_EX(type, message, severity) \
+ { \
+ RTC_DCHECK(type != RTCErrorType::NONE); \
+ LOG(severity) << message << " (" << type << ")"; \
+ return webrtc::RTCError(type, message); \
+ }
+
+#define LOG_AND_RETURN_ERROR(type, message) \
+ LOG_AND_RETURN_ERROR_EX(type, message, LS_ERROR)
+
+// RTCErrorOr<T> is the union of an RTCError object and a T object. RTCErrorOr
+// 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 RTCErrorOr<T>
+// does not allow its RTCErrorType value to be RTCErrorType::NONE. This is
+// enforced by a debug check in most cases.
+//
+// The primary use-case for RTCErrorOr<T> is as the return value of a function
+// which may fail. For example, CreateRtpSender will fail if the parameters
+// could not be successfully applied at the media engine level, but if
+// successful will return a unique_ptr to an RtpSender.
+//
+// Example client usage for a RTCErrorOr<std::unique_ptr<T>>:
+//
+// RTCErrorOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
+// if (result.ok()) {
+// std::unique_ptr<Foo> foo = result.ConsumeValue();
+// foo->DoSomethingCool();
+// } else {
+// LOG(LS_ERROR) << result.error();
+// }
+//
+// Example factory implementation returning RTCErrorOr<std::unique_ptr<T>>:
+//
+// RTCErrorOr<std::unique_ptr<Foo>> FooFactory::MakeNewFoo(int arg) {
+// if (arg <= 0) {
+// return RTCError(RTCErrorType::INVALID_RANGE, "Arg must be positive");
+// } else {
+// return std::unique_ptr<Foo>(new Foo(arg));
+// }
+// }
+//
+template <typename T>
+class RTCErrorOr {
+ // Used to convert between RTCErrorOr<Foo>/RtcErrorOr<Bar>, when an implicit
+ // conversion from Foo to Bar exists.
+ template <typename U>
+ friend class RTCErrorOr;
+
+ public:
+ typedef T element_type;
+
+ // Constructs a new RTCErrorOr with RTCErrorType::INTERNAL_ERROR error. This
+ // is marked 'explicit' to try to catch cases like 'return {};', where people
+ // think RTCErrorOr<std::vector<int>> will be initialized with an empty
+ // vector, instead of a RTCErrorType::INTERNAL_ERROR error.
+ explicit RTCErrorOr() : error_(RTCErrorType::INTERNAL_ERROR) {}
+
+ // Constructs a new RTCErrorOr with the given non-ok error. After calling
+ // this constructor, calls to value() will DCHECK-fail.
+ //
+ // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return
+ // value, so it is convenient and sensible to be able to do 'return
+ // RTCError(...)' when the return type is RTCErrorOr<T>.
+ //
+ // REQUIRES: !error.ok(). This requirement is DCHECKed.
+ RTCErrorOr(RTCError&& error) : error_(std::move(error)) {
+ RTC_DCHECK(!error.ok());
+ }
+
+ // Constructs a new RTCErrorOr with the given value. After calling this
+ // constructor, calls to value() will succeed, and calls to error() will
+ // return a default-constructed RTCError.
+ //
+ // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return type
+ // so it is convenient and sensible to be able to do 'return T()'
+ // when the return type is RTCErrorOr<T>.
+ RTCErrorOr(T value) : value_(std::move(value)) {}
+
+ // Delete the copy constructor and assignment operator; there aren't any use
+ // cases where you should need to copy an RTCErrorOr, as opposed to moving
+ // it. Can revisit this decision if use cases arise in the future.
+ RTCErrorOr(const RTCErrorOr& other) = delete;
+ RTCErrorOr& operator=(const RTCErrorOr& other) = delete;
+
+ // Move constructor and move-assignment operator.
+ RTCErrorOr(RTCErrorOr&& other) = default;
+ RTCErrorOr& operator=(RTCErrorOr&& other) = default;
+
+ // Conversion constructor and assignment operator; T must be copy or move
+ // constructible from U.
+ template <typename U>
+ RTCErrorOr(RTCErrorOr<U> other)
+ : error_(std::move(other.error_)), value_(std::move(other.value_)) {}
+ template <typename U>
+ RTCErrorOr& operator=(RTCErrorOr<U> other) {
+ error_ = std::move(other.error_);
+ value_ = std::move(other.value_);
+ return *this;
+ }
+
+ // Returns a reference to our error. If this contains a T, then returns
+ // default-constructed RTCError.
+ const RTCError& error() const { return error_; }
+
+ // Moves the error. Can be useful if, say "CreateFoo" returns an
+ // RTCErrorOr<Foo>, and internally calls "CreateBar" which returns an
+ // RTCErrorOr<Bar>, and wants to forward the error up the stack.
+ RTCError MoveError() { return std::move(error_); }
+
+ // Returns this->error().ok()
+ bool ok() const { return error_.ok(); }
+
+ // Returns a reference to our current value, or DCHECK-fails if !this->ok().
+ //
+ // Can be convenient for the implementation; for example, a method may want
+ // to access the value in some way before returning it to the next method on
+ // the stack.
+ const T& value() const {
+ RTC_DCHECK(ok());
+ return value_;
+ }
+ T& value() {
+ RTC_DCHECK(ok());
+ return value_;
+ }
+
+ // Moves our current value out of this object and returns it, or DCHECK-fails
+ // if !this->ok().
+ T MoveValue() {
+ RTC_DCHECK(ok());
+ return std::move(value_);
+ }
+
+ private:
+ RTCError error_;
+ T value_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_API_RTCERROR_H_
diff --git a/webrtc/api/rtcerror_unittest.cc b/webrtc/api/rtcerror_unittest.cc
new file mode 100644
index 0000000..32b03ad
--- /dev/null
+++ b/webrtc/api/rtcerror_unittest.cc
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2017 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <utility>
+
+#include "webrtc/api/rtcerror.h"
+#include "webrtc/test/gtest.h"
+
+namespace {
+
+const int kDefaultMoveOnlyIntValue = 0xbadf00d;
+
+// Class that has no copy constructor, ensuring that RTCErrorOr can
+struct MoveOnlyInt {
+ MoveOnlyInt() {}
+ explicit MoveOnlyInt(int value) : value(value) {}
+ MoveOnlyInt(const MoveOnlyInt& other) = delete;
+ MoveOnlyInt(MoveOnlyInt&& other) = default;
+ MoveOnlyInt& operator=(MoveOnlyInt&& other) = default;
+
+ int value = kDefaultMoveOnlyIntValue;
+};
+
+// Same as above. Used to test conversion from RTCErrorOr<A> to RTCErrorOr<B>
+// when A can be converted to B.
+struct MoveOnlyInt2 {
+ MoveOnlyInt2() {}
+ explicit MoveOnlyInt2(int value) : value(value) {}
+ MoveOnlyInt2(const MoveOnlyInt2& other) = delete;
+ MoveOnlyInt2(MoveOnlyInt2&& other) = default;
+ MoveOnlyInt2& operator=(MoveOnlyInt2&& other) = default;
+
+ explicit MoveOnlyInt2(MoveOnlyInt&& other) : value(other.value) {}
+ MoveOnlyInt2& operator=(MoveOnlyInt&& other) {
+ value = other.value;
+ return *this;
+ }
+
+ int value = kDefaultMoveOnlyIntValue;
+};
+
+} // namespace
+
+namespace webrtc {
+
+// Simple test for ostream operator for RTCErrorType.
+TEST(RTCErrorTypeTest, OstreamOperator) {
+ std::ostringstream oss;
+ oss << webrtc::RTCErrorType::NONE << ' '
+ << webrtc::RTCErrorType::INVALID_PARAMETER << ' '
+ << webrtc::RTCErrorType::INTERNAL_ERROR;
+ EXPECT_EQ("NONE INVALID_PARAMETER INTERNAL_ERROR", oss.str());
+}
+
+// Test that the default constructor creates a "no error" error.
+TEST(RTCErrorTest, DefaultConstructor) {
+ RTCError e;
+ EXPECT_EQ(RTCErrorType::NONE, e.type());
+ EXPECT_EQ(std::string(), e.message());
+ EXPECT_TRUE(e.ok());
+}
+
+TEST(RTCErrorTest, NormalConstructors) {
+ RTCError a(RTCErrorType::INVALID_PARAMETER);
+ EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, a.type());
+ EXPECT_EQ(std::string(), a.message());
+
+ // Constructor that takes const char* message.
+ RTCError b(RTCErrorType::UNSUPPORTED_PARAMETER, "foobar");
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, b.type());
+ EXPECT_EQ(std::string("foobar"), b.message());
+
+ // Constructor that takes std::string message.
+ RTCError c(RTCErrorType::INVALID_RANGE, std::string("new"));
+ EXPECT_EQ(RTCErrorType::INVALID_RANGE, c.type());
+ EXPECT_EQ(std::string("new"), c.message());
+}
+
+TEST(RTCErrorTest, MoveConstructor) {
+ // Static string.
+ RTCError a(RTCErrorType::INVALID_PARAMETER, "foo");
+ RTCError b(std::move(a));
+ EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, b.type());
+ EXPECT_EQ(std::string("foo"), b.message());
+
+ // Non-static string.
+ RTCError c(RTCErrorType::UNSUPPORTED_PARAMETER, std::string("bar"));
+ RTCError d(std::move(c));
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, d.type());
+ EXPECT_EQ(std::string("bar"), d.message());
+}
+
+TEST(RTCErrorTest, MoveAssignment) {
+ // Try all combinations of "is static string"/"is non-static string" moves.
+ RTCError e(RTCErrorType::INVALID_PARAMETER, "foo");
+
+ e = RTCError(RTCErrorType::UNSUPPORTED_PARAMETER, "bar");
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, e.type());
+ EXPECT_EQ(std::string("bar"), e.message());
+
+ e = RTCError(RTCErrorType::SYNTAX_ERROR, std::string("baz"));
+ EXPECT_EQ(std::string("baz"), e.message());
+
+ e = RTCError(RTCErrorType::SYNTAX_ERROR, std::string("another"));
+ EXPECT_EQ(std::string("another"), e.message());
+
+ e = RTCError(RTCErrorType::SYNTAX_ERROR, "last");
+ EXPECT_EQ(std::string("last"), e.message());
+}
+
+// Test that the error returned by RTCError::OK() is a "no error" error.
+TEST(RTCErrorTest, OKConstant) {
+ RTCError ok = RTCError::OK();
+ EXPECT_EQ(RTCErrorType::NONE, ok.type());
+ EXPECT_EQ(std::string(), ok.message());
+ EXPECT_TRUE(ok.ok());
+}
+
+// Test that "error.ok()" behaves as expected.
+TEST(RTCErrorTest, OkMethod) {
+ RTCError success;
+ RTCError failure(RTCErrorType::INTERNAL_ERROR);
+ EXPECT_TRUE(success.ok());
+ EXPECT_FALSE(failure.ok());
+}
+
+// Test that a message can be set using either static const strings or
+// std::strings.
+TEST(RTCErrorTest, SetMessage) {
+ RTCError e;
+ // Try all combinations of "is static string"/"is non-static string" calls.
+ e.set_message("foo");
+ EXPECT_EQ(std::string("foo"), e.message());
+
+ e.set_message("bar");
+ EXPECT_EQ(std::string("bar"), e.message());
+
+ e.set_message(std::string("string"));
+ EXPECT_EQ(std::string("string"), e.message());
+
+ e.set_message(std::string("more"));
+ EXPECT_EQ(std::string("more"), e.message());
+
+ e.set_message("love to test");
+ EXPECT_EQ(std::string("love to test"), e.message());
+}
+
+// Test that the default constructor creates an "INTERNAL_ERROR".
+TEST(RTCErrorOrTest, DefaultConstructor) {
+ RTCErrorOr<MoveOnlyInt> e;
+ EXPECT_EQ(RTCErrorType::INTERNAL_ERROR, e.error().type());
+}
+
+// Test that an RTCErrorOr can be implicitly constructed from a value.
+TEST(RTCErrorOrTest, ImplicitValueConstructor) {
+ RTCErrorOr<MoveOnlyInt> e = [] { return MoveOnlyInt(100); }();
+ EXPECT_EQ(100, e.value().value);
+}
+
+// Test that an RTCErrorOr can be implicitly constructed from an RTCError.
+TEST(RTCErrorOrTest, ImplicitErrorConstructor) {
+ RTCErrorOr<MoveOnlyInt> e = [] {
+ return RTCError(RTCErrorType::SYNTAX_ERROR);
+ }();
+ EXPECT_EQ(RTCErrorType::SYNTAX_ERROR, e.error().type());
+}
+
+TEST(RTCErrorOrTest, MoveConstructor) {
+ RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(5));
+ RTCErrorOr<MoveOnlyInt> b(std::move(a));
+ EXPECT_EQ(5, b.value().value);
+}
+
+TEST(RTCErrorOrTest, MoveAssignment) {
+ RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(5));
+ RTCErrorOr<MoveOnlyInt> b(MoveOnlyInt(10));
+ a = std::move(b);
+ EXPECT_EQ(10, a.value().value);
+}
+
+TEST(RTCErrorOrTest, ConversionConstructor) {
+ RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(1));
+ RTCErrorOr<MoveOnlyInt2> b(std::move(a));
+}
+
+TEST(RTCErrorOrTest, ConversionAssignment) {
+ RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(5));
+ RTCErrorOr<MoveOnlyInt2> b(MoveOnlyInt2(10));
+ b = std::move(a);
+ EXPECT_EQ(5, b.value().value);
+}
+
+TEST(RTCErrorOrTest, OkMethod) {
+ RTCErrorOr<int> success(1337);
+ RTCErrorOr<int> error = RTCError(RTCErrorType::INTERNAL_ERROR);
+ EXPECT_TRUE(success.ok());
+ EXPECT_FALSE(error.ok());
+}
+
+TEST(RTCErrorOrTest, MoveError) {
+ RTCErrorOr<int> e({RTCErrorType::SYNTAX_ERROR, "message"});
+ RTCError err = e.MoveError();
+ EXPECT_EQ(RTCErrorType::SYNTAX_ERROR, err.type());
+ EXPECT_EQ(std::string("message"), err.message());
+}
+
+TEST(RTCErrorOrTest, MoveValue) {
+ RTCErrorOr<MoveOnlyInt> e(MoveOnlyInt(88));
+ MoveOnlyInt value = e.MoveValue();
+ EXPECT_EQ(88, value.value);
+}
+
+// Death tests.
+// Disabled on Android because death tests misbehave on Android, see
+// base/test/gtest_util.h.
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+TEST(RTCErrorOrDeathTest, ConstructWithOkError) {
+ EXPECT_DEATH(RTCErrorOr<int> err = RTCError::OK(), "");
+}
+
+TEST(RTCErrorOrDeathTest, DereferenceErrorValue) {
+ RTCErrorOr<int> error = RTCError(RTCErrorType::INTERNAL_ERROR);
+ EXPECT_DEATH(error.value(), "");
+}
+
+TEST(RTCErrorOrDeathTest, MoveErrorValue) {
+ RTCErrorOr<int> error = RTCError(RTCErrorType::INTERNAL_ERROR);
+ EXPECT_DEATH(error.MoveValue(), "");
+}
+
+#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+} // namespace webrtc