From 6038e97e048bebf763f7149ce0d84d0798c65f8b Mon Sep 17 00:00:00 2001 From: deadbeef Date: Thu, 16 Feb 2017 23:31:33 -0800 Subject: [PATCH] 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} --- webrtc/BUILD.gn | 1 + webrtc/api/BUILD.gn | 27 ++ webrtc/api/peerconnectioninterface.h | 57 +--- webrtc/api/rtcerror.cc | 101 ++++++ webrtc/api/rtcerror.h | 291 ++++++++++++++++++ webrtc/api/rtcerror_unittest.cc | 241 +++++++++++++++ webrtc/pc/peerconnection.cc | 21 -- webrtc/pc/peerconnectioninterface_unittest.cc | 8 - 8 files changed, 662 insertions(+), 85 deletions(-) create mode 100644 webrtc/api/rtcerror.cc create mode 100644 webrtc/api/rtcerror.h create mode 100644 webrtc/api/rtcerror_unittest.cc diff --git a/webrtc/BUILD.gn b/webrtc/BUILD.gn index 67e6aba8e3..55b6a95bde 100644 --- a/webrtc/BUILD.gn +++ b/webrtc/BUILD.gn @@ -287,6 +287,7 @@ if (!build_with_chromium) { ":video_engine_tests", ":webrtc_nonparallel_tests", ":webrtc_perf_tests", + "api:rtc_api_unittests", "base:rtc_base_tests_utils", "common_audio:common_audio_unittests", "common_video:common_video_unittests", diff --git a/webrtc/api/BUILD.gn b/webrtc/api/BUILD.gn index f0752f9635..5a6051e744 100644 --- a/webrtc/api/BUILD.gn +++ b/webrtc/api/BUILD.gn @@ -61,6 +61,8 @@ rtc_static_library("libjingle_peerconnection_api") { "peerconnectioninterface.h", "peerconnectionproxy.h", "proxy.h", + "rtcerror.cc", + "rtcerror.h", "rtpparameters.h", "rtpreceiverinterface.h", "rtpsender.h", @@ -198,4 +200,29 @@ if (rtc_include_tests) { 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 950dad8f0b..a2e5e1bc73 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 @@ class StatsObserver : public rtc::RefCountInterface { 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 0000000000..15a3f29191 --- /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(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(error); + return stream << kRTCErrorTypeNames[index]; +} + +} // namespace webrtc diff --git a/webrtc/api/rtcerror.h b/webrtc/api/rtcerror.h new file mode 100644 index 0000000000..22714451b5 --- /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 +#include +#include // 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 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 +// 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 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>: +// +// RTCErrorOr> result = FooFactory::MakeNewFoo(arg); +// if (result.ok()) { +// std::unique_ptr foo = result.ConsumeValue(); +// foo->DoSomethingCool(); +// } else { +// LOG(LS_ERROR) << result.error(); +// } +// +// Example factory implementation returning RTCErrorOr>: +// +// RTCErrorOr> FooFactory::MakeNewFoo(int arg) { +// if (arg <= 0) { +// return RTCError(RTCErrorType::INVALID_RANGE, "Arg must be positive"); +// } else { +// return std::unique_ptr(new Foo(arg)); +// } +// } +// +template +class RTCErrorOr { + // Used to convert between RTCErrorOr/RtcErrorOr, when an implicit + // conversion from Foo to Bar exists. + template + 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> 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 as a return + // value, so it is convenient and sensible to be able to do 'return + // RTCError(...)' when the return type is RTCErrorOr. + // + // 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 as a return type + // so it is convenient and sensible to be able to do 'return T()' + // when the return type is RTCErrorOr. + 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 + RTCErrorOr(RTCErrorOr other) + : error_(std::move(other.error_)), value_(std::move(other.value_)) {} + template + RTCErrorOr& operator=(RTCErrorOr 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, and internally calls "CreateBar" which returns an + // RTCErrorOr, 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 0000000000..32b03add07 --- /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 + +#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 to RTCErrorOr +// 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 e; + EXPECT_EQ(RTCErrorType::INTERNAL_ERROR, e.error().type()); +} + +// Test that an RTCErrorOr can be implicitly constructed from a value. +TEST(RTCErrorOrTest, ImplicitValueConstructor) { + RTCErrorOr 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 e = [] { + return RTCError(RTCErrorType::SYNTAX_ERROR); + }(); + EXPECT_EQ(RTCErrorType::SYNTAX_ERROR, e.error().type()); +} + +TEST(RTCErrorOrTest, MoveConstructor) { + RTCErrorOr a(MoveOnlyInt(5)); + RTCErrorOr b(std::move(a)); + EXPECT_EQ(5, b.value().value); +} + +TEST(RTCErrorOrTest, MoveAssignment) { + RTCErrorOr a(MoveOnlyInt(5)); + RTCErrorOr b(MoveOnlyInt(10)); + a = std::move(b); + EXPECT_EQ(10, a.value().value); +} + +TEST(RTCErrorOrTest, ConversionConstructor) { + RTCErrorOr a(MoveOnlyInt(1)); + RTCErrorOr b(std::move(a)); +} + +TEST(RTCErrorOrTest, ConversionAssignment) { + RTCErrorOr a(MoveOnlyInt(5)); + RTCErrorOr b(MoveOnlyInt2(10)); + b = std::move(a); + EXPECT_EQ(5, b.value().value); +} + +TEST(RTCErrorOrTest, OkMethod) { + RTCErrorOr success(1337); + RTCErrorOr error = RTCError(RTCErrorType::INTERNAL_ERROR); + EXPECT_TRUE(success.ok()); + EXPECT_FALSE(error.ok()); +} + +TEST(RTCErrorOrTest, MoveError) { + RTCErrorOr 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 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 err = RTCError::OK(), ""); +} + +TEST(RTCErrorOrDeathTest, DereferenceErrorValue) { + RTCErrorOr error = RTCError(RTCErrorType::INTERNAL_ERROR); + EXPECT_DEATH(error.value(), ""); +} + +TEST(RTCErrorOrDeathTest, MoveErrorValue) { + RTCErrorOr error = RTCError(RTCErrorType::INTERNAL_ERROR); + EXPECT_DEATH(error.MoveValue(), ""); +} + +#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +} // namespace webrtc diff --git a/webrtc/pc/peerconnection.cc b/webrtc/pc/peerconnection.cc index 96e2b339a4..ee9341ecb4 100644 --- a/webrtc/pc/peerconnection.cc +++ b/webrtc/pc/peerconnection.cc @@ -458,27 +458,6 @@ bool SafeSetError(webrtc::RTCErrorType type, webrtc::RTCError* error) { namespace webrtc { -static const char* const kRTCErrorTypeNames[] = { - "NONE", - "UNSUPPORTED_PARAMETER", - "INVALID_PARAMETER", - "INVALID_RANGE", - "SYNTAX_ERROR", - "INVALID_STATE", - "INVALID_MODIFICATION", - "NETWORK_ERROR", - "INTERNAL_ERROR", -}; -static_assert(static_cast(RTCErrorType::INTERNAL_ERROR) == - (arraysize(kRTCErrorTypeNames) - 1), - "kRTCErrorTypeNames must have as many strings as RTCErrorType " - "has values."); - -std::ostream& operator<<(std::ostream& stream, RTCErrorType error) { - int index = static_cast(error); - return stream << kRTCErrorTypeNames[index]; -} - bool PeerConnectionInterface::RTCConfiguration::operator==( const PeerConnectionInterface::RTCConfiguration& o) const { // This static_assert prevents us from accidentally breaking operator==. diff --git a/webrtc/pc/peerconnectioninterface_unittest.cc b/webrtc/pc/peerconnectioninterface_unittest.cc index 7f73db8432..8a80e5e907 100644 --- a/webrtc/pc/peerconnectioninterface_unittest.cc +++ b/webrtc/pc/peerconnectioninterface_unittest.cc @@ -3384,14 +3384,6 @@ TEST(CreateSessionOptionsTest, MediaConstraintsInAnswer) { EXPECT_TRUE(updated_answer_options.has_video()); } -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()); -} - // Tests a few random fields being different. TEST(RTCConfigurationTest, ComparisonOperators) { PeerConnectionInterface::RTCConfiguration a;