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}
This commit is contained in:
deadbeef 2017-02-16 23:31:33 -08:00 committed by Commit bot
parent 74520c6718
commit 6038e97e04
8 changed files with 662 additions and 85 deletions

View File

@ -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",

View File

@ -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" ]
}
}
}

View File

@ -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 .

101
webrtc/api/rtcerror.cc Normal file
View File

@ -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

291
webrtc/api/rtcerror.h Normal file
View File

@ -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_

View File

@ -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

View File

@ -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<int>(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<int>(error);
return stream << kRTCErrorTypeNames[index];
}
bool PeerConnectionInterface::RTCConfiguration::operator==(
const PeerConnectionInterface::RTCConfiguration& o) const {
// This static_assert prevents us from accidentally breaking operator==.

View File

@ -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;